Index: 3rdParty_sources/httpunit/com/meterware/httpunit/AppletContextImpl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/AppletContextImpl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/AppletContextImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,230 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/import java.util.*;
+import java.applet.AppletContext;
+import java.applet.AudioClip;
+import java.applet.Applet;
+import java.net.URL;
+import java.awt.*;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author Russell Gold
+ **/
+class AppletContextImpl implements AppletContext {
+
+ private WebApplet _webApplet;
+
+
+ AppletContextImpl( WebApplet webApplet ) {
+ _webApplet = webApplet;
+ }
+
+
+ /**
+ * Creates an audio clip.
+ *
+ * @param url an absolute URL giving the location of the audio clip.
+ * @return the audio clip at the specified URL.
+ */
+ public AudioClip getAudioClip( URL url ) {
+ return null;
+ }
+
+
+ /**
+ * Returns an Image
object that can then be painted on
+ * the screen. The url
argument
that is
+ * passed as an argument must specify an absolute URL.
+ *
+ * This method always returns immediately, whether or not the image
+ * exists. When the applet attempts to draw the image on the screen,
+ * the data will be loaded. The graphics primitives that draw the
+ * image will incrementally paint on the screen.
+ *
+ * @param url an absolute URL giving the location of the image.
+ * @return the image at the specified URL.
+ * @see Image
+ */
+ public Image getImage( URL url ) {
+ return null;
+ }
+
+
+ /**
+ * Finds and returns the applet in the document represented by this
+ * applet context with the given name. The name can be set in the
+ * HTML tag by setting the name
attribute.
+ *
+ * @param name an applet name.
+ * @return the applet with the given name, or null
if
+ * not found.
+ */
+ public Applet getApplet( String name ) {
+ try {
+ WebApplet[] webApplets = _webApplet.getAppletsInPage();
+ for (int i = 0; i < webApplets.length; i++) {
+ if (webApplets[i].getName().equals( name )) return webApplets[i].getApplet();
+ }
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+
+ /**
+ * Finds all the applets in the document represented by this applet
+ * context.
+ *
+ * @return an enumeration of all applets in the document represented by
+ * this applet context.
+ */
+ public Enumeration getApplets() {
+ WebApplet[] webApplets = _webApplet.getAppletsInPage();
+ Vector v = new Vector();
+ try {
+ for (int i = 0; i < webApplets.length; i++) {
+ v.add( webApplets[i].getApplet() );
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException( e.toString() );
+ }
+ return v.elements();
+ }
+
+
+ /**
+ * Replaces the Web page currently being viewed with the given URL.
+ * This method may be ignored by applet contexts that are not
+ * browsers.
+ *
+ * @param url an absolute URL giving the location of the document.
+ */
+ public void showDocument( URL url ) {
+ showDocument( url, _webApplet.getBaseTarget() );
+ }
+
+
+ /**
+ * Requests that the browser or applet viewer show the Web page
+ * indicated by the url
argument. The
+ * target
argument indicates in which HTML frame the
+ * document is to be displayed.
+ * The target argument is interpreted as follows:
+ *
+ *
"_self" | Show in the window and frame that + * contain the applet. |
"_parent" | Show in the applet's parent frame. If + * the applet's frame has no parent frame, + * acts the same as "_self". |
"_top" | Show in the top-level frame of the applet's + * window. If the applet's frame is the + * top-level frame, acts the same as "_self". |
"_blank" | Show in a new, unnamed + * top-level window. |
name | Show in the frame or window named name. If + * a target named name does not already exist, a + * new top-level window with the specified name is created, + * and the document is shown there. |
+ * An applet viewer or browser is free to ignore showDocument
.
+ *
+ * @param url an absolute URL giving the location of the document.
+ * @param target a String
indicating where to display
+ * the page.
+ */
+ public void showDocument( URL url, String target ) {
+ _webApplet.sendRequest( url, target );
+ }
+
+
+ /**
+ * Requests that the argument string be displayed in the
+ * "status window". Many browsers and applet viewers
+ * provide such a window, where the application can inform users of
+ * its current state.
+ *
+ * @param status a string to display in the status window.
+ */
+ public void showStatus( String status ) {
+ }
+
+
+ /**
+ * Returns the stream to which specified key is associated within this
+ * applet context. Returns null if the applet context contains
+ * no stream for this key.
+ *
+ * For security reasons, mapping of streams and keys exists for each + * codebase. In other words, applet from one codebase cannot access + * the streams created by an applet from a different codebase + *
+ * @return the stream to which this applet context maps the key + * @param key key whose associated stream is to be returned. + * @since JDK1.4 + */ + public InputStream getStream( String key ) { + return null; + } + + + /** + * Finds all the keys of the streams in this applet context. + *
+ * For security reasons, mapping of streams and keys exists for each + * codebase. In other words, applet from one codebase cannot access + * the streams created by an applet from a different codebase + *
+ * @return an Iterator of all the names of the streams in this applet + * context. + * @since JDK1.4 + */ + public Iterator getStreamKeys() { + return null; + } + + + /** + * Associates the specified stream with the specified key in this + * applet context. If the applet context previously contained a mapping + * for this key, the old value is replaced. + *
+ * For security reasons, mapping of streams and keys exists for each + * codebase. In other words, applet from one codebase cannot access + * the streams created by an applet from a different codebase + *
+ * @param key key with which the specified value is to be associated.
+ * @param stream stream to be associated with the specified key. If this
+ * parameter is
+ * then a call to
+ * Note that the parsing does not strictly follow the specifications, but
+ * attempts to imitate the behavior of popular browsers. Specifically,
+ * it allows cookie values to contain commas, which the
+ * Netscape standard does not allow for, but which is required by some servers.
+ * Classes to support cookie handling. Supports the HTTP state mechanism. The central class of this package is the
+{@link com.meterware.httpunit.cookies.CookieJar}, which acts as a repository of
+{@link com.meterware.httpunit.cookies.Cookie} objects. There are two main ways to get cookies into the
+CookieJar. The first is to construct the CookieJar, passing a {@link com.meterware.httpunit.cookies.CookieSource}
+to its constructor. This will cause the CookieJar to parse the Set-Cookie headers from the source object. The second is
+to copy them from another CookieJar through use of the
+{@link com.meterware.httpunit.cookies.CookieJar#updateCookies updateCookies(CookieJar)} method. The CookieJar can also produce a Cookie header to be sent as part of a request.
+The {@link com.meterware.httpunit.cookies.CookieJar#getCookieHeaderField} method
+will select any cookies that it has which can be sent to the specified URL and assemble them into an appropriate header.null
, the specified key is removed
+ * in this applet context.
+ * @throws
+ * will return "/mystyle.css".
+ * @exception SAXException thrown if there is an error parsing this response
+ **/
+ public String getExternalStyleSheet() throws SAXException {
+ return getReceivedPage().getExternalStyleSheet();
+ }
+
+ /**
+ * Retrieves the "content" of the meta tags for a key pair attribute-attributeValue.
+ * IOException
if the stream size exceeds a certain
+ * size limit. Size limit is decided by the implementor of this
+ * interface.
+ * @since JDK1.4
+ */
+ public void setStream( String key, InputStream stream ) throws IOException {
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/AppletStubImpl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/AppletStubImpl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/AppletStubImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,119 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.applet.AppletStub;
+import java.applet.AppletContext;
+import java.net.URL;
+
+class AppletStubImpl implements AppletStub {
+
+ private WebApplet _webApplet;
+
+
+ AppletStubImpl( WebApplet webApplet ) {
+ _webApplet = webApplet;
+ }
+
+
+ /**
+ * Determines if the applet is active. An applet is active just
+ * before its start
method is called. It becomes
+ * inactive just before its stop
method is called.
+ *
+ * @return true
if the applet is active;
+ * false
otherwise.
+ */
+ public boolean isActive() {
+ return false;
+ }
+
+
+ /**
+ * Returns an absolute URL naming the directory of the document in which
+ * the applet is embedded. For example, suppose an applet is contained
+ * within the document:
+ *
+ * The document base is:
+ *
+ * http://java.sun.com/products/jdk/1.2/index.html
+ *
+ *
+ * @return the {@link URL} of the document that contains this
+ * applet.
+ * @see AppletStub#getCodeBase()
+ */
+ public URL getDocumentBase() {
+ return null;
+ }
+
+
+ /**
+ * Gets the base URL.
+ *
+ * @return the
+ * http://java.sun.com/products/jdk/1.2/
+ *
URL
of the applet.
+ */
+ public URL getCodeBase() {
+ return null;
+ }
+
+
+ /**
+ * Returns the value of the named parameter in the HTML tag. For
+ * example, if an applet is specified as
+ *
+ *
+ * <applet code="Clock" width=50 height=50>
+ * <param name=Color value="blue">
+ * </applet>
+ *
getParameter("Color")
returns the
+ * value "blue"
.
+ *
+ * @param name a parameter name.
+ * @return the value of the named parameter,
+ * or null if not set.
+ */
+ public String getParameter( String name ) {
+ return _webApplet.getParameter( name );
+ }
+
+
+ /**
+ * Gets a handler to the applet's context.
+ *
+ * @return the applet's context.
+ */
+ public AppletContext getAppletContext() {
+ return new AppletContextImpl( _webApplet );
+ }
+
+
+ /**
+ * Called when the applet wants to be resized.
+ *
+ * @param width the new requested width for the applet.
+ * @param height the new requested height for the applet.
+ */
+ public void appletResize( int width, int height ) {
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/AuthenticationChallenge.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/AuthenticationChallenge.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/AuthenticationChallenge.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,245 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2006, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.net.PasswordAuthentication;
+import java.net.MalformedURLException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * A challenge for authentication from the server to a client.
+ **/
+class AuthenticationChallenge extends HttpHeader {
+
+ private WebClient _client;
+ private WebRequest _request;
+
+ private static final AuthenticationStrategy BASIC_AUTHENTICATION = new BasicAuthenticationStrategy();
+ private static final AuthenticationStrategy DIGEST_AUTHENTICATION = new DigestAuthenticationStrategy();
+
+ static AuthorizationRequiredException createException( String wwwAuthenticateHeader ) {
+ AuthenticationChallenge challenge = new AuthenticationChallenge( null, null, wwwAuthenticateHeader );
+ return challenge.createAuthorizationRequiredException();
+ }
+
+
+ AuthenticationChallenge( WebClient client, WebRequest request, String headerString ) {
+ super( headerString, "Basic" );
+ _client = client;
+ _request = request;
+ }
+
+
+ boolean needToAuthenticate() {
+ if (getAuthenticationType() == null) return false;
+ if (getCredentialsForRealm() != null) return true;
+ if (!_client.getExceptionsThrownOnErrorStatus()) return false;
+
+ throw createAuthorizationRequiredException();
+ }
+
+
+ private String getAuthenticationType() {
+ return getLabel();
+ }
+
+
+ String createAuthenticationHeader() {
+ PasswordAuthentication credentials = getCredentialsForRealm();
+ return getAuthenticationStrategy().createAuthenticationHeader( this, credentials.getUserName(), new String( credentials.getPassword() ) );
+ }
+
+
+ private AuthenticationStrategy getAuthenticationStrategy() {
+ if (getAuthenticationType().equalsIgnoreCase( "basic" ) ) return BASIC_AUTHENTICATION;
+ if (getAuthenticationType().equalsIgnoreCase( "digest" ) ) return DIGEST_AUTHENTICATION;
+ throw new RuntimeException( "Unsupported authentication type '" + getAuthenticationType() + "'" );
+ }
+
+
+ private AuthorizationRequiredException createAuthorizationRequiredException() {
+ return AuthorizationRequiredException.createException( getAuthenticationType(), getProperties() );
+ }
+
+
+ private PasswordAuthentication getCredentialsForRealm() {
+ return _client.getCredentialsForRealm( getProperty( "realm" ) );
+ }
+
+ private String getMethod() {
+ return null == _request ? null : _request.getMethod();
+ }
+
+
+ private String getRequestUri() {
+ try {
+ return null == _request ? null : _request.getURL().getFile();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+
+ private interface AuthenticationStrategy {
+ String createAuthenticationHeader( AuthenticationChallenge challenge, String username, String password );
+ }
+
+
+ private static class BasicAuthenticationStrategy implements AuthenticationStrategy {
+
+ public String createAuthenticationHeader( AuthenticationChallenge challenge, String userName, String password ) {
+ return "Basic " + Base64.encode( userName + ':' + password );
+ }
+
+ }
+
+ private static class DigestAuthenticationStrategy implements AuthenticationStrategy {
+
+ private class Algorithm {
+
+ public void appendParams( StringBuffer sb, AuthenticationChallenge challenge, String userName, String password ) {
+ appendDigestParams( sb, challenge.getProperty( "realm" ), challenge.getProperty( "nonce" ), challenge.getRequestUri(), userName, password, challenge.getMethod(), challenge.getProperty( "opaque" ) );
+ }
+
+
+ protected void appendDigestParams( StringBuffer sb, String realm, String nonce, String uri, String userName, String password, String method, String opaque ) {
+ sb.append( "username=" ).append( quote( userName ) );
+ append( sb, "realm", realm );
+ append( sb, "nonce", nonce );
+ append( sb, "uri", uri );
+ append( sb, "response", getResponse( userName, realm, password, nonce, uri, method ) );
+ append( sb, "opaque", opaque );
+ }
+
+
+ protected String getResponse( String userName, String realm, String password, String nonce, String uri, String method ) {
+ try {
+ String a1 = A1( userName, password, realm, nonce );
+ String a2 = A2( uri, method );
+ String ha1 = H( a1 );
+ String ha2 = H( a2 );
+ return KD( ha1, nonce + ':' + ha2 );
+ } catch (NoSuchAlgorithmException e) {
+ return "";
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+
+ protected String A1( String userName, String password, String realm, String nonce ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ return userName + ':' + realm + ':' + password;
+ }
+
+
+ protected String A2( String uri, String method ) {
+ return method + ':' + uri;
+ }
+
+
+ final protected String KD( String secret, String data ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ return H( secret + ":" + data );
+ }
+
+ final protected String H( String data ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ MessageDigest digest = MessageDigest.getInstance( "MD5" );
+ digest.update( data.getBytes( "UTF8" ) );
+ byte[] bytes = digest.digest();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < bytes.length; i++) {
+ int aByte = bytes[i];
+ if (aByte < 0) aByte += 256;
+ if (aByte < 16) sb.append( '0' );
+ sb.append( Integer.toHexString( aByte ) );
+ }
+
+ return sb.toString();
+ }
+
+ private void append( StringBuffer sb, String name, String value ) {
+ sb.append( "," ).append( name ).append( "=" ).append( quote( value ) );
+ }
+
+
+ private String quote( String value ) {
+ if (value.startsWith( "\"" )) {
+ return value;
+ } else {
+ return "\"" + value + "\"";
+ }
+ }
+
+ }
+
+
+ private class QopAlgorithm extends Algorithm {
+
+
+ protected void appendDigestParams( StringBuffer sb, String realm, String nonce, String uri, String userName, String password, String method, String opaque ) {
+ super.appendDigestParams( sb, realm, nonce, uri, userName, password, method, opaque );
+// append( sb, "qop", "auth" );
+// append( sb, "nc", getNonceCount() );
+// append( sb, "cnonce", getCNonce() );
+ }
+
+
+ protected String getResponse( String userName, String realm, String password, String nonce, String uri, String method ) {
+ try {
+ String a1 = A1( userName, password, realm, nonce );
+ String a2 = A2( uri, method );
+ String ha1 = H( a1 );
+ String ha2 = H( a2 );
+ return KD( ha1, nonce + ':' + ha2 );
+ } catch (NoSuchAlgorithmException e) {
+ return "";
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+
+ protected String A1( String userName, String password, String realm, String nonce ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ return H( userName + ":" + realm + ":" + password ) + ":" + nonce + ":" + getCNonce();
+ }
+
+
+ private String getCNonce() {
+ return ":";
+ }
+
+
+ protected String A2( String uri, String method ) {
+ return super.A2( uri, method ); //To change body of overridden methods use File | Settings | File Templates.
+ }
+ }
+
+ public String createAuthenticationHeader( AuthenticationChallenge challenge, String userName, String password ) {
+ StringBuffer sb = new StringBuffer( "Digest ");
+ Algorithm algorithm = new Algorithm();
+ algorithm.appendParams( sb, challenge, userName, password );
+ return sb.toString();
+ }
+
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/AuthorizationRequiredException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/AuthorizationRequiredException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/AuthorizationRequiredException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,82 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2002,2006, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.util.Properties;
+import java.util.Map;
+
+
+/**
+ * This exception is thrown when an unauthorized request is made for a page that requires authentication.
+ **/
+public class AuthorizationRequiredException extends RuntimeException {
+
+
+ public static AuthorizationRequiredException createBasicAuthenticationRequiredException( String realm ) {
+ Properties props = new Properties();
+ props.put( "realm", realm );
+ return new AuthorizationRequiredException( "Basic", props );
+ }
+
+
+ static AuthorizationRequiredException createException( String scheme, Map properties ) {
+ return new AuthorizationRequiredException( scheme, properties );
+ }
+
+
+ private AuthorizationRequiredException( String scheme, Map properties ) {
+ _scheme = scheme;
+ _properties = properties;
+ }
+
+
+ public String getMessage() {
+ return _scheme + " authentication required: " + _properties;
+ }
+
+
+ /**
+ * Returns the name of the authentication scheme.
+ **/
+ public String getAuthenticationScheme() {
+ return _scheme;
+ }
+
+
+ /**
+ * Returns the named authentication parameter. For Basic authentication, the only parameter is "realm".
+ **/
+ public String getAuthenticationParameter( String parameterName ) {
+ return unQuote( (String) _properties.get( parameterName ) );
+ }
+
+
+ private String unQuote( String value ) {
+ if (value == null || value.length() <= 1 || !value.startsWith( "\"" ) || !value.endsWith( "\"")) return value;
+
+ return value.substring( 1, value.length()-1 );
+ }
+
+//------------------------------------- private members ------------------------------------------
+
+
+ private String _scheme;
+ private Map _properties;
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/Base64.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/Base64.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/Base64.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,100 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2002 by Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+/**
+ * A utility class to convert to and from base 64 encoding.
+ *
+ * @author Russell Gold
+ **/
+public class Base64 {
+
+ final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+ /**
+ * Returns the base 64 encoded equivalent of a supplied string.
+ * @param source the string to encode
+ */
+ public static String encode( String source ) {
+ char[] sourceBytes = getPaddedBytes( source );
+ int numGroups = (sourceBytes.length + 2) / 3;
+ char[] targetBytes = new char[4];
+ char[] target = new char[ 4 * numGroups ];
+
+ for (int group = 0; group < numGroups; group++) {
+ convert3To4( sourceBytes, group*3, targetBytes );
+ for (int i = 0; i < targetBytes.length; i++) {
+ target[ i + 4*group ] = encodingChar.charAt( targetBytes[i] );
+ }
+ }
+
+ int numPadBytes = sourceBytes.length - source.length();
+
+ for (int i = target.length-numPadBytes; i < target.length; i++) target[i] = '=';
+ return new String( target );
+ }
+
+
+ private static char[] getPaddedBytes( String source ) {
+ char[] converted = source.toCharArray();
+ int requiredLength = 3 * ((converted.length+2) /3);
+ char[] result = new char[ requiredLength ];
+ System.arraycopy( converted, 0, result, 0, converted.length );
+ return result;
+ }
+
+
+ private static void convert3To4( char[] source, int sourceIndex, char[] target ) {
+ target[0] = (char) ( source[ sourceIndex ] >>> 2);
+ target[1] = (char) (((source[ sourceIndex ] & 0x03) << 4) | (source[ sourceIndex+1 ] >>> 4));
+ target[2] = (char) (((source[ sourceIndex+1 ] & 0x0f) << 2) | (source[ sourceIndex+2 ] >>> 6));
+ target[3] = (char) ( source[ sourceIndex+2 ] & 0x3f);
+ }
+
+
+ /**
+ * Returns the plaintext equivalent of a base 64-encoded string.
+ * @param source a base 64 string (which must have a multiple of 4 characters)
+ */
+ public static String decode( String source ) {
+ if (source.length()%4 != 0) throw new RuntimeException( "valid Base64 codes have a multiple of 4 characters" );
+ int numGroups = source.length() / 4;
+ int numExtraBytes = source.endsWith( "==" ) ? 2 : (source.endsWith( "=" ) ? 1 : 0);
+ byte[] targetBytes = new byte[ 3*numGroups ];
+ byte[] sourceBytes = new byte[4];
+ for (int group = 0; group < numGroups; group++) {
+ for (int i = 0; i < sourceBytes.length; i++) {
+ sourceBytes[i] = (byte) Math.max( 0, encodingChar.indexOf( source.charAt( 4*group+i ) ) );
+ }
+ convert4To3( sourceBytes, targetBytes, group*3 );
+ }
+ return new String( targetBytes, 0, targetBytes.length - numExtraBytes );
+ }
+
+
+ private static void convert4To3( byte[] source, byte[] target, int targetIndex ) {
+ target[ targetIndex ] = (byte) (( source[0] << 2) | (source[1] >>> 4));
+ target[ targetIndex+1 ] = (byte) (((source[1] & 0x0f) << 4) | (source[2] >>> 2));
+ target[ targetIndex+2 ] = (byte) (((source[2] & 0x03) << 6) | (source[3]));
+ }
+
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/BlockElement.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/BlockElement.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/BlockElement.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,219 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2006-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.w3c.dom.Node;
+
+import java.net.URL;
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+/**
+ * Represents a block-level element such as a paragraph or table cell, which can contain other elements.
+ *
+ * @author Russell Gold
+ *
+ * @since 1.6
+ **/
+abstract public class BlockElement extends ParsedHTML implements HTMLSegment, HTMLElement {
+
+
+ private ScriptingHandler _scriptable;
+ private Node _node;
+
+
+ /**
+ * Returns the text value of this block.
+ **/
+ public String getText() {
+ if (_node.getNodeType() == Node.TEXT_NODE) {
+ return _node.getNodeValue().trim();
+ } else if (_node == null || !_node.hasChildNodes()) {
+ return "";
+ } else {
+ return NodeUtils.asText( _node.getChildNodes() ).trim();
+ }
+ }
+
+
+ /**
+ * Returns the tag for this block.
+ */
+ public String getTagName() {
+ return _node == null ? "p" : _node.getNodeName();
+ }
+
+
+ /**
+ * Returns a copy of the domain object model associated with this HTML segment.
+ **/
+ public Node getDOM() {
+ return super.getDOM();
+ }
+
+
+//-------------------------------- HTMLElement methods ---------------------------------------
+
+
+ /**
+ * Returns the ID associated with this element. IDs are unique throughout the HTML document.
+ **/
+ public String getID() {
+ return getAttribute( "id" );
+ }
+
+
+ /**
+ * Returns the class attribute associated with this element.
+ */
+ public String getClassName() {
+ return getAttribute( "class" );
+ }
+
+
+ /**
+ * Returns the name associated with this element.
+ **/
+ public String getName() {
+ return getAttribute( "name" );
+ }
+
+
+ /**
+ * Returns the title associated with this element.
+ **/
+ public String getTitle() {
+ return getAttribute( "title" );
+ }
+
+
+ /**
+ * Returns the delegate which supports scripting this element.
+ */
+ public ScriptingHandler getScriptingHandler() {
+ if (_scriptable == null) {
+ _scriptable = HttpUnitOptions.getScriptingEngine().createHandler( this );
+ }
+ return _scriptable;
+ }
+
+ /**
+ * handle the event that has the given script attached
+ * by compiling the eventScript as a function and executing it
+ * @param eventScript - the script to use
+ * @deprecated since 1.7 - use doEventScript instead
+ */
+ public boolean doEvent( String eventScript ) {
+ return doEventScript(eventScript);
+ }
+
+ /**
+ * optional do the event if it's defined
+ * @param eventScript - the script to work on
+ * @return true if the event script was handled
+ */
+ public boolean doEventScript(String eventScript) {
+ return this.getScriptingHandler().doEventScript(eventScript);
+ }
+
+
+ public boolean handleEvent(String eventName) {
+ return this.getScriptingHandler().handleEvent(eventName);
+ }
+
+ public ScriptableDelegate getParentDelegate() {
+ return getResponse().getDocumentScriptable();
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+ /**
+ * get the attribute with the given name
+ * @param name - the name of the attribute to get
+ */
+ public String getAttribute( final String name ) {
+ return NodeUtils.getNodeAttribute( _node, name );
+ }
+
+ /**
+ * set the attribute with the given name to the given value
+ * @param name - the name of the attribute to set
+ * @param value - the value to use
+ */
+ public void setAttribute( final String name, final Object value ) {
+ NodeUtils.setNodeAttribute( _node, name, (value == null) ? null : value.toString() );
+ }
+
+ /**
+ * remove the attribute with the given name
+ * @param name - the name of the attribute
+ */
+ public void removeAttribute( final String name ) {
+ NodeUtils.removeNodeAttribute( _node, name );
+ }
+
+ /**
+ * Returns true if this element may have an attribute with the specified name.
+ */
+ public boolean isSupportedAttribute( String name ) {
+ return false;
+ }
+
+
+ public Node getNode() {
+ return _node;
+ }
+
+//----------------------------------------------- Object methods -------------------------------------------------------
+
+
+ public boolean equals( Object obj ) {
+ return getClass().equals( obj.getClass() ) && equals( (BlockElement) obj );
+ }
+
+
+ private boolean equals( BlockElement block ) {
+ return _node.equals( block._node );
+ }
+
+
+ public int hashCode() {
+ return _node.hashCode();
+ }
+
+
+//------------------------------------- protected members --------------------------------------------------------------
+
+
+ protected BlockElement( WebResponse response, FrameSelector frame, URL baseURL, String baseTarget, Node rootNode, String characterSet ) {
+ super( response, frame, baseURL, baseTarget, rootNode, characterSet );
+ _node = rootNode;
+ }
+
+
+ protected int getAttributeValue( Node node, String attributeName, int defaultValue ) {
+ return NodeUtils.getAttributeValue( node, attributeName, defaultValue );
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/Button.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/Button.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/Button.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,233 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+import com.meterware.httpunit.dom.*;
+import com.meterware.httpunit.parsing.ScriptHandler;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+
+
+/**
+ * A button in a form.
+ *
+ * @author Russell Gold
+ **/
+public class Button extends FormControl {
+
+ static final public HTMLElementPredicate WITH_ID;
+ static final public HTMLElementPredicate WITH_LABEL;
+
+ private WebResponse _baseResponse;
+ // remember the last verifyEnabled result
+ private boolean _wasEnabled=true;
+
+
+ public String getType() {
+ return BUTTON_TYPE;
+ }
+
+
+ Button( WebForm form ) {
+ super( form );
+ }
+
+
+ /**
+ * construct a button from the given html control and assign the event handlers for onclick, onmousedown and onmouseup
+ * @param form
+ * @param control
+ */
+ Button( WebForm form, HTMLControl control ) {
+ super( form, control );
+ }
+
+
+ Button( WebResponse response, HTMLControl control ) {
+ super( null, control );
+ _baseResponse = response;
+ }
+
+
+ /**
+ * Returns the value associated with this button.
+ **/
+ public String getValue() {
+ return emptyIfNull( getNode() instanceof HTMLInputElementImpl
+ ? ((HTMLInputElementImpl) getNode()).getValue()
+ : ((HTMLButtonElementImpl) getNode()).getValue() );
+ }
+
+ /**
+ * the onClickSequence for this button
+ * @return true if the even was handled
+ */
+ protected boolean doOnClickSequence(int x,int y) throws IOException, SAXException {
+ verifyButtonEnabled();
+ boolean result=doOnClickEvent();
+ if (result) {
+ doButtonAction(x,y);
+ }
+ this.rememberEnableState();
+ return result;
+ }
+
+ /**
+ * Performs the action associated with clicking this button after running any 'onClick' script.
+ * For a submit button this typically submits the form.
+ */
+ public void click() throws IOException, SAXException {
+ doOnClickSequence(0,0);
+ }
+
+
+ boolean wasEnabled() {
+ return _wasEnabled;
+ }
+
+ /**
+ * remember wether the button was enabled
+ */
+ public void rememberEnableState() {
+ _wasEnabled=!isDisabled();
+ }
+
+ /**
+ * verifyButtonEnabled
+ */
+ protected void verifyButtonEnabled() {
+ rememberEnableState();
+ if (isDisabled())
+ throwDisabledException();
+ }
+
+ /**
+ * throw an exception that I'm disbled
+ *
+ */
+ public void throwDisabledException() {
+ throw new DisabledButtonException(this);
+ }
+
+ /**
+ * This exception is thrown on an attempt to click on a button disabled button
+ **/
+ class DisabledButtonException extends IllegalStateException {
+
+
+ DisabledButtonException( Button button ) {
+ _name = button.getName();
+ _value = button.getValue();
+ }
+
+
+ public String getMessage() {
+ String msg="Button" + (getName().length() == 0 ? "" : " '" + getName() + "'") + " is disabled and may not be clicked.";
+ return msg;
+ }
+
+
+ protected String _name;
+ protected String _value;
+
+ }
+
+
+ /**
+ * Returns true if this button is disabled, meaning that it cannot be clicked.
+ **/
+ public boolean isDisabled() {
+ return super.isDisabled();
+ }
+
+
+ /**
+ * Perform the normal action of this button.
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ * @throws IOException
+ * @throws SAXException
+ */
+ protected void doButtonAction(int x,int y) throws IOException, SAXException {
+ // pseudo - abstract
+ }
+
+ /**
+ * Perform the normal action of this button.
+ * delegate to the x-y version
+ * @throws IOException
+ * @throws SAXException
+ */
+ protected void doButtonAction() throws IOException, SAXException {
+ doButtonAction(0,0);
+ }
+
+
+//-------------------------------------------------- FormControl methods -----------------------------------------------
+
+
+ protected String[] getValues() {
+ return new String[ 0 ];
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ if (getForm() != null) return super.getParentDelegate();
+ return _baseResponse.getDocumentScriptable();
+ }
+
+
+ class Scriptable extends FormControl.Scriptable {
+
+ public void click() throws IOException, SAXException {
+ doButtonAction();
+ }
+ }
+
+
+ static {
+ WITH_ID = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object button, Object id ) {
+ return ((Button) button).getID().equals( id );
+ }
+ };
+
+ WITH_LABEL = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object button, Object label ) {
+ return ((Button) button).getValue().equals( label );
+ }
+ };
+
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ClientProperties.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ClientProperties.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ClientProperties.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,322 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2003, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * A class which represents the properties of a web client.
+ *
+ * @author Russell Gold
+ **/
+public class ClientProperties {
+
+
+ /**
+ * Returns the current defaults for newly created web clients.
+ */
+ public static ClientProperties getDefaultProperties() {
+ return _defaultProperties;
+ }
+
+
+ /**
+ * Specifies the ID information for a client.
+ */
+ public void setApplicationID( String applicationName, String applicationCodeName, String applicationVersion ) {
+ _applicationCodeName = applicationCodeName;
+ _applicationName = applicationName;
+ _applicationVersion = applicationVersion;
+ }
+
+
+ public String getApplicationCodeName() {
+ return _applicationCodeName;
+ }
+
+
+ public void setApplicationCodeName( String applicationCodeName ) {
+ _applicationCodeName = applicationCodeName;
+ }
+
+
+ public String getApplicationName() {
+ return _applicationName;
+ }
+
+
+ public void setApplicationName( String applicationName ) {
+ _applicationName = applicationName;
+ }
+
+
+ public String getApplicationVersion() {
+ return _applicationVersion;
+ }
+
+
+ public void setApplicationVersion( String applicationVersion ) {
+ _applicationVersion = applicationVersion;
+ }
+
+
+ /**
+ * Returns the user agent identification. Unless this has been set explicitly, it will default to the
+ * application code name followed by a slash and the application version.
+ */
+ public String getUserAgent() {
+ return _userAgent != null ? _userAgent : _applicationCodeName + '/' + _applicationVersion;
+ }
+
+
+ public void setUserAgent( String userAgent ) {
+ _userAgent = userAgent;
+ }
+
+
+ public String getPlatform() {
+ return _platform;
+ }
+
+
+ public void setPlatform( String platform ) {
+ _platform = platform;
+ }
+
+
+ /**
+ * A shortcut for setting both availableScreenWidth and availableScreenHeight at one time.
+ */
+ public void setAvailableScreenSize( int width, int height ) {
+ _availWidth = width;
+ _availHeight = height;
+ }
+
+
+ public int getAvailableScreenWidth() {
+ return _availWidth;
+ }
+
+
+ public void setAvailableScreenWidth( int availWidth ) {
+ _availWidth = availWidth;
+ }
+
+
+ public int getAvailHeight() {
+ return _availHeight;
+ }
+
+
+ public void setAvailHeight( int availHeight ) {
+ _availHeight = availHeight;
+ }
+
+
+ /**
+ * Returns true if the client should accept and transmit cookies. The default is to accept them.
+ */
+ public boolean isAcceptCookies() {
+ return _acceptCookies;
+ }
+
+
+ /**
+ * Specifies whether the client should accept and send cookies.
+ */
+ public void setAcceptCookies( boolean acceptCookies ) {
+ _acceptCookies = acceptCookies;
+ }
+
+
+ /**
+ * Returns true if the client will accept GZIP encoding of responses. The default is to accept GZIP encoding.
+ **/
+ public boolean isAcceptGzip() {
+ return _acceptGzip;
+ }
+
+
+ /**
+ * Specifies whether the client will accept GZIP encoded responses. The default is true.
+ */
+ public void setAcceptGzip( boolean acceptGzip ) {
+ _acceptGzip = acceptGzip;
+ }
+
+
+ /**
+ * Returns true if the client should automatically follow page redirect requests (status 3xx).
+ * By default, this is true.
+ **/
+ public boolean isAutoRedirect() {
+ return _autoRedirect;
+ }
+
+
+ /**
+ * Determines whether the client should automatically follow page redirect requests (status 3xx).
+ * By default, this is true in order to simulate normal browser operation.
+ **/
+ public void setAutoRedirect( boolean autoRedirect ) {
+ _autoRedirect = autoRedirect;
+ }
+
+
+ /**
+ * Returns true if the client should automatically follow page refresh requests.
+ * By default, this is false, so that programs can verify the redirect page presented
+ * to users before the browser switches to the new page.
+ **/
+ public boolean isAutoRefresh() {
+ return _autoRefresh;
+ }
+
+
+ /**
+ * Specifies whether the client should automatically follow page refresh requests.
+ * By default, this is false, so that programs can verify the redirect page presented
+ * to users before the browser switches to the new page. Setting this to true can
+ * cause an infinite loop on pages that refresh themselves.
+ **/
+ public void setAutoRefresh( boolean autoRefresh ) {
+ _autoRefresh = autoRefresh;
+ }
+
+
+ public boolean isIframeSupported() {
+ return _iframeSupported;
+ }
+
+
+ public void setIframeSupported( boolean iframeSupported ) {
+ _iframeSupported = iframeSupported;
+ }
+
+
+ /**
+ * Returns the context type (if any) to use instead of the one specified by the server. Defaults to null.
+ * @return the overriding context type, or null if none is specified.
+ */
+ public String getOverrideContextType() {
+ return _overrideContextType;
+ }
+
+
+ /**
+ * All responses to this client will use the specified content type rather than the one specified by the server.
+ * Setting this to "text/html" will force all reponses to be interpreted as HTML.
+ * @param overrideContextType the new override to apply to context types.
+ */
+ public void setOverrideContextType( String overrideContextType ) {
+ _overrideContextType = overrideContextType;
+ }
+
+
+ /**
+ * Specifies a listener for DNS requests from the client.
+ * @param dnsListener the new listener.
+ */
+ public void setDnsListener( DNSListener dnsListener ) {
+ _dnsListener = dnsListener;
+ }
+
+
+ /**
+ * Returns the listener for DNS requests to be used by the client.
+ * @return the currently specified DNS listener, or null if none is specified.
+ */
+ DNSListener getDnsListener() {
+ return _dnsListener;
+ }
+
+ /**
+ * @return the whether Referer information should be stripped from the
+ * header
+ */
+ public boolean isSendReferer() {
+ return _sendReferer;
+ }
+
+
+ /**
+ * set whether Referer information should be stripped
+ * @param referer the _sendReferer to set
+ */
+ public void setSendReferer(boolean referer) {
+ _sendReferer = referer;
+ }
+
+
+ ClientProperties cloneProperties() {
+ return new ClientProperties( this );
+ }
+
+
+ private String _applicationCodeName = "httpunit";
+ private String _applicationName = "HttpUnit";
+ private String _applicationVersion = "1.5";
+ private String _userAgent;
+ private String _platform = "Java";
+ private String _overrideContextType = null;
+ private int _availWidth = 800;
+ private int _availHeight = 600;
+
+ private boolean _iframeSupported = true;
+ private boolean _acceptCookies = true;
+ private boolean _acceptGzip = true;
+ private boolean _autoRedirect = true;
+ private boolean _autoRefresh = false;
+
+ private DNSListener _dnsListener;
+ private boolean _sendReferer;
+
+ private static ClientProperties _defaultProperties = new ClientProperties();
+
+
+ /**
+ * default Constructor
+ *
+ */
+ private ClientProperties() {
+ _sendReferer=true;
+ }
+
+
+ /**
+ * copy constructor
+ * @param source - the ClientProperties to copy from
+ */
+ private ClientProperties( ClientProperties source ) {
+ _applicationCodeName = source._applicationCodeName;
+ _applicationName = source._applicationName;
+ _applicationVersion = source._applicationVersion;
+ _userAgent = source._userAgent;
+ _platform = source._platform;
+ _overrideContextType = source._overrideContextType;
+ _iframeSupported = source._iframeSupported;
+ _acceptCookies = source._acceptCookies;
+ _acceptGzip = source._acceptGzip;
+ _autoRedirect = source._autoRedirect;
+ _autoRefresh = source._autoRefresh;
+ _sendReferer = source._sendReferer;
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ContentConcealer.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ContentConcealer.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ContentConcealer.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,30 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2003, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * This is a marker interface implemented by HTMLElement classes which hide their content.
+ *
+ * @author Russell Gold
+ **/
+interface ContentConcealer {
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/DNSListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/DNSListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/DNSListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,18 @@
+package com.meterware.httpunit;
+
+/**
+ * A listener for DNS Requests. Users may implement this interface to bypass the normal DNS lookup.
+ *
+ * @author Russell Gold
+ **/
+public interface DNSListener {
+
+
+ /**
+ * Returns the IP address as a string for the specified host name.
+ * Note: no validation is done to verify that the returned value is an actual IP address or
+ * that the passed host name was not an IP address.
+ **/
+ String getIpAddress( String hostName );
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/DialogAdapter.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/DialogAdapter.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/DialogAdapter.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,45 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ *
+ * @author Russell Gold
+ **/
+public class DialogAdapter implements DialogResponder {
+
+ /**
+ * Invoked when the user agent needs to display a confirmation dialog. This default implementation confirms
+ * all dialogs.
+ */
+ public boolean getConfirmation( String confirmationPrompt ) {
+ return true;
+ }
+
+
+ /**
+ * Invoked when the user agent needs to display a generic dialog and obtain a user response. This default
+ * implementation returns the default response.
+ */
+ public String getUserResponse( String prompt, String defaultResponse ) {
+ return defaultResponse;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/DialogResponder.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/DialogResponder.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/DialogResponder.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,45 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+
+/**
+ * Interface for an object to supply user responses to dialogs.
+ *
+ * @author Russell Gold
+ **/
+public interface DialogResponder {
+
+
+ /**
+ * Invoked when the user agent needs to display a confirmation dialog. This method should return true
+ * to accept the proposed action or false to reject it.
+ */
+ public boolean getConfirmation( String confirmationPrompt );
+
+
+ /**
+ * Invoked when the user agent needs to display a generic dialog and obtain a user response. This method
+ * should return the user's answer.
+ */
+ public String getUserResponse( String prompt, String defaultResponse );
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ElementRegistry.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ElementRegistry.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ElementRegistry.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,62 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.w3c.dom.Node;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @author Russell Gold
+ */
+class ElementRegistry {
+
+ private Map _map = new HashMap();
+
+
+ /**
+ * Registers an HttpUnit element for a node.
+ * @return the registered element
+ */
+ Object registerElement( Node node, HTMLElement htmlElement ) {
+ _map.put( node, htmlElement );
+ return htmlElement;
+ }
+
+
+ /**
+ * Returns the HttpUnit element associated with the specified DOM element, if any.
+ */
+ Object getRegisteredElement( Node node ) {
+ return _map.get( node );
+ }
+
+
+ Iterator iterator() {
+ return _map.values().iterator();
+ }
+
+
+ boolean hasNode( Node node ) {
+ return _map.containsKey( node );
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/FixedURLWebRequestSource.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/FixedURLWebRequestSource.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/FixedURLWebRequestSource.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,249 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.util.*;
+import java.net.URL;
+import java.io.IOException;
+
+import org.w3c.dom.Node;
+import com.meterware.httpunit.protocol.UploadFileSpec;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+
+
+/**
+ * An implementation of web request source whose URL does not change under user action.
+ *
+ * @author Russell Gold
+ **/
+abstract class FixedURLWebRequestSource extends WebRequestSource {
+
+ private static final String[] NO_VALUES = new String[0];
+ private Map _presetParameterMap;
+ private ArrayList _presetParameterList;
+ private String _characterSet;
+
+
+ public FixedURLWebRequestSource( WebResponse response, Node node, URL baseURL, String attribute, FrameSelector frame, String defaultTarget, String characterSet ) {
+ super( response, node, baseURL, attribute, frame, defaultTarget );
+ _characterSet = characterSet;
+ }
+
+
+//------------------------------------------- WebRequestSource methods -------------------------------------------------
+
+
+ /**
+ * Creates and returns a web request which will simulate clicking on this link.
+ **/
+ public WebRequest getRequest() {
+ return new GetMethodWebRequest( this );
+ }
+
+
+ /**
+ * Returns an array containing the names of any parameters defined as part of this link's URL.
+ **/
+ public String[] getParameterNames() {
+ ArrayList parameterNames = new ArrayList( getPresetParameterMap().keySet() );
+ return (String[]) parameterNames.toArray( new String[ parameterNames.size() ] );
+ }
+
+
+ /**
+ * Returns the multiple default values of the named parameter.
+ **/
+ public String[] getParameterValues( String name ) {
+ final String[] values = (String[]) getPresetParameterMap().get( name );
+ return values == null ? NO_VALUES : values;
+ }
+
+
+ protected void addPresetParameter( String name, String value ) {
+ _presetParameterMap.put( name, HttpUnitUtils.withNewValue( (String[]) _presetParameterMap.get( name ), value ) );
+ _presetParameterList.add( new PresetParameter( name, value ) );
+ }
+
+
+ protected String getEmptyParameterValue() {
+ return "";
+ }
+
+
+ protected void setDestination( String destination ) {
+ super.setDestination( destination );
+ _presetParameterList = null;
+ _presetParameterMap = null;
+ }
+
+
+//------------------------------------------- ParameterHolder methods --------------------------------------------------
+
+
+ /**
+ * Specifies the position at which an image button (if any) was clicked.
+ **/
+ void selectImageButtonPosition( SubmitButton imageButton, int x, int y ) {
+ throw new IllegalNonFormParametersRequest();
+ }
+
+
+ /**
+ * Iterates through the fixed, predefined parameters in this holder, recording them in the supplied parameter processor.\
+ * These parameters always go on the URL, no matter what encoding method is used.
+ **/
+
+ void recordPredefinedParameters( ParameterProcessor processor ) throws IOException {
+ }
+
+
+ /**
+ * Iterates through the parameters in this holder, recording them in the supplied parameter processor.
+ **/
+ public void recordParameters( ParameterProcessor processor ) throws IOException {
+ Iterator i = getPresetParameterList().iterator();
+ while (i.hasNext()) {
+ PresetParameter o = (PresetParameter) i.next();
+ processor.addParameter( o.getName(), o.getValue(), getCharacterSet() );
+ }
+ }
+
+
+ /**
+ * Removes a parameter name from this collection.
+ **/
+ void removeParameter( String name ) {
+ throw new IllegalNonFormParametersRequest();
+ }
+
+
+ /**
+ * Sets the value of a parameter in a web request.
+ **/
+ void setParameter( String name, String value ) {
+ setParameter( name, new String[] { value } );
+ }
+
+
+ /**
+ * Sets the multiple values of a parameter in a web request.
+ **/
+ void setParameter( String name, String[] values ) {
+ if (values == null) {
+ throw new IllegalArgumentException( "May not supply a null argument array to setParameter()" );
+ } else if (!getPresetParameterMap().containsKey( name )) {
+ throw new IllegalNonFormParametersRequest();
+ } else if (!equals( getParameterValues( name ), values )) {
+ throw new IllegalNonFormParametersRequest();
+ }
+ }
+
+
+ String getCharacterSet() {
+ return _characterSet;
+ }
+
+
+ private boolean equals( String[] left, String[] right ) {
+ if (left.length != right.length) return false;
+ List rightValues = Arrays.asList( right );
+ for (int i = 0; i < left.length; i++) {
+ if (!rightValues.contains( left[i] )) return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Sets the multiple values of a file upload parameter in a web request.
+ **/
+ void setParameter( String name, UploadFileSpec[] files ) {
+ throw new IllegalNonFormParametersRequest();
+ }
+
+
+ /**
+ * Returns true if the specified parameter is a file field.
+ **/
+ boolean isFileParameter( String name ) {
+ return false;
+ }
+
+
+ boolean isSubmitAsMime() {
+ return false;
+ }
+
+
+ private Map getPresetParameterMap() {
+ if (_presetParameterMap == null) loadPresetParameters();
+ return _presetParameterMap;
+ }
+
+
+ private ArrayList getPresetParameterList() {
+ if (_presetParameterList == null) loadPresetParameters();
+ return _presetParameterList;
+ }
+
+
+ private void loadPresetParameters() {
+ _presetParameterMap = new HashMap();
+ _presetParameterList = new ArrayList();
+ loadDestinationParameters();
+ }
+
+
+}
+
+
+class PresetParameter {
+ private String _name;
+ private String _value;
+
+
+ public PresetParameter( String name, String value ) {
+ _name = name;
+ _value = value;
+ }
+
+
+ public String getName() {
+ return _name;
+ }
+
+
+ public String getValue() {
+ return _value;
+ }
+}
+
+
+class IllegalNonFormParametersRequest extends IllegalRequestParameterException {
+
+ public IllegalNonFormParametersRequest() {
+ }
+
+ public String getMessage() {
+ return "May not modify parameters for a request not derived from a form with parameter checking enabled.";
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/FormControl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/FormControl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/FormControl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,1023 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.*;
+import com.meterware.httpunit.controls.SelectionFormControl;
+import com.meterware.httpunit.dom.*;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+import com.meterware.httpunit.protocol.UploadFileSpec;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import java.util.Hashtable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Set;
+import java.io.IOException;
+
+
+/**
+ * Represents a control in an HTML form.
+ *
+ * @author Russell Gold
+ **/
+public abstract class FormControl extends HTMLElementBase {
+
+ final static String[] NO_VALUE = new String[0];
+
+ private final WebForm _form;
+ private HTMLControl _control;
+
+ public static final String UNDEFINED_TYPE = "undefined";
+ public static final String BUTTON_TYPE = "button";
+ public static final String RESET_BUTTON_TYPE = "reset";
+ public static final String SUBMIT_BUTTON_TYPE = "submit";
+ public static final String IMAGE_BUTTON_TYPE = "image";
+ public static final String RADIO_BUTTON_TYPE = "radio";
+ public static final String CHECKBOX_TYPE = "checkbox";
+ public static final String TEXT_TYPE = "text";
+ public static final String PASSWORD_TYPE = "password";
+ public static final String HIDDEN_TYPE = "hidden";
+ public static final String TEXTAREA_TYPE = "textarea";
+ public static final String FILE_TYPE = "file";
+ public static final String SINGLE_TYPE = "select-one";
+ public static final String MULTIPLE_TYPE = "select-multiple";
+
+
+ /**
+ * Return the type of the control, as seen from JavaScript.
+ */
+ abstract public String getType();
+
+ static ScriptableDelegate newSelectionOption() {
+ return new SelectionFormControl.Option();
+ }
+
+
+ FormControl( WebForm form ) {
+ this( form, newEmptyControlElement( form ) );
+ }
+
+
+ private static HTMLControl newEmptyControlElement( WebForm form ) {
+ return (HTMLControl) form.getElement().getOwnerDocument().createElement( "input" );
+ }
+
+
+ /**
+ * initialize the given form control from a Webform and a HTMLControl
+ * @param form
+ * @param control
+ */
+ protected FormControl( WebForm form, HTMLControl control ) {
+ super( control );
+ _control = control;
+ _form = form;
+ supportAttribute( "tabindex" );
+ supportAttribute( "disabled" );
+ // Add all custom attributes
+ Set customAttributes = HttpUnitOptions.getCustomAttributes();
+ if(customAttributes != null) {
+ for(Iterator iter = customAttributes.iterator(); iter.hasNext(); ) {
+ supportAttribute((String)iter.next());
+ }
+ }
+ }
+
+
+ /**
+ * Returns the current value(s) associated with this control. These values will be transmitted to the server
+ * if the control is 'successful'.
+ **/
+ protected abstract String[] getValues();
+
+
+ /**
+ * Returns either a single delegate object or potentially an array of delegates as needed, given the form control.
+ * This default implementation returns the scriptable delegate for the control.
+ */
+ Object getDelegate() {
+ return getScriptingHandler();
+ }
+
+
+ final protected WebForm getForm() {
+ return _form;
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return (ScriptableDelegate) getForm().getScriptingHandler();
+ }
+
+
+ /**
+ * Returns the values permitted in this control. Does not apply to text or file controls.
+ **/
+ public String[] getOptionValues() {
+ return NO_VALUE;
+ }
+
+
+ /**
+ * Returns the list of values displayed by this control, if any.
+ **/
+ protected String[] getDisplayedOptions() {
+ return NO_VALUE;
+ }
+
+
+ /**
+ * Returns true if this control is read-only.
+ **/
+ protected boolean isReadOnly() {
+ return isDisabled() || _control.getReadOnly();
+ }
+
+
+ /**
+ * Returns true if this control is hidden.
+ **/
+ public boolean isHidden() {
+ return false;
+ }
+
+
+ void setDisabled( boolean disabled ) {
+ _control.setDisabled( disabled );
+ }
+
+
+ /**
+ * Returns true if this control is disabled, meaning that it will not send a value to the server as part of a request.
+ **/
+ public boolean isDisabled() {
+ return _control.getDisabled();
+ }
+
+
+ /**
+ * Returns true if this control accepts free-form text.
+ **/
+ boolean isTextControl() {
+ return false;
+ }
+
+
+ /**
+ * Returns true if only one control of this kind with this name can have a value. This is true for radio buttons.
+ **/
+ boolean isExclusive() {
+ return false;
+ }
+
+
+ /**
+ * Returns true if a single control can have multiple values.
+ **/
+ protected boolean isMultiValued() {
+ return false;
+ }
+
+
+ /**
+ * Returns true if this control accepts a file for upload.
+ **/
+ boolean isFileParameter() {
+ return false;
+ }
+
+
+ protected abstract void addValues( ParameterProcessor processor, String characterSet ) throws IOException;
+
+
+ /**
+ * Remove any required values for this control from the list, throwing an exception if they are missing.
+ **/
+ void claimRequiredValues( List values ) {
+ }
+
+
+ /**
+ * Sets this control to the next compatible value from the list, removing it from the list.
+ **/
+ void claimValue( List values ) {
+ }
+
+
+ /**
+ * Sets this control to the next compatible value from the list, removing it from the list.
+ **/
+ protected void claimUniqueValue( List values ) {
+ }
+
+
+ /**
+ * Specifies a file to be uploaded via this control.
+ **/
+ void claimUploadSpecification( List files ) {
+ }
+
+
+ /**
+ * Resets this control to its initial value.
+ **/
+ protected void reset() {
+ _control.reset();
+ }
+
+
+ /**
+ * Toggles the value of this control.
+ */
+ public void toggle() {
+ throw new FormParameter.IllegalCheckboxParameterException( getName(), "toggleCheckbox" );
+ }
+
+
+ /**
+ * Sets the state of this boolean control.
+ */
+ public void setState( boolean state ) {
+ throw new FormParameter.IllegalCheckboxParameterException( getName(), "setCheckbox" );
+ }
+
+
+ /**
+ * Performs the 'onChange' event defined for this control.
+ * @deprecated since 1.7 use doOnChangeEvent instead
+ */
+ protected void sendOnChangeEvent() {
+ doOnChangeEvent();
+ }
+
+ /**
+ * Performs the 'onchange' event defined for this control.
+ */
+ protected boolean doOnChangeEvent() {
+ return handleEvent("onchange");
+ }
+
+
+ /**
+ * Performs the 'onClick' event defined for this control.
+ * @deprecated since 1.7 use doOnClickEvent instead
+ */
+ protected void sendOnClickEvent() {
+ doOnClickEvent();
+ }
+
+
+ /**
+ * Performs the 'onClick' event defined for this control.
+ */
+ protected boolean doOnClickEvent() {
+ return handleEvent("onclick");
+ }
+
+ /**
+ * Performs the 'onMouseUp' event defined for this control.
+ * @deprecated since 1.7 use doOnMouseUpEvent instead
+ */
+ protected void sendOnMouseUpEvent() {
+ doOnMouseUpEvent();
+ }
+
+ /**
+ * Performs the 'onMouseUp' event defined for this control.
+ */
+ protected boolean doOnMouseUpEvent() {
+ return handleEvent("onmouseup");
+ }
+
+ /**
+ * Performs the 'onMouseDown' event defined for this control.
+ * @deprecated since 1.7 use doOnMouseDownEvent instead
+ */
+ protected void sendOnMouseDownEvent() {
+ doOnMouseDownEvent();
+ }
+
+ /**
+ * Performs the 'onMouseDown' event defined for this control.
+ */
+ protected boolean doOnMouseDownEvent() {
+ return handleEvent("onmousedown");
+ }
+
+ /**
+ * Creates and returns a scriptable object for this control. Subclasses should override this if they use a different
+ * implementation of Scriptable.
+ */
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ /**
+ * Returns the value of this control in the form. If no value is specified, defaults to the empty string.
+ **/
+ protected String getValueAttribute() {
+ return "";
+ }
+
+ /**
+ * Sets the value of this control in the form.
+ */
+ protected void setValueAttribute( String value ) {}
+
+
+ /**
+ * Removes the specified required value from the list of values, throwing an exception if it is missing.
+ **/
+ final protected void claimValueIsRequired( List values, final String value ) {
+ if (!values.contains( value )) throw new MissingParameterValueException( getName(), value, (String[]) values.toArray( new String[ values.size() ]) );
+ values.remove( value );
+ }
+
+
+ static String[] getControlElementTags() {
+ return new String[] { "textarea", "select", "button", "input" };
+ }
+
+
+ /**
+ * return the FormControl for the given parameter node in a form
+ * @param form - the form in which the parameter is defined
+ * @param node - the node in which the parameter is defined
+ * @return the form control
+ */
+ static FormControl newFormParameter( WebForm form, Node node ) {
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ return null;
+ } else if (node.getNodeName().equalsIgnoreCase( "textarea" )) {
+ return new TextAreaFormControl( form, (HTMLTextAreaElementImpl) node );
+ } else if (node.getNodeName().equalsIgnoreCase( "select" )) {
+ return new SelectionFormControl( form, (HTMLSelectElementImpl) node );
+ } else if (node.getNodeName().equalsIgnoreCase( "button" )) {
+ HTMLControl control = (HTMLControl) node;
+ final String type = control.getType();
+ if (type.equalsIgnoreCase( SUBMIT_BUTTON_TYPE )) {
+ return new SubmitButton( form, control );
+ } else if (type.equalsIgnoreCase( RESET_BUTTON_TYPE )) {
+ return new ResetButton( form, control );
+ } else {
+ return new Button( form, control );
+ }
+ } else if (!node.getNodeName().equalsIgnoreCase( "input" )) {
+ return null;
+ } else {
+ HTMLInputElementImpl element = (HTMLInputElementImpl) node;
+ final String type = element.getType();
+ if (type.equalsIgnoreCase( TEXT_TYPE )) {
+ return new TextFieldFormControl( form, element );
+ } else if (type.equalsIgnoreCase( PASSWORD_TYPE )) {
+ return new PasswordFieldFormControl( form, element );
+ } else if (type.equalsIgnoreCase( HIDDEN_TYPE )) {
+ return new HiddenFieldFormControl( form, element );
+ } else if (type.equalsIgnoreCase( RADIO_BUTTON_TYPE )) {
+ return new RadioButtonFormControl( form, element );
+ } else if (type.equalsIgnoreCase( CHECKBOX_TYPE )) {
+ return new CheckboxFormControl( form, element );
+ } else if (type.equalsIgnoreCase( SUBMIT_BUTTON_TYPE ) || type.equalsIgnoreCase( IMAGE_BUTTON_TYPE )) {
+ return new SubmitButton( form, element );
+ } else if (type.equalsIgnoreCase( BUTTON_TYPE )) {
+ return new Button( form, (HTMLControl) node );
+ } else if (type.equalsIgnoreCase( RESET_BUTTON_TYPE )) {
+ return new ResetButton( form, (HTMLControl) node );
+ } else if (type.equalsIgnoreCase( FILE_TYPE )) {
+ return new FileSubmitFormControl( form, element );
+ } else {
+ return new TextFieldFormControl( form, element );
+ }
+ }
+ }
+
+
+ protected String emptyIfNull( String value ) {
+ return (value == null) ? "" : value;
+ }
+
+ /**
+ * implementation of Scriptable input elements
+ */
+ public class Scriptable extends HTMLElementScriptable implements Input {
+
+ /**
+ * get my Name
+ * @return the name of this scriptable
+ */
+ public String getName() {
+ return FormControl.this.getName();
+ }
+
+
+ /**
+ * get my ID
+ * @return the id of this scriptable
+ */
+ public String getID() {
+ return FormControl.this.getID();
+ }
+
+
+ /**
+ * construct a Scriptable
+ */
+ public Scriptable() {
+ super( FormControl.this );
+ }
+
+
+ /**
+ * get the given property
+ * @param propertyName - the name of the property to get
+ */
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "name" )) {
+ return FormControl.this.getName();
+ } else if (propertyName.equalsIgnoreCase( "type" )) {
+ return FormControl.this.getType();
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ /**
+ * set the given property to the given value
+ * @param propertyName - the property to set
+ * @param value - the value to use
+ */
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equalsIgnoreCase( "value" )) {
+ setValueAttribute( value.toString() );
+ } else if (propertyName.equalsIgnoreCase( "disabled" )) {
+ setDisabled( value instanceof Boolean && ((Boolean) value).booleanValue() );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+
+ /**
+ * set the given attribute to the given value
+ * @param attributeName - the name of the attribute to set
+ * @param value - the value to use
+ */
+ public void setAttribute(String attributeName, Object value) {
+ // Value set by JavaScript, make sure attribute is supported
+ supportAttribute(attributeName);
+ super.setAttribute( attributeName, value );
+ }
+
+ /**
+ * allow calling click for this control
+ */
+ public void click() throws IOException, SAXException {
+ // TODO check whether the empty body of this method was correct
+ // call onclick event handler
+ HTMLElement element=this.get_element();
+ if (element instanceof FormControl) {
+ FormControl control=(FormControl)element;
+ control.sendOnClickEvent();
+ }
+ }
+
+ /**
+ * simulate blur
+ */
+ public void blur() {
+ handleEvent("onblur");
+ }
+
+
+ /**
+ * simulate focus;
+ */
+ public void focus() {
+ handleEvent("onfocus");
+ }
+
+ /**
+ * allow firing a sendOnChangeEvent
+ *
+ */
+ public void sendOnChangeEvent() {
+ // TODO check why the test for this does not work although
+ // the javascript function call is done in the corresponding testcase
+ // testCallOnChange()
+ HTMLElement element=this.get_element();
+ if (element instanceof FormControl) {
+ FormControl control=(FormControl)element;
+ control.sendOnChangeEvent();
+ }
+ }
+
+ }
+
+}
+
+
+abstract class BooleanFormControl extends FormControl {
+
+ private String[] _displayedValue;
+
+ private HTMLInputElementImpl _element;
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ class Scriptable extends FormControl.Scriptable {
+
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "value" )) {
+ return getQueryValue();
+ } else if (propertyName.equalsIgnoreCase( "checked" )) {
+ return isChecked() ? Boolean.TRUE : Boolean.FALSE;
+ } else if (propertyName.equalsIgnoreCase( "defaultchecked" )) {
+ return _element.getDefaultChecked() ? Boolean.TRUE : Boolean.FALSE;
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equalsIgnoreCase( "checked" )) {
+ setChecked( value instanceof Boolean && ((Boolean) value).booleanValue() );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+ }
+
+ public BooleanFormControl( WebForm form, HTMLInputElementImpl element ) {
+ super( form, element );
+ _element = element;
+ _displayedValue = new String[] { readDisplayedValue( element ) };
+ }
+
+
+ private String readDisplayedValue( Node node ) {
+ Node nextSibling = node.getNextSibling();
+ while (nextSibling != null && nextSibling.getNodeType() != Node.TEXT_NODE && nextSibling.getNodeType() != Node.ELEMENT_NODE) nextSibling = nextSibling.getNextSibling();
+ if (nextSibling == null || nextSibling.getNodeType() != Node.TEXT_NODE) return "";
+ return nextSibling.getNodeValue();
+ }
+
+
+ boolean isChecked() {
+ return _element.getChecked();
+ }
+
+
+ protected String getValueAttribute() {
+ return emptyIfNull( _element.getValue() );
+ }
+
+
+ protected void setValueAttribute( String value ) {
+ _element.setValue( value );
+ }
+
+
+ public void setChecked( boolean checked ) {
+ _element.setChecked( checked );
+ }
+
+
+ /**
+ * Returns the current value(s) associated with this control. These values will be transmitted to the server
+ * if the control is 'successful'.
+ **/
+ public String[] getValues() {
+ return isChecked() ? toArray( getQueryValue() ) : NO_VALUE;
+ }
+
+
+ /**
+ * Returns the values permitted in this control.
+ **/
+ public String[] getOptionValues() {
+ return (isReadOnly() && !isChecked()) ? NO_VALUE : toArray( getQueryValue() );
+ }
+
+
+ protected String[] getDisplayedOptions() {
+ return _displayedValue;
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ if (isChecked() && !isDisabled()) processor.addParameter( getName(), getQueryValue(), characterSet );
+ }
+
+
+ /**
+ * Remove any required values for this control from the list, throwing an exception if they are missing.
+ **/
+ void claimRequiredValues( List values ) {
+ if (isValueRequired()) claimValueIsRequired( values, getQueryValue() );
+ }
+
+
+ protected boolean isValueRequired() {
+ return isReadOnly() && isChecked();
+ }
+
+
+ abstract String getQueryValue();
+
+
+ private String[] toArray( String value ) {
+ return new String[] { value };
+ }
+}
+
+
+class CheckboxFormControl extends BooleanFormControl {
+
+ public String getType() {
+ return CHECKBOX_TYPE;
+ }
+
+ public CheckboxFormControl( WebForm form, HTMLInputElementImpl element ) {
+ super( form, element );
+ }
+
+
+ protected void claimUniqueValue( List values ) {
+ if (isValueRequired()) return;
+ setState( values.contains( getQueryValue() ) );
+ if (isChecked()) values.remove( getQueryValue() );
+ }
+
+
+ String getQueryValue() {
+ final String value = getValueAttribute();
+ return value.length() == 0 ? "on" : value;
+ }
+
+
+ /**
+ * Toggles the value of this control.
+ */
+ public void toggle() {
+ setState( !isChecked() );
+ }
+
+
+ /**
+ * Sets the state of this boolean control. Triggers the 'onclick' event if the state has changed.
+ */
+ public void setState( boolean state ) {
+ boolean wasChecked = isChecked();
+ setChecked( state );
+ if (isChecked() != wasChecked) sendOnClickEvent();
+ }
+ }
+
+
+abstract class TextFormControl extends FormControl {
+
+ public TextFormControl( WebForm form, HTMLControl control ) {
+ super( form, control );
+ }
+
+
+ /**
+ * Returns the current value(s) associated with this control. These values will be transmitted to the server
+ * if the control is 'successful'.
+ **/
+ public String[] getValues() {
+ return new String[] { getValue() };
+ }
+
+
+ abstract protected String getDefaultValue();
+
+ abstract protected String getValue();
+
+ abstract protected void setValue( String value );
+
+
+ /**
+ * Returns true to indicate that this control accepts free-form text.
+ **/
+ public boolean isTextControl() {
+ return true;
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ if (!isDisabled() && getName().length() > 0) processor.addParameter( getName(), getValues()[0], characterSet );
+ }
+
+
+ /**
+ * claim values and fire onChange Event if a change occured
+ * @param values - the list of values
+ */
+ void claimValue( List values ) {
+ if (isReadOnly()) return;
+
+ String oldValue = getValue();
+ if (values.isEmpty()) {
+ setValue( "" );
+ } else {
+ setValue( (String) values.get(0) );
+ values.remove(0);
+ }
+ boolean same=oldValue==null && getValue()==null;
+ if (oldValue!=null)
+ same=oldValue.equals( getValue());
+ if (!same) sendOnChangeEvent();
+ }
+
+
+ void claimRequiredValues( List values ) {
+ if (isReadOnly()) claimValueIsRequired( values );
+ }
+
+
+ protected void claimValueIsRequired( List values ) {
+ claimValueIsRequired( values, getDefaultValue() );
+ }
+
+ class Scriptable extends FormControl.Scriptable {
+
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "value" )) {
+ return getValue();
+ } else if (propertyName.equalsIgnoreCase( "defaultValue" )) {
+ return getDefaultValue();
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ public void set( String propertyName, Object value ) {
+ if (!propertyName.equalsIgnoreCase( "value" )) {
+ super.set( propertyName, value );
+ } else if (value instanceof Number) {
+ setValue( HttpUnitUtils.trimmedValue( (Number) value ) );
+ } else {
+ setValue( (value == null) ? null : value.toString() );
+ }
+ }
+ }
+}
+
+
+class TextFieldFormControl extends TextFormControl {
+
+ private HTMLInputElementImpl _element;
+
+ public String getType() {
+ return TEXT_TYPE;
+ }
+
+ public TextFieldFormControl( WebForm form, HTMLInputElementImpl element ) {
+ super( form, element );
+ _element = element;
+ supportAttribute( "maxlength" );
+ }
+
+
+ protected String getDefaultValue() {
+ return _element.getDefaultValue();
+ }
+
+
+ protected String getValue() {
+ return emptyIfNull( _element.getValue() );
+ }
+
+
+ protected void setValue( String value ) {
+ _element.setValue( value );
+ }
+}
+
+class PasswordFieldFormControl extends TextFieldFormControl {
+
+ public String getType() {
+ return PASSWORD_TYPE;
+ }
+
+ public PasswordFieldFormControl(WebForm form, HTMLInputElementImpl element) {
+ super(form, element);
+ }
+}
+
+/**
+ * a hidden text field
+ */
+class HiddenFieldFormControl extends TextFieldFormControl {
+
+ public String getType() {
+ return HIDDEN_TYPE;
+ }
+
+ public HiddenFieldFormControl( WebForm form, HTMLInputElementImpl element ) {
+ super( form, element );
+ }
+
+
+ void claimRequiredValues( List values ) {
+ claimValueIsRequired( values );
+ }
+
+
+ void claimValue( List values ) {
+ }
+
+
+ public boolean isHidden() {
+ return true;
+ }
+}
+
+
+class TextAreaFormControl extends TextFormControl {
+
+ private HTMLTextAreaElementImpl _element;
+
+ public TextAreaFormControl( WebForm form, HTMLTextAreaElementImpl element ) {
+ super( form, element );
+ _element = element;
+ }
+
+ public String getType() {
+ return TEXTAREA_TYPE;
+ }
+
+
+ protected String getDefaultValue() {
+ return _element.getDefaultValue();
+ }
+
+
+ protected String getValue() {
+ return _element.getValue();
+ }
+
+
+ protected void setValue( String value ) {
+ _element.setValue( value );
+ }
+
+}
+
+
+/**
+ * a control for File submit
+ */
+class FileSubmitFormControl extends FormControl {
+
+ /**
+ * accessor for the type
+ * @return the constant FILE_TYPE
+ */
+ public String getType() {
+ return FILE_TYPE;
+ }
+
+ private UploadFileSpec _fileToUpload;
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ class Scriptable extends FormControl.Scriptable {
+
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "value" )) {
+ return getSelectedName();
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ }
+
+ public FileSubmitFormControl( WebForm form, HTMLInputElementImpl node ) {
+ super( form, node );
+ }
+
+
+ /**
+ * Returns true if this control accepts a file for upload.
+ **/
+ public boolean isFileParameter() {
+ return true;
+ }
+
+
+ /**
+ * Returns the name of the selected file, if any.
+ */
+ public String[] getValues() {
+ return new String[] { getSelectedName() };
+ }
+
+
+ private String getSelectedName() {
+ return _fileToUpload == null ? "" : _fileToUpload.getFileName();
+ }
+
+
+ /**
+ * Specifies a number of file upload specifications for this control.
+ **/
+ void claimUploadSpecification( List files ) {
+ if (files.isEmpty()) {
+ _fileToUpload = null;
+ } else {
+ _fileToUpload = (UploadFileSpec) files.get(0);
+ files.remove(0);
+ }
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ if (!isDisabled() && _fileToUpload != null) {
+ processor.addFile( getName(), _fileToUpload );
+ }
+ }
+}
+
+
+
+
+//============================= exception class MissingParameterValueException ======================================
+
+
+/**
+ * This exception is thrown on an attempt to remove a required value from a form parameter.
+ **/
+class MissingParameterValueException extends IllegalRequestParameterException {
+
+
+ MissingParameterValueException( String parameterName, String missingValue, String[] proposed ) {
+ _parameterName = parameterName;
+ _missingValue = missingValue;
+ _proposedValues = proposed;
+ }
+
+
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
+ sb.append( "Parameter '" ).append( _parameterName ).append( "' must have the value '" );
+ sb.append( _missingValue ).append( "'. Attempted to set it to: { " );
+ for (int i = 0; i < _proposedValues.length; i++) {
+ if (i != 0) sb.append( ", " );
+ sb.append( _proposedValues[i] );
+ }
+ sb.append( " }" );
+ return sb.toString();
+ }
+
+
+ private String _parameterName;
+ private String _missingValue;
+ private String[] _proposedValues;
+}
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/FormParameter.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/FormParameter.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/FormParameter.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,375 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2003,2006-2007 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.protocol.UploadFileSpec;
+
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Represents the aggregate of all form controls with a particular name. This permits us to abstract setting
+ * values so that changing a control type does not break a test.
+ *
+ * @author Russell Gold
+ **/
+public class FormParameter {
+
+
+ private FormControl[] _controls;
+ private ArrayList _controlList = new ArrayList();
+ private RadioGroupFormControl _group;
+ private String _name;
+
+
+ void addControl( FormControl control ) {
+ _controls = null;
+ if (_name == null) _name = control.getName();
+ if (!_name.equalsIgnoreCase( control.getName() )) throw new RuntimeException( "all controls should have the same name" );
+ if (control.isExclusive()) {
+ getRadioGroup( control.getForm() ).addRadioButton( (RadioButtonFormControl) control );
+ } else {
+ _controlList.add( control );
+ }
+ }
+
+
+ /**
+ * get the controls for this form Parameter
+ * @return the controls
+ */
+ public FormControl[] getControls() {
+ if (_controls == null) _controls = (FormControl[]) _controlList.toArray( new FormControl[ _controlList.size() ] );
+ return _controls;
+ }
+
+ /**
+ * get the control for this form Parameter (assuming it
+ * has only one as for a text control
+ * @return the controls
+ */
+ public FormControl getControl() {
+ FormControl[] controls=getControls();
+ if (controls.length!=1) {
+ throw new RuntimeException("getControl can only be called if the number of controls is 1 but it is "+controls.length+" you might want to use getControls instead");
+ }
+ return controls[0];
+ }
+
+
+ Object getScriptableObject() {
+ if (getControls().length == 1) {
+ return getControls()[0].getDelegate();
+ } else {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < _controls.length; i++) {
+ FormControl control = _controls[i];
+ list.add( control.getScriptingHandler() );
+ }
+ return list.toArray( new ScriptableDelegate[ list.size() ] );
+ }
+ }
+
+
+ String[] getValues() {
+ ArrayList valueList = new ArrayList();
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ valueList.addAll( Arrays.asList( controls[i].getValues() ) );
+ }
+ return (String[]) valueList.toArray( new String[ valueList.size() ] );
+ }
+
+
+ /**
+ * set values to the given values
+ * @param values
+ */
+ void setValues( String[] values ) {
+ ArrayList list = new ArrayList( values.length );
+ list.addAll( Arrays.asList( values ) );
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++)
+ controls[i].claimRequiredValues( list );
+ for (int i = 0; i < controls.length; i++)
+ controls[i].claimUniqueValue( list );
+ for (int i = 0; i < controls.length; i++)
+ controls[i].claimValue( list );
+ if (!list.isEmpty()) throw
+ new UnusedParameterValueException( _name, (String) list.get(0) );
+ }
+
+
+ public void toggleCheckbox() {
+ FormControl[] controls = getControls();
+ if (controls.length != 1) throw new IllegalCheckboxParameterException( _name, "toggleCheckbox" );
+ controls[0].toggle();
+ }
+
+
+ public void toggleCheckbox( String value ) {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ FormControl control = controls[i];
+ if (value.equals( control.getValueAttribute())) {
+ control.toggle();
+ return;
+ }
+ }
+ throw new IllegalCheckboxParameterException( _name + "/" + value , "toggleCheckbox" );
+ }
+
+
+ public void setValue( boolean state ) {
+ FormControl[] controls = getControls();
+ if (controls.length != 1) throw new IllegalCheckboxParameterException( _name, "setCheckbox" );
+ controls[0].setState( state );
+ }
+
+
+ public void setValue( String value, boolean state ) {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ FormControl control = controls[i];
+ if (value.equals( control.getValueAttribute())) {
+ control.setState( state );
+ return;
+ }
+ }
+ throw new IllegalCheckboxParameterException( _name + "/" + value , "setCheckbox" );
+ }
+
+
+ void setFiles( UploadFileSpec[] fileArray ) {
+ ArrayList list = new ArrayList( fileArray.length );
+ list.addAll( Arrays.asList( fileArray ) );
+ for (int i = 0; i < getControls().length; i++) getControls()[i].claimUploadSpecification( list );
+ if (!list.isEmpty()) throw new UnusedUploadFileException( _name, fileArray.length - list.size(), fileArray.length );
+ }
+
+
+ String[] getOptions() {
+ ArrayList optionList = new ArrayList();
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ optionList.addAll( Arrays.asList( controls[i].getDisplayedOptions() ) );
+ }
+ return (String[]) optionList.toArray( new String[ optionList.size() ] );
+ }
+
+
+ String[] getOptionValues() {
+ ArrayList valueList = new ArrayList();
+ for (int i = 0; i < getControls().length; i++) {
+ valueList.addAll( Arrays.asList( getControls()[i].getOptionValues() ) );
+ }
+ return (String[]) valueList.toArray( new String[ valueList.size() ] );
+ }
+
+
+ boolean isMultiValuedParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].isMultiValued()) return true;
+ if (!controls[i].isExclusive() && controls.length > 1) return true;
+ }
+ return false;
+ }
+
+
+ int getNumTextParameters() {
+ int result = 0;
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].isTextControl()) result++;
+ }
+ return result;
+ }
+
+
+ boolean isTextParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].isTextControl()) return true;
+ }
+ return false;
+ }
+
+
+ boolean isFileParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].isFileParameter()) return true;
+ }
+ return false;
+ }
+
+
+ boolean isDisabledParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (!controls[i].isDisabled()) return false;
+ }
+ return true;
+ }
+
+
+ boolean isReadOnlyParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (!controls[i].isReadOnly()) return false;
+ }
+ return true;
+ }
+
+
+ public boolean isHiddenParameter() {
+ FormControl[] controls = getControls();
+ for (int i = 0; i < controls.length; i++) {
+ if (!controls[i].isHidden()) return false;
+ }
+ return true;
+ }
+
+
+ private RadioGroupFormControl getRadioGroup( WebForm form ) {
+ if (_group == null) {
+ _group = new RadioGroupFormControl( form );
+ _controlList.add( _group );
+ }
+ return _group;
+ }
+
+
+//============================= exception class UnusedParameterValueException ======================================
+
+
+ /**
+ * This exception is thrown on an attempt to set a parameter to a value not permitted to it by the form.
+ **/
+ public class UnusedParameterValueException extends IllegalRequestParameterException {
+
+
+ /**
+ * construct an exception for an unused parameter with the given name
+ * and the value that is bad
+ * @param parameterName
+ * @param badValue
+ */
+ UnusedParameterValueException( String parameterName, String badValue ) {
+ _parameterName = parameterName;
+ _badValue = badValue;
+ }
+
+
+ /**
+ * get the message for this exception
+ * @return the message
+ */
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
+ sb.append( "Attempted to assign to parameter '" ).append( _parameterName );
+ sb.append( "' the extraneous value '" ).append( _badValue ).append( "'." );
+ return sb.toString();
+ }
+
+
+ private String _parameterName;
+ private String _badValue;
+ }
+
+
+//============================= exception class UnusedUploadFileException ======================================
+
+
+ /**
+ * This exception is thrown on an attempt to upload more files than permitted by the form.
+ **/
+ class UnusedUploadFileException extends IllegalRequestParameterException {
+
+
+ /**
+ * construct a new UnusedUploadFileException exception base on the parameter Name the number of files expected and supplied
+ * @param parameterName
+ * @param numFilesExpected
+ * @param numFilesSupplied
+ */
+ UnusedUploadFileException( String parameterName, int numFilesExpected, int numFilesSupplied ) {
+ _parameterName = parameterName;
+ _numExpected = numFilesExpected;
+ _numSupplied = numFilesSupplied;
+ }
+
+
+ /**
+ * get the message for this exception
+ */
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer( HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE );
+ sb.append( "Attempted to upload " ).append( _numSupplied ).append( " files using parameter '" ).append( _parameterName );
+ if (_numExpected == 0) {
+ sb.append( "' which is not a file parameter." );
+ } else {
+ sb.append( "' which only has room for " ).append( _numExpected ).append( '.' );
+ }
+ return sb.toString();
+ }
+
+
+ private String _parameterName;
+ private int _numExpected;
+ private int _numSupplied;
+ }
+
+
+//============================= exception class IllegalCheckboxParameterException ======================================
+
+
+ /**
+ * This exception is thrown on an attempt to set a parameter to a value not permitted to it by the form.
+ **/
+ static class IllegalCheckboxParameterException extends IllegalRequestParameterException {
+
+
+ IllegalCheckboxParameterException( String parameterName, String methodName ) {
+ _parameterName = parameterName;
+ _methodName = methodName;
+ }
+
+
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
+ sb.append( "Attempted to invoke method '" ).append( _methodName );
+ sb.append( "' for parameter '" ).append( _parameterName ).append( "', which is not a unique checkbox control." );
+ return sb.toString();
+ }
+
+
+ private String _parameterName;
+ private String _methodName;
+ }
+
+
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/FrameHolder.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/FrameHolder.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/FrameHolder.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,222 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.*;
+
+import org.xml.sax.SAXException;
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+class FrameHolder {
+
+ /** Map from a frame selector to its corresponding web response. **/
+ private Hashtable _contents = new Hashtable();
+
+ /** Map from a frame selector to its subframe selectors. **/
+ private Hashtable _subframes = new Hashtable();
+
+ /** The window which owns this frame holder. **/
+ private WebWindow _window;
+
+ /** The topmost frame in this frameholder. **/
+ private FrameSelector _topFrame;
+
+
+ FrameHolder( WebWindow window ) {
+ _window = window;
+ _topFrame = FrameSelector.newTopFrame( window );
+ DefaultWebResponse blankResponse = new DefaultWebResponse( window.getClient(), null, WebResponse.BLANK_HTML );
+ _contents.put( _topFrame, blankResponse );
+ HttpUnitOptions.getScriptingEngine().associate( blankResponse );
+ }
+
+
+ FrameSelector getTopFrame() {
+ return _topFrame;
+ }
+
+
+ WebResponse getFrameContents( FrameSelector targetFrame ) {
+ if (targetFrame == FrameSelector.TOP_FRAME) targetFrame = getTopFrame();
+ WebResponse response = get( targetFrame );
+ if (response == null) throw new NoSuchFrameException( targetFrame.getName() );
+ return response;
+ }
+
+
+ WebResponse getSubframeContents( FrameSelector frame, String subFrameName ) {
+ FrameSelector[] subframes = (FrameSelector[]) _subframes.get( frame );
+ if (subframes == null) throw new NoSuchFrameException( subFrameName );
+
+ for (int i = 0; i < subframes.length; i++) {
+ FrameSelector subframe = subframes[i];
+ if (subframe.getName().equalsIgnoreCase( subFrameName ) ) return get( subframe );
+ }
+ throw new NoSuchFrameException( subFrameName );
+ }
+
+
+ WebResponse getParentFrameContents( FrameSelector frame ) {
+ return get( frame.getParent() == null ? _topFrame : frame.getParent() );
+ }
+
+
+ WebResponse get( FrameSelector targetFrame ) {
+ return (WebResponse) _contents.get( targetFrame );
+ }
+
+
+ WebResponse get( String target ) {
+ FrameSelector frame = getFrame( _topFrame, target );
+ return frame == null ? null : (WebResponse) _contents.get( frame );
+ }
+
+
+ FrameSelector getFrame( String target ) {
+ return target.equals( _window.getName() ) ? _topFrame : getFrame( _topFrame, target );
+ }
+
+
+ private FrameSelector getFrame( FrameSelector rootFrame, String target ) {
+ if (target.equalsIgnoreCase( WebRequest.TOP_FRAME )) return _topFrame;
+ if (target.equalsIgnoreCase( rootFrame.getName() )) return rootFrame;
+
+ return lookupFrame( rootFrame, target );
+ }
+
+
+ private FrameSelector lookupFrame( FrameSelector rootFrame, String target ) {
+ FrameSelector result = getFromSubframe( rootFrame, target );
+ if (result != null) {
+ return result;
+ } else if (rootFrame.getName().equals( target )) {
+ return rootFrame;
+ } else if (rootFrame.getParent() != null) {
+ return lookupFrame( rootFrame.getParent(), target );
+ } else {
+ return null;
+ }
+ }
+
+
+ private FrameSelector getFromSubframe( FrameSelector rootFrame, String target ) {
+ FrameSelector[] subframes = (FrameSelector[]) _subframes.get( rootFrame );
+ if (subframes == null) return null;
+
+ for (int i = 0; i < subframes.length; i++) {
+ if (subframes[i].getName().equalsIgnoreCase( target )) return subframes[i];
+ }
+ for (int i = 0; i < subframes.length; i++) {
+ FrameSelector result = getFromSubframe( subframes[i], target );
+ if (result != null) return result;
+ }
+ return null;
+ }
+
+
+ List getActiveFrameNames() {
+ List result = new ArrayList();
+ for (Enumeration e = _contents.keys(); e.hasMoreElements();) {
+ result.add( ((FrameSelector) e.nextElement()).getName() );
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Determines the frame in which the reply to a request will be stored.
+ */
+ FrameSelector getTargetFrame( WebRequest request ) {
+ if (WebRequest.NEW_WINDOW.equalsIgnoreCase( request.getTarget() )) {
+ return FrameSelector.NEW_FRAME;
+ } else if (WebRequest.TOP_FRAME.equalsIgnoreCase( request.getTarget() )) {
+ return _topFrame;
+ } else if (WebRequest.SAME_FRAME.equalsIgnoreCase( request.getTarget() )) {
+ return request.getSourceFrame();
+ } else if (WebRequest.PARENT_FRAME.equalsIgnoreCase( request.getTarget() )) {
+ return request.getSourceFrame().getParent() == null ? _topFrame : request.getSourceFrame().getParent();
+ } else if (request.getSourceFrame().getName().equalsIgnoreCase( request.getTarget() )) {
+ return request.getSourceFrame();
+ } else {
+ FrameSelector targetFrame = getFrame( request.getSourceFrame(), request.getTarget() );
+ if (targetFrame == null) targetFrame =_window.getClient().findFrame( request.getTarget() );
+ return (targetFrame != null) ? targetFrame : FrameSelector.NEW_FRAME;
+ }
+ }
+
+
+ void updateFrames( WebResponse response, FrameSelector frame, RequestContext requestContext ) throws MalformedURLException, IOException, SAXException {
+ removeSubFrames( frame );
+ _contents.put( frame, response );
+
+ if (response.isHTML()) {
+ HttpUnitOptions.getScriptingEngine().associate( response );
+ requestContext.addNewResponse( response );
+ WebRequest[] requests = response.getFrameRequests();
+ if (requests.length > 0) {
+ createSubFrames( frame, response.getFrameSelectors() );
+ for (int i = 0; i < requests.length; i++) {
+ if (requests[i].getURLString().length() != 0) {
+ response.getWindow().getSubframeResponse( requests[i], requestContext );
+ }
+ }
+ }
+ }
+ }
+
+
+ private void removeSubFrames( FrameSelector frame ) {
+ FrameSelector[] subframes = (FrameSelector[]) _subframes.get( frame );
+ if (subframes == null) return;
+
+ _subframes.remove( frame );
+ for (int i = 0; i < subframes.length; i++) {
+ removeSubFrames( subframes[ i ] );
+ _contents.remove( subframes[ i ] );
+ }
+ }
+
+
+ private void createSubFrames( FrameSelector frame, FrameSelector[] subframes ) {
+ _subframes.put( frame, subframes );
+ for (int i = 0; i < subframes.length; i++) {
+ _contents.put( subframes[ i ], WebResponse.createBlankResponse() );
+ }
+ }
+
+
+ /**
+ * Given the qualified name of a frame and the name of a nested frame, returns the qualified name of the nested frame.
+ */
+ static FrameSelector newNestedFrame( FrameSelector parentFrame, final String relativeName ) {
+ if (relativeName == null || relativeName.length() == 0) return new FrameSelector();
+ return new FrameSelector( relativeName, parentFrame );
+ }
+
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/FrameSelector.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/FrameSelector.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/FrameSelector.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,95 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * An immutable class which describes the position of a frame in the window hierarchy.
+ *
+ * @author Russell Gold
+ *
+ * @since 1.6
+ **/
+public class FrameSelector {
+
+ public static FrameSelector TOP_FRAME = new FrameSelector( WebRequest.TOP_FRAME );
+ static FrameSelector NEW_FRAME = new FrameSelector( WebRequest.TOP_FRAME );
+
+ private String _name;
+ private WebWindow _window;
+ private FrameSelector _parent;
+
+
+ FrameSelector() {
+ _name = super.toString();
+ }
+
+
+ FrameSelector( String name ) {
+ _name = name;
+ }
+
+
+ FrameSelector( String name, FrameSelector parent ) {
+ _name = name;
+ _parent = parent;
+ }
+
+
+ String getName() {
+ return _name;
+ }
+
+
+ FrameSelector getParent() {
+ return _parent;
+ }
+
+
+ public String toString() {
+ return "Frame Selector: [ " + getFullName() + " ]";
+ }
+
+
+ private String getFullName() {
+ return _name + (_parent == null ? "" : " in " + _parent.getFullName() );
+ }
+
+
+ WebWindow getWindow() {
+ return _window != null ? _window
+ : (_parent == null ? null : _parent.getWindow());
+ }
+
+
+ static FrameSelector newTopFrame( WebWindow window ) {
+ return new FrameSelector( WebRequest.TOP_FRAME, window );
+ }
+
+
+ private FrameSelector( String name, WebWindow window ) {
+ _name = name;
+ _window = window;
+ }
+
+
+}
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/GetMethodWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/GetMethodWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/GetMethodWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,119 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2002, 2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import org.w3c.dom.Element;
+
+import java.net.URL;
+
+/**
+ * An HTTP request using the GET method.
+ **/
+public class GetMethodWebRequest extends HeaderOnlyWebRequest {
+
+
+ /**
+ * Constructs a web request using a specific absolute url string.
+ **/
+ public GetMethodWebRequest( String urlString ) {
+ super( urlString );
+ }
+
+
+ /**
+ * Constructs a web request using a base URL and a relative url string.
+ **/
+ public GetMethodWebRequest( URL urlBase, String urlString ) {
+ super( urlBase, urlString );
+ }
+
+
+ /**
+ * Constructs a web request with a specific target.
+ **/
+ public GetMethodWebRequest( URL urlBase, String urlString, String target ) {
+ super( urlBase, urlString, target );
+ }
+
+
+ /**
+ * Returns the HTTP method defined for this request.
+ **/
+ public String getMethod() {
+ return "GET";
+ }
+
+
+//--------------------------------------- package members ---------------------------------------------
+
+
+ /**
+ * Constructs a web request for a form submitted from JavaScript.
+ **/
+ GetMethodWebRequest( WebForm sourceForm ) {
+ super( sourceForm );
+ }
+
+
+ /**
+ * Constructs a web request for a link or image.
+ **/
+ GetMethodWebRequest( FixedURLWebRequestSource source ) {
+ super( source );
+ }
+
+
+ /**
+ * Constructs a web request with a specific target.
+ **/
+ GetMethodWebRequest( WebResponse referer, Element sourceElement, URL urlBase, String urlString, String target ) {
+ super( referer, sourceElement, urlBase, urlString, target );
+ }
+
+
+ /**
+ * Constructs an initial web request for a frame.
+ **/
+ GetMethodWebRequest( URL urlBase, String urlString, FrameSelector frame ) {
+ super( urlBase, urlString, frame );
+ }
+
+
+ /**
+ * Constructs a web request for a javascript open call.
+ **/
+ GetMethodWebRequest( URL urlBase, String urlString, FrameSelector frame, String target ) {
+ super( urlBase, urlString, frame, target );
+ }
+
+
+ /**
+ * Constructs a web request for a form.
+ **/
+ GetMethodWebRequest( WebForm sourceForm, ParameterHolder parameterHolder, SubmitButton button, int x, int y ) {
+ super( sourceForm, parameterHolder, button, x, y );
+ }
+
+
+}
+
+
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElement.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElement.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElement.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,125 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptingEventHandler;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * An interface which defines the common properties for an HTML element, which can correspond to any HTML tag.
+ *
+ * @since 1.5.2
+ * @author Russell Gold
+ **/
+// TODO activate the extends Element as
+// in http://www.w3.org/TR/REC-DOM-Level-1/java-language-binding.html
+//public interface HTMLElement extends Element,ScriptingEventHandler {
+public interface HTMLElement extends ScriptingEventHandler {
+
+ /**
+ * Returns the ID associated with this element. IDs are unique throughout the HTML document.
+ **/
+ String getID();
+
+
+ /**
+ * Returns the class associated with this element.
+ **/
+ String getClassName();
+
+
+ /**
+ * Returns the name associated with this element.
+ **/
+ String getName();
+
+
+ /**
+ * Returns the title associated with this element.
+ **/
+ String getTitle();
+
+
+ /**
+ * Returns the value of the attribute of this element with the specified name.
+ * Returns the empty string if no such attribute exists.
+ *
+ * @since 1.6
+ */
+ String getAttribute( String name );
+
+ /**
+ * Set the value of the attribute of this element with the specified name.
+ * @since 1.7
+ */
+ void setAttribute( String name, Object value );
+
+ /**
+ * Remove the attribute of this element with the specified name.
+ * @since 1.7
+ */
+ void removeAttribute( String name );
+
+ /**
+ * Returns true if this element may have an attribute with the specified name.
+ *
+ * @since 1.6
+ */
+ boolean isSupportedAttribute( String name );
+
+
+ /**
+ * Returns the delegate which supports scripting this element.
+ */
+ ScriptingHandler getScriptingHandler();
+
+
+ /**
+ * Returns the contents of this element, converted to a string.
+ *
+ * @since 1.6
+ */
+ String getText();
+
+
+ /**
+ * Returns the tag name of this node.
+ *
+ * @since 1.6.1
+ */
+ String getTagName();
+
+
+ ScriptableDelegate newScriptable();
+
+ /**
+ * Returns the scriptable delegate which can provide the scriptable delegate for this element.
+ */
+ ScriptableDelegate getParentDelegate();
+
+ /**
+ * Returns the DOM node underlying this element.
+ */
+ Node getNode();
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementBase.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementBase.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementBase.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,188 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.w3c.dom.Node;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+
+
+/**
+ *
+ * @since 1.5.2
+ * @author Russell Gold
+ **/
+abstract
+class HTMLElementBase implements HTMLElement {
+
+ private Node _node;
+ private ScriptingHandler _scriptable;
+ private Set _supportedAttributes = new HashSet();
+
+
+ public String getID() {
+ return getAttribute( "id" );
+ }
+
+
+ public String getClassName() {
+ return getAttribute( "class" );
+ }
+
+
+ public String getTitle() {
+ return getAttribute( "title" );
+ }
+
+
+ public String getName() {
+ return getAttribute( "name" );
+ }
+
+
+ /**
+ * Returns a scriptable object which can act as a proxy for this control.
+ */
+ public ScriptingHandler getScriptingHandler() {
+ if (_scriptable == null) {
+ _scriptable = HttpUnitOptions.getScriptingEngine().createHandler( this );
+ }
+ return _scriptable;
+ }
+
+ /**
+ * handle the event that has the given script attached
+ * by compiling the eventScript as a function and executing it
+ * @param eventScript - the script to use
+ * @deprecated since 1.7 - use doEventScript instead
+ */
+ public boolean doEvent( String eventScript ) {
+ return doEventScript(eventScript);
+ }
+
+ /**
+ * optional do the event if it's defined
+ */
+ public boolean doEventScript(String eventScript) {
+ return this.getScriptingHandler().doEventScript(eventScript);
+ }
+
+
+ public boolean handleEvent(String eventName) {
+ return this.getScriptingHandler().handleEvent(eventName);
+ }
+
+
+ /**
+ * Returns the text value of this block.
+ **/
+ public String getText() {
+ if (_node.getNodeType() == Node.TEXT_NODE) {
+ return _node.getNodeValue().trim();
+ } else if (_node == null || !_node.hasChildNodes()) {
+ return "";
+ } else {
+ return NodeUtils.asText( _node.getChildNodes() ).trim();
+ }
+ }
+
+
+ public String getTagName() {
+ return _node.getNodeName();
+ }
+
+
+ /**
+ * construct me from a node
+ * @param node - the node to get me from
+ */
+ protected HTMLElementBase( Node node ) {
+ _node = node;
+ // default attributes every html element can have
+ supportAttribute( "id" );
+ supportAttribute( "class" );
+ supportAttribute( "title" );
+ supportAttribute( "name" );
+ }
+
+
+ /**
+ * get the Attribute with the given name - by delegating to
+ * NodeUtils
+ * @param name - the name of the attribute to get
+ * @return the attribute
+ */
+ public String getAttribute( final String name ) {
+ return NodeUtils.getNodeAttribute( getNode(), name );
+ }
+
+ /**
+ * set the Attribute with the given name - by delegating to NodeUtils
+ * @param name - the name of the attribute to set
+ * @param value - the value to set
+ */
+ public void setAttribute( final String name, final Object value ) {
+ NodeUtils.setNodeAttribute( getNode(), name, (value == null) ? null : value.toString() );
+ }
+
+ /**
+ * remove the Attribute with the given name - by delegating to NodeUtils
+ * @param name - the name of the attribute to remove
+ */
+ public void removeAttribute( final String name ) {
+ NodeUtils.removeNodeAttribute( getNode(), name );
+ }
+
+
+ public boolean isSupportedAttribute( String name ) {
+ return _supportedAttributes.contains( name );
+ }
+
+
+ protected String getAttribute( final String name, String defaultValue ) {
+ return NodeUtils.getNodeAttribute( getNode(), name, defaultValue );
+ }
+
+
+ public Node getNode() {
+ return _node;
+ }
+
+
+ protected void supportAttribute( String name ) {
+ _supportedAttributes.add( name );
+ }
+
+
+ /**
+ * Creates and returns a scriptable object for this control. Subclasses should override this if they use a different
+ * implementation of Scriptable.
+ */
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementPredicate.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementPredicate.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementPredicate.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,34 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+
+/**
+ * An interface which can be used to define matching criteria for an HTML element. It can be passed to methods such
+ * as WebRequest.getMatchingLink to define arbitrary matching criteria for web links.
+ *
+ * @author Russell Gold
+ **/
+public interface HTMLElementPredicate {
+
+ public boolean matchesCriteria( Object htmlElement, Object criteria );
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementScriptable.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementScriptable.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLElementScriptable.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,109 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.DocumentElement;
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+class HTMLElementScriptable extends ScriptableDelegate implements DocumentElement {
+
+ /**
+ * the element that I am scripting for
+ */
+ private HTMLElement _element;
+
+
+ /**
+ * @return the _element
+ */
+ protected HTMLElement get_element() {
+ return _element;
+ }
+
+ /**
+ * get the property with the given name
+ * @param propertyName - the name of the property to get
+ */
+ public Object get( String propertyName ) {
+ if (propertyName.equals( "nodeName" )) {
+ return _element.getTagName();
+ } else if (propertyName.equals( "tagName" )) {
+ return _element.getTagName();
+ } else if (propertyName.equalsIgnoreCase( "title" )) {
+ return _element.getTitle();
+ } else if (_element.isSupportedAttribute( propertyName )) {
+ return _element.getAttribute( propertyName );
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+ /**
+ * get the content of the given attribute
+ * @param attributeName
+ * @return the attribute as a string
+ */
+ public String getAttribute(String attributeName) {
+ return _element.getAttribute(attributeName);
+ }
+
+ /**
+ * set the attribute with the given attribute name to the given value
+ * @param attributeName
+ * @param value
+ */
+ public void setAttribute( String attributeName, Object value ) {
+ _element.setAttribute( attributeName, value );
+ }
+
+ /**
+ * remove the given attribute
+ * @param attributeName
+ */
+ public void removeAttribute( String attributeName ) {
+ _element.removeAttribute( attributeName );
+ }
+
+ public boolean handleEvent(String eventName) {
+ // check whether onclick is activated
+ if (eventName.toLowerCase().equals( "onclick" )) {
+ handleEvent( "onmousedown" );
+ }
+ String eventScript = getAttribute( eventName );
+ boolean result = doEventScript( eventScript );
+ if (eventName.toLowerCase().equals( "onclick" )) {
+ handleEvent( "onmouseup" );
+ }
+ return result;
+ }
+
+ /**
+ * construct me from a given element
+ * @param element
+ */
+ public HTMLElementScriptable( HTMLElement element ) {
+ _element = element;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLPage.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLPage.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLPage.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,279 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2007, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.NamedDelegate;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+import com.meterware.httpunit.parsing.HTMLParserFactory;
+import com.meterware.httpunit.parsing.DocumentAdapter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.html.HTMLDocument;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Vector;
+
+
+/**
+ * This class represents an HTML page returned from a request.
+ *
+ * @author Russell Gold
+ * @author Benoit Xhenseval
+ **/
+public class HTMLPage extends ParsedHTML {
+
+ private Scriptable _scriptable;
+
+
+ HTMLPage( WebResponse response, FrameSelector frame, URL baseURL, String baseTarget, String characterSet ) {
+ super( response, frame, baseURL, baseTarget, null, characterSet );
+ }
+
+
+ /**
+ * Returns the title of the page.
+ **/
+ public String getTitle() throws SAXException {
+ NodeList nl = ((Document) getOriginalDOM()).getElementsByTagName( "title" );
+ if (nl.getLength() == 0) return "";
+ if (!nl.item(0).hasChildNodes()) return "";
+ return nl.item(0).getFirstChild().getNodeValue();
+ }
+
+
+ /**
+ * Returns the onLoad event script.
+ */
+ public String getOnLoadEvent() throws SAXException {
+ Element mainElement = getMainElement( ((Document) getOriginalDOM()) );
+ return mainElement == null ? "" : mainElement.getAttribute( "onload" );
+ }
+
+
+ private Element getMainElement( Document document ) {
+ NodeList nl = document.getElementsByTagName( "frameset" );
+ if (nl.getLength() == 0) nl = document.getElementsByTagName( "body" );
+ return nl.getLength() == 0 ? null : ((Element) nl.item(0));
+ }
+
+
+ /**
+ * Returns the location of the linked stylesheet in the head
+ *
+ *
+ *
+ **/
+ public String getExternalStyleSheet() throws SAXException {
+ NodeList nl = ((Document) getOriginalDOM()).getElementsByTagName( "link" );
+ int length = nl.getLength();
+ if (length == 0) return "";
+
+ for (int i = 0; i < length; i++) {
+ if ("stylesheet".equalsIgnoreCase(NodeUtils.getNodeAttribute( nl.item(i), "rel" )))
+ return NodeUtils.getNodeAttribute( nl.item(i), "href" );
+ }
+ return "";
+ }
+
+
+ /**
+ * Retrieves the "content" of the meta tags for a key pair attribute-attributeValue.
+ *
+ *
+ *
+ *
+ *
+ * this can be used like this
+ *
+ * getMetaTagContent("name","robots") will return { "index","follow" }
+ * getMetaTagContent("http-equiv","Expires") will return { "now" }
+ *
+ **/
+ public String[] getMetaTagContent(String attribute, String attributeValue) {
+ Vector matches = new Vector();
+ NodeList nl = ((Document) getOriginalDOM()).getElementsByTagName("meta");
+ int length = nl.getLength();
+
+ for (int i = 0; i < length; i++) {
+ if (attributeValue.equalsIgnoreCase(NodeUtils.getNodeAttribute(nl.item(i), attribute))) {
+ matches.addElement( NodeUtils.getNodeAttribute( nl.item(i), "content" ) );
+ }
+ }
+ String[] result = new String[ matches.size() ];
+ matches.copyInto( result );
+ return result;
+ }
+
+ /**
+ * scriptable for HTML Page
+ */
+
+ public class Scriptable extends ScriptableDelegate {
+
+ /**
+ * get the Object with the given propertyName
+ * @param propertyName - the name of the property
+ */
+ public Object get( String propertyName ) {
+ NamedDelegate delegate = getNamedItem( getForms(), propertyName );
+ if (delegate != null) return delegate;
+
+ delegate = getNamedItem( getLinks(), propertyName );
+ if (delegate != null) return delegate;
+
+ delegate = getNamedItem( getImages(), propertyName );
+ if (delegate != null) return delegate;
+
+ return null;
+ }
+
+
+ private NamedDelegate getNamedItem( ScriptingHandler[] items, String name ) {
+ if (name == null) return null;
+ for (int i = 0; i < items.length; i++) {
+ if (items[i] instanceof NamedDelegate && name.equals( ((NamedDelegate) items[i]).getName() )) return (NamedDelegate) items[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Sets the value of the named property. Will throw a runtime exception if the property does not exist or
+ * cannot accept the specified value.
+ **/
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equalsIgnoreCase( "location" )) {
+ getResponse().getScriptableObject().set( "location", value );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+
+
+ public WebResponse.Scriptable getParent() {
+ return getResponse().getScriptableObject();
+ }
+
+
+ public String getTitle() throws SAXException {
+ return HTMLPage.this.getTitle();
+ }
+
+
+ public ScriptingHandler[] getLinks() {
+ WebLink[] links = HTMLPage.this.getLinks();
+ ScriptingHandler[] result = new WebLink.Scriptable[ links.length ];
+ for (int i = 0; i < links.length; i++) {
+ result[i] = links[i].getScriptingHandler();
+ }
+ return result;
+ }
+
+
+ public ScriptingHandler[] getForms() {
+ WebForm[] forms = HTMLPage.this.getForms();
+ ScriptingHandler[] result = new ScriptingHandler[ forms.length ];
+ for (int i = 0; i < forms.length; i++) {
+ result[i] = forms[i].getScriptingHandler();
+ }
+ return result;
+ }
+
+
+ public ScriptingHandler[] getImages() {
+ WebImage[] images = HTMLPage.this.getImages();
+ ScriptingHandler[] result = new WebImage.Scriptable[ images.length ];
+ for (int i = 0; i < images.length; i++) {
+ result[i] = images[i].getScriptingHandler();
+ }
+ return result;
+ }
+
+
+ Scriptable() {}
+
+
+ public boolean replaceText( String text, String contentType ) {
+ return getResponse().replaceText( text, contentType );
+ }
+
+
+ public void setCookie( String name, String value ) {
+ getResponse().setCookie( name, value );
+ }
+
+
+ public String getCookie() {
+ return emptyIfNull( getResponse().getCookieHeader() );
+ }
+
+
+ private String emptyIfNull( String string ) {
+ return string == null ? "" : string;
+ }
+
+
+ public ScriptableDelegate getElementWithID( String id ) {
+ final HTMLElement elementWithID = HTMLPage.this.getElementWithID( id );
+ return elementWithID == null ? null : (ScriptableDelegate) elementWithID.getScriptingHandler();
+ }
+
+
+ public ScriptableDelegate[] getElementsByName( String name ) {
+ return getDelegates( HTMLPage.this.getElementsWithName( name ) );
+ }
+
+
+ public ScriptableDelegate[] getElementsByTagName( String name ) {
+ return getDelegates( HTMLPage.this.getElementsByTagName( HTMLPage.this.getRootNode(), name ) );
+ }
+ }
+
+
+ Scriptable getScriptableObject() {
+ if (_scriptable == null) {
+ _scriptable = new Scriptable();
+ _scriptable.setScriptEngine( getResponse().getScriptableObject().getScriptEngine( _scriptable ) );
+ }
+ return _scriptable;
+ }
+
+
+ /**
+ * parse the given test with the given URL
+ * @param text
+ * @param pageURL
+ * @throws SAXException
+ * @throws IOException
+ */
+ public void parse( String text, URL pageURL ) throws SAXException, IOException {
+ HTMLParserFactory.getHTMLParser().parse( pageURL, text, new DocumentAdapter() {
+ public void setDocument(HTMLDocument document ) { HTMLPage.this.setRootNode( document ); }
+ public String getIncludedScript( String srcAttribute ) throws IOException { return HTMLPage.this.getIncludedScript( srcAttribute ); }
+ public ScriptingHandler getScriptingHandler() { return getResponse().getScriptingHandler(); }
+ });
+ }
+
+
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLSegment.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLSegment.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HTMLSegment.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,232 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import org.xml.sax.SAXException;
+
+/**
+ * Represents the parse tree for a segment of HTML.
+ *
+ * @author Russell Gold
+ **/
+public interface HTMLSegment {
+
+
+ /**
+ * Returns the HTMLElement found in this segment with the specified ID.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ */
+ public HTMLElement getElementWithID( String id ) throws SAXException;
+
+
+ /**
+ * Returns the HTMLElements found in this segment with the specified name.
+ */
+ public HTMLElement[] getElementsWithName( String name ) throws SAXException;
+
+
+ /**
+ * Returns the HTMLElements found with the specified attribute value.
+ *
+ * @since 1.6
+ */
+ public HTMLElement[] getElementsWithAttribute( String name, String value ) throws SAXException;
+
+
+ /**
+ * Returns a list of HTML element names contained in this HTML section.
+ */
+ public String[] getElementNames() throws SAXException;
+
+
+ /**
+ * Returns the forms found in this HTML segment in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebForm[] getForms() throws SAXException;
+
+
+ /**
+ * Returns the form found in this HTML segment with the specified ID.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebForm getFormWithID( String ID ) throws SAXException;
+
+
+ /**
+ * Returns the form found in this HTML segment with the specified name.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebForm getFormWithName( String name ) throws SAXException;
+
+
+ /**
+ * Returns the first form found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm getFirstMatchingForm( HTMLElementPredicate predicate, Object value ) throws SAXException;
+
+
+ /**
+ * Returns all forms found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm[] getMatchingForms( HTMLElementPredicate predicate, Object criteria ) throws SAXException;
+
+
+ /**
+ * Returns the links found in this HTML segment in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebLink[] getLinks() throws SAXException;
+
+
+ /**
+ * Returns the first link which contains the specified text.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebLink getLinkWith( String text ) throws SAXException;
+
+
+ /**
+ * Returns the first link which contains an image with the specified text as its 'alt' attribute.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebLink getLinkWithImageText( String text ) throws SAXException;
+
+
+ /**
+ * Returns the first link found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getFirstMatchingLink( HTMLElementPredicate predicate, Object value ) throws SAXException;
+
+
+ /**
+ * Returns all links found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink[] getMatchingLinks( HTMLElementPredicate predicate, Object criteria ) throws SAXException;
+
+
+ /**
+ * Returns the images found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebImage[] getImages() throws SAXException;
+
+
+ /**
+ * Returns the image found in the page with the specified name.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebImage getImageWithName( String name ) throws SAXException;
+
+
+ /**
+ * Returns the first image found in the page with the specified src attribute.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebImage getImageWithSource( String source ) throws SAXException;
+
+
+ /**
+ * Returns the first image found in the page with the specified alt attribute.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebImage getImageWithAltText( String source ) throws SAXException;
+
+
+ /**
+ * Returns the applets found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebApplet[] getApplets() throws SAXException;
+
+
+ /**
+ * Returns the top-level block elements found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ *
+ * @since 1.6
+ */
+ public TextBlock[] getTextBlocks() throws SAXException;
+
+
+ /**
+ * Returns the top-level tables found in this HTML segment in the order in which
+ * they appear.
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebTable[] getTables() throws SAXException;
+
+
+ /**
+ * Returns the first table in the response which matches the specified predicate and value.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getFirstMatchingTable( HTMLElementPredicate predicate, Object criteria ) throws SAXException;
+
+
+ /**
+ * Returns all tables found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebTable[] getMatchingTables( HTMLElementPredicate predicate, Object criteria ) throws SAXException;
+
+
+ /**
+ * Returns the first table in this HTML segment which has the specified text as the full text of
+ * its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebTable getTableStartingWith( final String text ) throws SAXException;
+
+
+ /**
+ * Returns the first table in this HTML segment which has the specified text as a prefix of the text
+ * in its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebTable getTableStartingWithPrefix( String text ) throws SAXException;
+
+
+ /**
+ * Returns the first table in this HTML segment which has the specified text as its summary attribute.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebTable getTableWithSummary( String summary ) throws SAXException;
+
+
+ /**
+ * Returns the first table in this HTML segment which has the specified text as its ID attribute.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ * @exception SAXException thrown if there is an error parsing the segment.
+ **/
+ public WebTable getTableWithID( final String ID ) throws SAXException;
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HeadMethodWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HeadMethodWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HeadMethodWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,54 @@
+package com.meterware.httpunit;
+
+import java.net.URL;
+
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * A web request using the HEAD method. This request is used to obtain header information for a resource
+ * without necessarily waiting for the data to be computed or transmitted.
+ *
+ * @author Russell Gold
+ **/
+public class HeadMethodWebRequest extends HeaderOnlyWebRequest {
+
+ /**
+ * Creates a new head request from a complete URL string.
+ * @param urlString the URL desired, including the protocol.
+ */
+ public HeadMethodWebRequest( String urlString ) {
+ super( urlString );
+ this.setMethod("HEAD");
+ }
+
+
+ /**
+ * Creates a new head request using a relative URL and base.
+ * @param urlBase the base URL.
+ * @param urlString the relative URL
+ */
+ public HeadMethodWebRequest( URL urlBase, String urlString ) {
+ super( urlBase, urlString );
+ this.setMethod("HEAD");
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HeaderOnlyWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HeaderOnlyWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HeaderOnlyWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,107 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002,2004,2007 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.protocol.URLEncodedString;
+
+import java.net.URL;
+import java.io.IOException;
+
+import org.w3c.dom.Element;
+
+
+/**
+ * A web request which has no information in its message body.
+ *
+ * @author Russell Gold
+ **/
+public class HeaderOnlyWebRequest extends WebRequest {
+
+
+ /**
+ * Returns the query string defined for this request.
+ **/
+ public String getQueryString() {
+ try {
+ URLEncodedString encoder = new URLEncodedString();
+ getParameterHolder().recordPredefinedParameters( encoder );
+ getParameterHolder().recordParameters( encoder );
+ return encoder.getString();
+ } catch (IOException e) {
+ throw new RuntimeException( "Programming error: " + e ); // should never happen
+ }
+ }
+
+ /**
+ * @param method the method to set
+ */
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+
+//-------------------------------- protected members ---------------------------
+
+
+ protected HeaderOnlyWebRequest( URL urlBase, String urlString, FrameSelector frame, String target ) {
+ super( urlBase, urlString, frame, target );
+ }
+
+
+ protected HeaderOnlyWebRequest( URL urlBase, String urlString, String target ) {
+ super( urlBase, urlString, target );
+ }
+
+
+ protected HeaderOnlyWebRequest( WebResponse referer, Element sourceElement, URL urlBase, String urlString, String target ) {
+ super( referer, sourceElement, urlBase, urlString, target );
+ }
+
+
+ protected HeaderOnlyWebRequest( URL urlBase, String urlString ) {
+ super( urlBase, urlString );
+ }
+
+
+ protected HeaderOnlyWebRequest( String urlString ) {
+ super( urlString );
+ }
+
+
+//------------------------------------ package members --------------------------
+
+
+ HeaderOnlyWebRequest( WebRequestSource requestSource ) {
+ super( requestSource, WebRequest.newParameterHolder( requestSource ) );
+ setHeaderField( REFERER_HEADER_NAME, requestSource.getBaseURL().toExternalForm() );
+ }
+
+
+ HeaderOnlyWebRequest( WebForm sourceForm, ParameterHolder parameterHolder, SubmitButton button, int x, int y ) {
+ super( sourceForm, parameterHolder, button, x, y );
+ setHeaderField( REFERER_HEADER_NAME, sourceForm.getBaseURL().toExternalForm() );
+ }
+
+
+ HeaderOnlyWebRequest( URL urlBase, String urlString, FrameSelector frame ) {
+ super( urlBase, urlString, frame, frame.getName() );
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HtmlErrorListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HtmlErrorListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HtmlErrorListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,35 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2002, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.parsing.HTMLParserListener;
+
+/**
+ * This interface represents a listener which can receive notification of errors and warnings during the parsing
+ * of an HTML page.
+ *
+ * @deprecated as of 1.5.2, use HTMLParserListener
+ *
+ * @author Benoit Xhenseval
+ * @author Russell Gold
+ **/
+public interface HtmlErrorListener extends HTMLParserListener {
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,132 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2001, 2008 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.net.URL;
+
+
+/**
+ * This exception is thrown when an Http error (response code 4xx or 5xx) is detected.
+ * @author Seth Ladd
+ * @author Russell Gold
+ **/
+public class HttpException extends RuntimeException {
+
+
+ /**
+ * throw a http Exception with the given responseCode
+ * @param responseCode
+ */
+ protected HttpException( int responseCode ) {
+ _responseCode = responseCode;
+ System.err.println(responseCode);
+ }
+
+ /**
+ * throw a http Exception with the given responseCode and cause
+ * @param responseCode
+ * @param cause
+ */
+ protected HttpException( int responseCode, Throwable cause ) {
+ _responseCode = responseCode;
+ _cause = cause;
+ }
+
+ /**
+ * throw a http Exception with the given responseCode and Message and base url
+ * @param responseCode
+ * @param responseMessage
+ * @param baseURL
+ */
+ protected HttpException( int responseCode, String responseMessage, URL baseURL ) {
+ _responseMessage = responseMessage;
+ _responseCode = responseCode;
+ _url = baseURL;
+ }
+
+ /**
+ * throw a http Exception with the given responseCode and Message, base url and cause
+ * @param responseCode
+ * @param responseMessage
+ * @param baseURL
+ * @param cause
+ */
+ protected HttpException( int responseCode, String responseMessage, URL baseURL, Throwable cause ) {
+ _responseMessage = responseMessage;
+ _responseCode = responseCode;
+ _url = baseURL;
+ _cause = cause;
+ }
+
+ /**
+ * get the Message for the http Exception
+ * @return - the message of the Exception
+ */
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE).append( "Error on HTTP request: " );
+ sb.append( _responseCode );
+ if (_responseMessage != null) {
+ sb.append( " " );
+ sb.append( _responseMessage );
+ sb.append( "" );
+ }
+ if (_url != null) {
+ sb.append( " [" );
+ sb.append( _url.toExternalForm() );
+ sb.append( "]" );
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * get the response Code of this http Exception
+ * @return - the response Code code 4xx or 5xx
+ */
+ public int getResponseCode() {
+ return _responseCode;
+ }
+
+
+ /**
+ * get the response Message of this http Exception
+ * @return the response message
+ */
+ public String getResponseMessage() {
+ return _responseMessage;
+ }
+
+
+ // private local copies of variables
+ private int _responseCode;
+ private URL _url;
+ private String _responseMessage;
+
+ /**
+ * get the cause (if any)
+ */
+ public Throwable getCause() {
+ return _cause;
+ }
+
+
+ private Throwable _cause;
+
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpHeader.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpHeader.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpHeader.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,124 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2006, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.util.*;
+
+/**
+ * @author Russell Gold
+ */
+public class HttpHeader {
+
+ private String _label;
+ private Map _properties;
+
+
+ public HttpHeader( String headerString ) {
+ this( headerString, null );
+ }
+
+
+ public HttpHeader( String headerString, String defaultLabel ) {
+ if (headerString != null) {
+ final int index = headerString.indexOf( ' ' );
+ if (index < 0) { // non-conforming header
+ _label = defaultLabel;
+ _properties = loadProperties( headerString );
+ } else {
+ _label = headerString.substring( 0, index );
+ _properties = loadProperties( headerString.substring( index+1 ) );
+ }
+ }
+ }
+
+
+ public boolean equals( Object obj ) {
+ if (!getClass().equals( obj.getClass() ) ) return false;
+ return getLabel().equals( ((HttpHeader) obj).getLabel() ) &&
+ getProperties().equals( ((HttpHeader) obj).getProperties() );
+ }
+
+
+ public String toString() {
+ return getLabel() + " " + getProperties();
+ }
+
+
+ protected String getProperty( String key ) {
+ return unQuote( (String) getProperties().get( key ) );
+ }
+
+
+ private String unQuote( String value ) {
+ if (value == null || value.length() <= 1 || !value.startsWith( "\"" ) || !value.endsWith( "\"")) return value;
+
+ return value.substring( 1, value.length()-1 );
+ }
+
+
+// Headers have the general format (ignoring unquoted white space):
+// header ::= property-def | property-def ',' header
+// property-def ::= name '=' value
+// name ::= ID
+// value ::= ID | QUOTED-STRING
+//
+ static private Map loadProperties( String parameterString ) {
+ Properties properties = new Properties();
+ char[] chars = parameterString.toCharArray();
+ int i = 0;
+ StringBuffer sb = new StringBuffer();
+
+ while (i < chars.length) {
+ while (i < chars.length && Character.isWhitespace( chars[i] ) ) i++;
+ while (i < chars.length && Character.isJavaIdentifierPart( chars[i] ) ) sb.append( chars[i++] );
+ String name = sb.toString();
+ sb.setLength( 0 );
+ while (i < chars.length && chars[i] != '=' ) i++;
+ if (i == chars.length) break;
+ i++; // skip '='
+ while (i < chars.length && Character.isWhitespace( chars[i] ) ) i++;
+ if (i == chars.length) break;
+ if (chars[i] == '"') {
+ sb.append( chars[i++] );
+ while (i < chars.length && chars[i] != '"' ) sb.append( chars[i++] );
+ sb.append( '"' );
+ if (i < chars.length) i++; // skip close quote
+ } else {
+ while (i < chars.length && Character.isJavaIdentifierPart( chars[i] ) ) sb.append( chars[i++] );
+ }
+ properties.setProperty( name, sb.toString() );
+ sb.setLength( 0 );
+ while (i < chars.length && chars[i] != ',' ) i++;
+ if (i == chars.length) break;
+ i++; // skip '='
+ }
+ return properties;
+ }
+
+
+ public String getLabel() {
+ return _label;
+ }
+
+
+ public Map getProperties() {
+ return _properties;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpInternalErrorException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpInternalErrorException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpInternalErrorException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,52 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2001, 2008 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+
+/**
+ * This exception is thrown when an internal error is found on the server.
+ * @author Seth Ladd
+ * @author Russell Gold
+ **/
+public class HttpInternalErrorException extends HttpException {
+
+
+ /**
+ * construct an internal http error form an url
+ * @param url
+ */
+ public HttpInternalErrorException( URL url ) {
+ super( HttpURLConnection.HTTP_INTERNAL_ERROR, "Internal Error", url );
+ }
+
+
+ /**
+ * construct an internal HTTP Error from a URL and a throwable
+ * @param url
+ * @param t
+ */
+ public HttpInternalErrorException( URL url, Throwable t ) {
+ super( HttpURLConnection.HTTP_INTERNAL_ERROR, t.toString(), url,t );
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpNotFoundException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpNotFoundException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpNotFoundException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,53 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2001,2008 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+
+/**
+ * This exception is thrown when the desired URL is not found.
+ * @author Seth Ladd
+ * @author Russell Gold
+ **/
+public class HttpNotFoundException extends HttpException {
+
+ /**
+ * construct a HttpNotFoundException (404 Error)
+ * @param responseMessage
+ * @param baseURL
+ */
+ public HttpNotFoundException( String responseMessage, URL baseURL ) {
+ super( HttpURLConnection.HTTP_NOT_FOUND, responseMessage, baseURL );
+ }
+
+
+ /**
+ * construct a HttpNotFoundException (404 Error)
+ * @param url
+ * @param t
+ */
+ public HttpNotFoundException( URL url, Throwable t ) {
+ this( t.toString(), url );
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitOptions.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitOptions.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitOptions.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,592 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingEngineFactory;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+import com.meterware.httpunit.parsing.HTMLParserListener;
+import com.meterware.httpunit.parsing.HTMLParserFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+/**
+ * A collection of global options to control HttpUnit's behavior.
+ *
+ * @author Russell Gold
+ * @author Dave Glowacki
+ * @author Benoit Xhenseval
+ **/
+public abstract class HttpUnitOptions {
+ /**
+ * ID for Revision Control System - will show in the class file and
+ * can be looked for using the ident command of RCS
+ */
+ private final static String RCSID="$Id$";
+
+
+ public static final String ORIGINAL_SCRIPTING_ENGINE_FACTORY = "com.meterware.httpunit.javascript.JavaScriptEngineFactory";
+ private static final String NEW_SCRIPTING_ENGINE_FACTORY = "com.meterware.httpunit.dom.DomBasedScriptingEngineFactory";
+
+ // comment out the scripting engine not to be used by allowing the appropriate number of asterisks in the comment on the next line (1 or 2)
+ /**/
+ final static public String DEFAULT_SCRIPT_ENGINE_FACTORY = ORIGINAL_SCRIPTING_ENGINE_FACTORY;
+ /*/
+ final static public String DEFAULT_SCRIPT_ENGINE_FACTORY = NEW_SCRIPTING_ENGINE_FACTORY;
+ /*/
+
+
+ /**
+ * Resets all options to their default values.
+ */
+ public static void reset() {
+ _exceptionsOnErrorStatus = true;
+ _parameterValuesValidated = true;
+ _imagesTreatedAsAltText = false;
+ _loggingHttpHeaders = false;
+ _matchesIgnoreCase = true;
+ _checkContentLength = false;
+ _redirectDelay = 0; // TODO move this to ClientProperties
+ _characterSet = HttpUnitUtils.DEFAULT_CHARACTER_SET;
+ _contentType = DEFAULT_CONTENT_TYPE;
+ _postIncludesCharset = false;
+ _exceptionsThrownOnScriptError = true;
+ _customAttributes = null;
+ _javaScriptOptimizationLevel = -1;
+ setScriptEngineClassName( DEFAULT_SCRIPT_ENGINE_FACTORY );
+ setScriptingEnabled( true );
+ }
+
+
+ /**
+ * Returns true if HttpUnit is accepting and saving cookies. The default is to accept them.
+ * @deprecated as of 1.5.3, use ClientProperties#isAcceptCookies();
+ */
+ public static boolean isAcceptCookies() {
+ return ClientProperties.getDefaultProperties().isAcceptCookies();
+ }
+
+
+ /**
+ * Specifies whether HttpUnit should accept and send cookies.
+ * @deprecated as of 1.5.3, use ClientProperties#setAcceptCookies();
+ */
+ public static void setAcceptCookies( boolean acceptCookies ) {
+ ClientProperties.getDefaultProperties().setAcceptCookies( acceptCookies );
+ }
+
+
+ /**
+ * Returns true if any WebClient created will accept GZIP encoding of responses. The default is to accept GZIP encoding.
+ * @deprecated as of 1.5.3, use ClientProperties#isAcceptGzip();
+ **/
+ public static boolean isAcceptGzip() {
+ return ClientProperties.getDefaultProperties().isAcceptGzip();
+ }
+
+
+ /**
+ * Specifies whether a WebClient will be initialized to accept GZIP encoded responses. The default is true.
+ * @deprecated as of 1.5.3, use ClientProperties#setAcceptGzip();
+ */
+ public static void setAcceptGzip( boolean acceptGzip ) {
+ ClientProperties.getDefaultProperties().setAcceptGzip( acceptGzip );
+ }
+
+
+ /**
+ * Resets the default character set to the HTTP default encoding.
+ **/
+ public static void resetDefaultCharacterSet() {
+ _characterSet = HttpUnitUtils.DEFAULT_CHARACTER_SET;
+ }
+
+
+ /**
+ * Resets the default content type to plain text.
+ **/
+ public static void resetDefaultContentType() {
+ _contentType = DEFAULT_CONTENT_TYPE;
+ }
+
+
+ /**
+ * Sets the default character set for pages which do not specify one and for requests created without HTML sources.
+ * By default, HttpUnit uses the HTTP default encoding, iso-8859-1.
+ **/
+ public static void setDefaultCharacterSet( String characterSet ) {
+ _characterSet = characterSet;
+ }
+
+
+ /**
+ * Returns the character set to be used for pages which do not specify one.
+ **/
+ public static String getDefaultCharacterSet() {
+ return _characterSet;
+ }
+
+
+ /**
+ * Returns true if HttpUnit will throw an exception when a message is only partially received. The default is
+ * to avoid such checks.
+ */
+ public static boolean isCheckContentLength() {
+ return _checkContentLength;
+ }
+
+
+ /**
+ * Specifies whether HttpUnit should throw an exception when the content length of a message does not match its
+ * actual received length. Defaults to false.
+ */
+ public static void setCheckContentLength( boolean checkContentLength ) {
+ _checkContentLength = checkContentLength;
+ }
+
+
+ /**
+ * Determines whether a normal POST request will include the character set in the content-type header.
+ * The default is to include it; however, some older servlet engines (most notably Tomcat 3.1) get confused
+ * when they see it.
+ **/
+ public static void setPostIncludesCharset( boolean postIncludesCharset )
+ {
+ _postIncludesCharset = postIncludesCharset;
+ }
+
+
+ /**
+ * Returns true if POST requests should include the character set in the content-type header.
+ **/
+ public static boolean isPostIncludesCharset()
+ {
+ return _postIncludesCharset;
+ }
+
+
+ /**
+ * Sets the default content type for pages which do not specify one.
+ **/
+ public static void setDefaultContentType( String contentType ) {
+ _contentType = contentType;
+ }
+
+
+ /**
+ * Returns the content type to be used for pages which do not specify one.
+ **/
+ public static String getDefaultContentType() {
+ return _contentType;
+ }
+
+
+ /**
+ * Returns true if parser warnings are enabled.
+ * @deprecated as of 1.5.2, use HTMLParserFactory#isParserWarningsEnabled
+ **/
+ public static boolean getParserWarningsEnabled() {
+ return HTMLParserFactory.isParserWarningsEnabled();
+ }
+
+
+ /**
+ * If true, tells the parser to display warning messages. The default is false (warnings are not shown).
+ * @deprecated as of 1.5.2, use HTMLParserFactory#setParserWarningsEnabled
+ **/
+ public static void setParserWarningsEnabled( boolean enabled ) {
+ HTMLParserFactory.setParserWarningsEnabled( enabled );
+ }
+
+
+ /**
+ * If true, WebClient.getResponse throws an exception when it receives an error status.
+ * Defaults to true.
+ **/
+ public static void setExceptionsThrownOnErrorStatus( boolean enabled ) {
+ _exceptionsOnErrorStatus = enabled;
+ }
+
+
+ /**
+ * Returns true if WebClient.getResponse throws exceptions when detected an error status.
+ **/
+ public static boolean getExceptionsThrownOnErrorStatus() {
+ return _exceptionsOnErrorStatus;
+ }
+
+
+ /**
+ * Returns true if form parameter settings are checked.
+ *
+ * @deprecated as of 1.6, use WebForm#newUnvalidatedRequest() to obtain a request without parameter validation.
+ **/
+ public static boolean getParameterValuesValidated() {
+ return _parameterValuesValidated;
+ }
+
+
+ /**
+ * If true, tells HttpUnit to throw an exception on any attempt to set a form parameter to a value
+ * which could not be set via the browser. The default is true (parameters are validated).
+ * Note: this only applies to a WebRequest created after this setting is changed. A request created
+ * with this option disabled will not only not be checked for correctness, its parameter submission
+ * order will not be guaranteed, and changing parameters will not trigger Javascript onChange / onClick events.
+ *
+ * @deprecated as of 1.6, use WebForm#newUnvalidatedRequest() to obtain a request without parameter validation.
+ **/
+ public static void setParameterValuesValidated( boolean validated ) {
+ _parameterValuesValidated = validated;
+ }
+
+
+ /**
+ * Returns true if images are treated as text, using their alt attributes.
+ **/
+ public static boolean getImagesTreatedAsAltText() {
+ return _imagesTreatedAsAltText;
+ }
+
+
+ /**
+ * If true, tells HttpUnit to treat images with alt attributes as though they were the text
+ * value of that attribute in all searches and displays. The default is false (image text is generally ignored).
+ **/
+ public static void setImagesTreatedAsAltText( boolean asText ) {
+ _imagesTreatedAsAltText = asText;
+ }
+
+
+ /**
+ * If true, text matches in methods such as {@link HTMLSegment#getLinkWith} are
+ * case insensitive. The default is true (matches ignore case).
+ **/
+ public static boolean getMatchesIgnoreCase() {
+ return _matchesIgnoreCase;
+ }
+
+
+ /**
+ * If true, text matches in methods such as {@link HTMLSegment#getLinkWith} are
+ * case insensitive. The default is true (matches ignore case).
+ **/
+ public static void setMatchesIgnoreCase( boolean ignoreCase ) {
+ _matchesIgnoreCase = ignoreCase;
+ }
+
+
+ /**
+ * Returns true if HTTP headers are to be dumped to system output.
+ **/
+ public static boolean isLoggingHttpHeaders() {
+ return _loggingHttpHeaders;
+ }
+
+
+ /**
+ * If true, tells HttpUnit to log HTTP headers to system output. The default is false.
+ **/
+ public static void setLoggingHttpHeaders( boolean enabled ) {
+ _loggingHttpHeaders = enabled;
+ }
+
+
+ /**
+ * Returns true if HttpUnit should automatically follow page redirect requests (status 3xx).
+ * By default, this is true.
+ * @deprecated as of 1.5.3, use ClientProperties#isAutoRedirect();
+ **/
+ public static boolean getAutoRedirect() {
+ return ClientProperties.getDefaultProperties().isAutoRedirect();
+ }
+
+
+ /**
+ * Determines whether HttpUnit should automatically follow page redirect requests (status 3xx).
+ * By default, this is true in order to simulate normal browser operation.
+ * @deprecated as of 1.5.3, use ClientProperties#setAutoRedirect();
+ **/
+ public static void setAutoRedirect( boolean autoRedirect ) {
+ ClientProperties.getDefaultProperties().setAutoRedirect( autoRedirect );
+ }
+
+
+ /**
+ * Returns the delay, in milliseconds, before a redirect request is issues.
+ **/
+ public static int getRedirectDelay() {
+ return _redirectDelay;
+ }
+
+
+ /**
+ * Sets the delay, in milliseconds, before a redirect request is issued. This may be necessary if the server
+ * under some cases where the server performs asynchronous processing which must be completed before the
+ * new request can be handled properly, and is taking advantage of slower processing by most user agents. It
+ * almost always indicates an error in the server design, and therefore the default delay is zero.
+ **/
+ public static void setRedirectDelay( int delayInMilliseconds ) {
+ _redirectDelay = delayInMilliseconds;
+ }
+
+
+ /**
+ * Returns true if HttpUnit should automatically follow page refresh requests.
+ * By default, this is false, so that programs can verify the redirect page presented
+ * to users before the browser switches to the new page.
+ * @deprecated as of 1.5.3, use ClientProperties#isAutoRefresh();
+ **/
+ public static boolean getAutoRefresh() {
+ return ClientProperties.getDefaultProperties().isAutoRefresh();
+ }
+
+
+ /**
+ * Specifies whether HttpUnit should automatically follow page refresh requests.
+ * By default, this is false, so that programs can verify the redirect page presented
+ * to users before the browser switches to the new page. Setting this to true can
+ * cause an infinite loop on pages that refresh themselves.
+ * @deprecated as of 1.5.3, use ClientProperties#setAutoRefresh();
+ **/
+ public static void setAutoRefresh( boolean autoRefresh ) {
+ ClientProperties.getDefaultProperties().setAutoRefresh( autoRefresh );
+ }
+
+
+ /**
+ * Remove an Html error listener.
+ * @deprecated as of 1.5.2, use HTMLParserfactory#removeHTMLParserListener
+ **/
+ public static void removeHtmlErrorListener(HTMLParserListener el) {
+ HTMLParserFactory.removeHTMLParserListener( el );
+ }
+
+ /**
+ * Add an Html error listener.
+ * @deprecated as of 1.5.2, use HTMLParserfactory#addHTMLParserListener
+ **/
+ public static void addHtmlErrorListener(HTMLParserListener el) {
+ HTMLParserFactory.addHTMLParserListener( el );
+ }
+
+ /**
+ * Get the list of Html Error Listeners
+ * @deprecated as of 1.5.2, removed with no replacement
+ **/
+ public static Vector getHtmlErrorListeners() {
+ return null;
+ }
+
+
+ public static String getScriptEngineClassName() {
+ return _scriptEngineClassName;
+ }
+
+
+ public static void setScriptEngineClassName( String scriptEngineClassName ) {
+ if (_scriptEngineClassName == null || !_scriptEngineClassName.equals( scriptEngineClassName )) {
+ _scriptingEngine = null;
+ }
+ _scriptEngineClassName = scriptEngineClassName;
+ }
+
+
+ public static ScriptingEngineFactory getScriptingEngine() {
+ if (_scriptingEngine == null) {
+ try {
+ Class factoryClass = Class.forName( _scriptEngineClassName );
+ final ScriptingEngineFactory factory = (ScriptingEngineFactory) factoryClass.newInstance();
+ _scriptingEngine = factory.isEnabled() ? factory : NULL_SCRIPTING_ENGINE_FACTORY;
+ _scriptingEngine.setThrowExceptionsOnError( _exceptionsThrownOnScriptError );
+ } catch (ClassNotFoundException e) {
+ disableScripting( e, "Unable to find scripting engine factory class " );
+ } catch (InstantiationException e) {
+ disableScripting( e, "Unable to instantiate scripting engine factory class " );
+ } catch (IllegalAccessException e) {
+ disableScripting( e, "Unable to create scripting engine factory class " );
+ }
+ }
+ return _scriptingEngine;
+ }
+
+
+ /**
+ * change the scriptingEnabled flag
+ * @param scriptingEnabled
+ */
+ public static void setScriptingEnabled( boolean scriptingEnabled ) {
+ if (scriptingEnabled != _scriptingEnabled) {
+ _scriptingEngine = scriptingEnabled ? null : NULL_SCRIPTING_ENGINE_FACTORY;
+ }
+ _scriptingEnabled = scriptingEnabled;
+ }
+
+
+ public static boolean isScriptingEnabled() {
+ return _scriptingEnabled;
+ }
+
+
+
+ /**
+ * Determines whether script errors result in exceptions or warning messages.
+ */
+ public static void setExceptionsThrownOnScriptError( boolean throwExceptions ) {
+ _exceptionsThrownOnScriptError = throwExceptions;
+ getScriptingEngine().setThrowExceptionsOnError( throwExceptions );
+ }
+
+
+ /**
+ * Returns true if script errors cause exceptions to be thrown.
+ */
+ public static boolean getExceptionsThrownOnScriptError() {
+ return _exceptionsThrownOnScriptError;
+ }
+
+
+ /**
+ * Returns the accumulated script error messages encountered. Error messages are accumulated only
+ * if 'throwExceptionsOnError' is disabled.
+ */
+ public static String[] getScriptErrorMessages() {
+ return getScriptingEngine().getErrorMessages();
+ }
+
+
+ /**
+ * Clears the accumulated script error messages.
+ */
+ public static void clearScriptErrorMessages() {
+ getScriptingEngine().clearErrorMessages();
+ }
+
+
+ private static void disableScripting( Exception e, String errorMessage ) {
+ System.err.println( errorMessage + _scriptEngineClassName );
+ System.err.println( "" + e );
+ System.err.println( "JavaScript execution disabled");
+ _scriptingEngine = NULL_SCRIPTING_ENGINE_FACTORY;
+ }
+
+
+//--------------------------------- private members --------------------------------------
+
+
+ private static final String DEFAULT_CONTENT_TYPE = "text/html";
+
+ private static final ScriptingEngineFactory NULL_SCRIPTING_ENGINE_FACTORY = new ScriptingEngineFactory() {
+ public boolean isEnabled() { return false; }
+ public void associate( WebResponse response ) {}
+ public void load( WebResponse response ) {}
+ public void setThrowExceptionsOnError( boolean throwExceptions ) {}
+ public boolean isThrowExceptionsOnError() { return false; }
+ public String[] getErrorMessages() { return new String[ 0 ]; }
+ public void clearErrorMessages() {}
+ public ScriptingHandler createHandler( HTMLElement element ) { return ScriptableDelegate.NULL_SCRIPT_ENGINE; }
+ public ScriptingHandler createHandler( WebResponse response ) { return ScriptableDelegate.NULL_SCRIPT_ENGINE; }
+ };
+
+
+ /**
+ * Add the name of a custom attribute that should be supported for form controls.
+ * @deprecated for new Scripting engine
+ */
+ public static void addCustomAttribute(String attributeName) {
+ if(_customAttributes == null)
+ _customAttributes = new HashSet();
+ _customAttributes.add(attributeName);
+ }
+
+ /**
+ * Get the Set of custom attribute names to be supported by form controls.
+ * @deprecated for new scripting engine
+ */
+ static Set getCustomAttributes() {
+ return _customAttributes;
+ }
+
+
+ private static Set _customAttributes = null;
+
+ private static boolean _exceptionsOnErrorStatus = true;
+
+ private static boolean _parameterValuesValidated = true;
+
+ private static boolean _imagesTreatedAsAltText;
+
+ private static boolean _loggingHttpHeaders;
+
+ private static boolean _matchesIgnoreCase = true;
+
+ private static boolean _postIncludesCharset = false;
+
+ private static boolean _checkContentLength = false;
+
+ private static int _redirectDelay;
+
+ private static String _characterSet = HttpUnitUtils.DEFAULT_CHARACTER_SET;
+
+ private static String _contentType = DEFAULT_CONTENT_TYPE;
+
+ private static String _scriptEngineClassName;
+
+ private static ScriptingEngineFactory _scriptingEngine;
+
+ private static boolean _scriptingEnabled = true;
+
+ private static boolean _exceptionsThrownOnScriptError = true;
+
+ private static int _javaScriptOptimizationLevel = -1;
+
+
+ static {
+ reset();
+
+ }
+
+
+ /**
+ * getter for Java Script optimization level
+ * @return the javaScriptOptimizationLevel to be use for running
+ * scripts
+ */
+ public static int getJavaScriptOptimizationLevel() {
+ return _javaScriptOptimizationLevel;
+ }
+
+
+ /**
+ * setter for Java Script optimization level
+ * @param scriptOptimizationLevel the _javaScriptOptimizationLevel to set
+ * see rhino documentation for valid values:
+ * -2: with continuation
+ * -1: interpret
+ * 0: compile to Java bytecode, don't optimize
+ * 1..9: compile to Java bytecode, optimize *
+ */
+ public static void setJavaScriptOptimizationLevel(
+ int scriptOptimizationLevel) {
+ _javaScriptOptimizationLevel = scriptOptimizationLevel;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitUtils.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitUtils.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpUnitUtils.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,461 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.util.StringTokenizer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
+import org.xml.sax.EntityResolver;
+
+/**
+ * Utility code shared by httpunit and servletunit.
+ **/
+public class HttpUnitUtils {
+
+ public static final int DEFAULT_TEXT_BUFFER_SIZE = 2048;
+ public static final String DEFAULT_CHARACTER_SET = "iso-8859-1";
+ /**
+ * set to true to debug Exception handling
+ */
+ private static boolean EXCEPTION_DEBUG=true;
+
+ /**
+ * handle Exceptions and thowables
+ * @param th
+ */
+ public static void handleException(Throwable th) {
+ if (EXCEPTION_DEBUG) {
+ th.printStackTrace();
+ }
+ }
+
+ /**
+ * are we running in the Eclipse IDE?
+ * @return whether we are running in the Eclipse environment
+ */
+ public static boolean isEclipse() {
+ StackTraceElement[] ste = new Throwable().getStackTrace();
+ return (ste[ste.length - 1].getClassName().startsWith("org.eclipse.jdt"));
+ }
+
+ /**
+ * Returns the content type and encoding as a pair of strings.
+ * If no character set is specified, the second entry will be null.
+ * @param header the header to parse
+ * @return a string array with the content type and the content charset
+ **/
+ public static String[] parseContentTypeHeader( String header ) {
+ String[] result = new String[] { "text/plain", null };
+ StringTokenizer st = new StringTokenizer( header, ";=" );
+ result[0] = st.nextToken();
+ while (st.hasMoreTokens()) {
+ String parameter = st.nextToken();
+ if (st.hasMoreTokens()) {
+ String value = stripQuotes( st.nextToken() );
+ if (parameter.trim().equalsIgnoreCase( "charset" )) {
+ result[1] = value;
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * strip the quotes from a value
+ * @param value
+ * @return the stripped value
+ */
+ public static String stripQuotes( String value ) {
+ if (value.startsWith( "'" ) || value.startsWith( "\"" )) value = value.substring( 1 );
+ if (value.endsWith( "'" ) || value.endsWith( "\"" )) value = value.substring( 0, value.length()-1 );
+ return value;
+ }
+
+ /**
+ * Returns an interpretation of the specified URL-encoded string, using the iso-8859-1 character set.
+ *
+ * @since 1.6
+ **/
+ public static String decode( String byteString ) {
+ return decode( byteString, "iso-8859-1" );
+ }
+
+
+ /**
+ * Returns a string representation of a number, trimming off any trailing decimal zeros.
+ */
+ static String trimmedValue( Number number ) {
+ String rawNumber = number.toString();
+ if (rawNumber.indexOf('.') == -1) return rawNumber;
+
+ int index = rawNumber.length();
+ while (rawNumber.charAt( index-1 ) == '0') index--;
+ if (rawNumber.charAt( index-1 ) == '.') index--;
+ return rawNumber.substring( 0, index );
+ }
+
+
+
+ /**
+ * Decodes a URL safe string into its original form using the
+ * specified character set. Escaped characters are converted back
+ * to their original representation.
+ *
+ * This method is copied from the Jakarta Commons Codec;
+ * org.apache.commons.codec.net.URLCodec
class.
+ *
+ * @param string URL safe string to convert into its original form
+ * @return original string
+ * @throws IllegalArgumentException thrown if URL decoding is unsuccessful,
+ */
+ public static String decode( String string, String charset ) {
+ try {
+ if (string == null) return null;
+
+ return new String( decodeUrl( string.getBytes( "US-ASCII" ) ), charset );
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException( e.toString() );
+ }
+ }
+
+
+ /**
+ * Decodes an array of URL safe 7-bit characters into an array of
+ * original bytes. Escaped characters are converted back to their
+ * original representation.
+ *
+ * This method is copied from the Jakarta Commons Codec;
+ * org.apache.commons.codec.net.URLCodec
class.
+ *
+ * @param pArray array of URL safe characters
+ * @return array of original bytes
+ */
+ private static final byte[] decodeUrl( byte[] pArray ) throws IllegalArgumentException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ for (int i = 0; i < pArray.length; i++) {
+ int b = pArray[i];
+ if (b == '+') {
+ buffer.write( ' ' );
+ } else if (b != '%') {
+ buffer.write( b );
+ } else {
+ try {
+ int u = Character.digit( (char) pArray[++i], 16 );
+ int l = Character.digit( (char) pArray[++i], 16 );
+ if (u == -1 || l == -1) throw new IllegalArgumentException( "Invalid URL encoding" );
+ buffer.write( (char) ((u << 4) + l) );
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException( "Invalid URL encoding" );
+ }
+ }
+ }
+ return buffer.toByteArray();
+ }
+
+ /**
+ * parse an InputStream to a string (for debugging)
+ * @param is
+ * @return the string gotten from the inputString
+ */
+ public static String parseISToString(java.io.InputStream is){
+ java.io.DataInputStream din = new java.io.DataInputStream(is);
+ StringBuffer sb = new StringBuffer();
+ try{
+ String line = null;
+ while((line=din.readLine()) != null){
+ sb.append(line+"\n");
+ }
+ }catch(Exception ex){
+ // TODO handle exception properly here
+ ex.getMessage();
+ }finally{
+ try{
+ is.close();
+ }catch(Exception ex){}
+ }
+ return sb.toString();
+ }
+
+ /**
+ * parse the given inputSource with a new Parser
+ * @param inputSource
+ * @return the document parsed from the input Source
+ */
+ public static Document parse(InputSource inputSource) throws SAXException,IOException {
+ DocumentBuilder db=newParser();
+ try {
+ Document doc=db.parse(inputSource);
+ return doc;
+ } catch (java.net.MalformedURLException mue) {
+ if (EXCEPTION_DEBUG) {
+ String msg=mue.getMessage();
+ if (msg!=null) {
+ System.err.println(msg);
+ }
+ InputStream is=inputSource.getByteStream();
+ is.reset();
+ String content=parseISToString(is);
+ System.err.println(content);
+ }
+ throw mue;
+ }
+ }
+
+ /**
+ * parse the given inputStream with a new Parser
+ * @param inputStream
+ * @return the document parsed from the input Stream
+ */
+ public static Document parse(InputStream inputStream) throws SAXException,IOException {
+ DocumentBuilder db=newParser();
+ try {
+ Document doc=db.parse(inputStream);
+ return doc;
+ } catch (java.net.MalformedURLException mue) {
+ if (EXCEPTION_DEBUG) {
+ String msg=mue.getMessage();
+ if (msg!=null) {
+ System.err.println(msg);
+ }
+ InputStream is=inputStream;
+ is.reset();
+ String content=parseISToString(is);
+ System.err.println(content);
+ }
+ throw mue;
+ }
+ }
+
+
+ /**
+ * creates a parser using JAXP API.
+ */
+ public static DocumentBuilder newParser() throws SAXException {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setEntityResolver( new HttpUnitUtils.ClasspathEntityResolver() );
+ return builder;
+ } catch (ParserConfigurationException ex) {
+ // redirect the new exception for code compatibility
+ throw new SAXException( ex );
+ }
+ }
+
+
+ /**
+ * Returns a string array created by appending a string to an existing array. The existing array may be null.
+ **/
+ static String[] withNewValue( String[] oldValue, String newValue ) {
+ String[] result;
+ if (oldValue == null) {
+ result = new String[] { newValue };
+ } else {
+ result = new String[ oldValue.length+1 ];
+ System.arraycopy( oldValue, 0, result, 0, oldValue.length );
+ result[ oldValue.length ] = newValue;
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns a string array created by appending an object to an existing array. The existing array may be null.
+ **/
+ static Object[] withNewValue( Object[] oldValue, Object newValue ) {
+ Object[] result;
+ if (oldValue == null) {
+ result = new Object[] { newValue };
+ } else {
+ result = new Object[ oldValue.length+1 ];
+ System.arraycopy( oldValue, 0, result, 0, oldValue.length );
+ result[ oldValue.length ] = newValue;
+ }
+ return result;
+ }
+
+
+ /**
+ * Return true if the first string contains the second.
+ * Case sensitivity is according to the setting of HttpUnitOptions.matchesIgnoreCase
+ */
+ static boolean contains( String string, String substring ) {
+ if (HttpUnitOptions.getMatchesIgnoreCase()) {
+ return string.toUpperCase().indexOf( substring.toUpperCase() ) >= 0;
+ } else {
+ return string.indexOf( substring ) >= 0;
+ }
+ }
+
+
+ /**
+ * Return true if the first string starts with the second.
+ * Case sensitivity is according to the setting of HttpUnitOptions.matchesIgnoreCase
+ */
+ static boolean hasPrefix( String string, String prefix ) {
+ if (HttpUnitOptions.getMatchesIgnoreCase()) {
+ return string.toUpperCase().startsWith( prefix.toUpperCase() );
+ } else {
+ return string.startsWith( prefix );
+ }
+ }
+
+
+ /**
+ * Return true if the first string equals the second.
+ * Case sensitivity is according to the setting of HttpUnitOptions.matchesIgnoreCase
+ */
+ static boolean matches( String string1, String string2 ) {
+ if (HttpUnitOptions.getMatchesIgnoreCase()) {
+ return string1.equalsIgnoreCase( string2 );
+ } else {
+ return string1.equals( string2 );
+ }
+ }
+
+
+ /**
+ * check whether the URL is a java script url
+ * @param urlString - the string to analyze
+ * @return - true if this is a javascript url
+ */
+ static boolean isJavaScriptURL( String urlString ) {
+ boolean result=urlString.toLowerCase().startsWith( "javascript:" );
+ return result;
+ }
+
+
+ /**
+ * Trims whitespace from the ends, and encodes from the middle.
+ * Spaces within quotes are respected.
+ */
+ static String encodeSpaces( String s ) {
+ s = s.trim();
+ // if no spaces we are fine
+ if (s.indexOf( ' ' ) < 0)
+ return s;
+
+ boolean inQuotes = false;
+ StringBuffer sb = new StringBuffer();
+ char[] chars = s.toCharArray();
+ // loop over oper the chars of the URL
+ for (int i = 0; i < chars.length; i++) {
+ // get the current character
+ char aChar = chars[i];
+ // toggle quotation and add quote
+ if (aChar == '"' || aChar == '\'' ) {
+ inQuotes = !inQuotes;
+ sb.append( aChar );
+ // append everything in quotes and printable chars above space
+ } else if (inQuotes) {
+ sb.append( aChar );
+ } else if (aChar > ' ') {
+ sb.append( aChar );
+ } else if (aChar==' ') {
+ // encode spaces
+ // TODO check what to do about breaking testLinkUrlAcrossLineBreaks then ...
+ // sb.append("%20");
+ }
+ }
+ return sb.toString();
+ }
+
+
+ static String replaceEntities( String string ) {
+ int i = 0;
+ int ampIndex;
+ while ((ampIndex = string.indexOf( '&', i )) >= 0) {
+ int semiColonIndex = string.indexOf( ';', ampIndex+1 );
+ if (semiColonIndex < 0) break;
+ i = ampIndex+1;
+
+ String entityName = string.substring( ampIndex+1, semiColonIndex );
+ if (entityName.equalsIgnoreCase( "amp" )) {
+ string = string.substring( 0, ampIndex ) + '&' + string.substring( semiColonIndex+1 );
+ }
+
+ }
+ return string;
+ }
+
+
+ /**
+ * Strips the fragment identifier (if any) from the Url.
+ */
+ static String trimFragment( String rawUrl ) {
+ if (isJavaScriptURL( rawUrl )) return rawUrl;
+ final int hashIndex = rawUrl.indexOf( '#' );
+ return hashIndex < 0 ? rawUrl: rawUrl.substring( 0, hashIndex );
+ }
+
+
+ static class ClasspathEntityResolver implements EntityResolver {
+
+ public InputSource resolveEntity( String publicID, String systemID ) {
+ if (systemID == null) return null;
+
+ String localName = systemID;
+ if (localName.indexOf( "/" ) > 0) {
+ localName = localName.substring( localName.lastIndexOf( "/" ) + 1, localName.length() );
+ }
+
+ try {
+ return new InputSource( getClass().getClassLoader().getResourceAsStream( localName ) );
+ } catch (Exception e) {
+ // proposed patch for bug report
+ // [ 1264706 ] [patch] replace ClasspathEntityResolver
+ // by fabrizio giustina
+ // even to return this in all cases!
+ // return new InputSource( new ByteArrayInputStream( new byte[0] ) );
+ return null;
+ }
+ }
+ }
+
+
+ /**
+ * @return the eXCEPTION_DEBUG
+ */
+ protected static boolean isEXCEPTION_DEBUG() {
+ return EXCEPTION_DEBUG;
+ }
+
+ /**
+ * @param exception_debug the eXCEPTION_DEBUG to set
+ */
+ public static boolean setEXCEPTION_DEBUG(boolean exception_debug) {
+ boolean oldExceptionDebug=exception_debug;
+ EXCEPTION_DEBUG = exception_debug;
+ return oldExceptionDebug;
+ }
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpWebResponse.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpWebResponse.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpWebResponse.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,276 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+
+/**
+ * A response from a web server to an Http request.
+ *
+ * @author Russell Gold
+ **/
+class HttpWebResponse extends WebResponse {
+
+ private String _referer;
+
+
+ /**
+ * Constructs a response object from an input stream.
+ * @param frame the target window or frame to which the request should be directed
+ * @param url the url from which the response was received
+ * @param connection the URL connection from which the response can be read
+ **/
+ HttpWebResponse( WebConversation client, FrameSelector frame, URL url, URLConnection connection, boolean throwExceptionOnError ) throws IOException {
+ super( client, frame, url );
+ if (HttpUnitOptions.isLoggingHttpHeaders()) System.out.println( "\nReceived from " + url );
+ readHeaders( connection );
+
+ /** make sure that any IO exception for HTML received page happens here, not later. **/
+ if (_responseCode < HttpURLConnection.HTTP_BAD_REQUEST || !throwExceptionOnError) {
+ defineRawInputStream( new BufferedInputStream( getInputStream( connection ) ) );
+ if (getContentType().startsWith( "text" )) loadResponseText();
+ }
+ }
+
+
+ HttpWebResponse( WebConversation client, FrameSelector frame, WebRequest request, URLConnection connection, boolean throwExceptionOnError ) throws IOException {
+ this( client, frame, request.getURL(), connection, throwExceptionOnError );
+ _referer = request.getReferer();
+ }
+
+
+
+ /**
+ * get the input stream for the given connection
+ * @param connection
+ * @return
+ * @throws IOException
+ */
+ private InputStream getInputStream( URLConnection connection ) throws IOException {
+ InputStream result=null;
+ // check whether there is an error stream
+ if (isResponseOnErrorStream( connection )) {
+ result=((HttpURLConnection) connection).getErrorStream();
+ } else {
+ // if there is no error stream it depends on the response code
+ try {
+ result=connection.getInputStream();
+ } catch (java.io.FileNotFoundException fnfe) {
+ // as of JDK 1.5 a null inputstream might have been returned here
+ // see bug report [ 1283878 ] FileNotFoundException using Sun JDK 1.5 on empty error pages
+ // by Roger Lindsj�
+ if (isErrorResponse(connection)) {
+ // fake an empty error stream
+ result=new ByteArrayInputStream(new byte[0]);
+ } else {
+ throw fnfe;
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * check whether a response code >=400 was received
+ * @param connection
+ * @return
+ */
+ private boolean isErrorResponse(URLConnection connection ) {
+ return _responseCode >= HttpURLConnection.HTTP_BAD_REQUEST;
+ }
+
+ /**
+ * check whether the response is on the error stream
+ * @param connection
+ * @return
+ */
+ private boolean isResponseOnErrorStream( URLConnection connection ) {
+ return isErrorResponse(connection) && ((HttpURLConnection) connection).getErrorStream() != null;
+ }
+
+
+ /**
+ * Returns the response code associated with this response.
+ **/
+ public int getResponseCode() {
+ return _responseCode;
+ }
+
+
+ /**
+ * Returns the response message associated with this response.
+ **/
+ public String getResponseMessage() {
+ return _responseMessage;
+ }
+
+
+ public String[] getHeaderFieldNames() {
+ Vector names = new Vector();
+ for (Enumeration e = _headers.keys(); e.hasMoreElements();) {
+ names.addElement( e.nextElement() );
+ }
+ String[] result = new String[ names.size() ];
+ names.copyInto( result );
+ return result;
+ }
+
+
+ /**
+ * Returns the value for the specified header field. If no such field is defined, will return null.
+ **/
+ public String getHeaderField( String fieldName ) {
+ String[] fields = (String[]) _headers.get( fieldName.toUpperCase());
+ return fields == null ? null : fields[0];
+ }
+
+
+ public String[] getHeaderFields( String fieldName ) {
+ String[] fields = (String[]) _headers.get( fieldName.toUpperCase());
+ return fields == null ? new String[0] : fields;
+ }
+
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer( "HttpWebResponse [url=" );
+ sb.append( getURL() ).append( "; headers=" );
+ for (Enumeration e = _headers.keys(); e.hasMoreElements(); ) {
+ Object key = e.nextElement();
+ String[] values = (String[]) _headers.get( key );
+ for (int i = 0; i < values.length; i++) {
+ sb.append( "\n " ).append( key ).append( ": " ).append( values[i] );
+ }
+ }
+ sb.append( " ]" );
+ return sb.toString();
+ }
+
+
+ String getReferer() {
+ return _referer;
+ }
+
+
+//------------------------------------- private members -------------------------------------
+
+
+ private final static String FILE_ENCODING = System.getProperty( "file.encoding" );
+
+
+ private int _responseCode = HttpURLConnection.HTTP_OK;
+ private String _responseMessage = "OK";
+
+ private Hashtable _headers = new Hashtable();
+
+
+
+ private void readResponseHeader( HttpURLConnection connection ) throws IOException {
+ if (!needStatusWorkaround()) {
+ _responseCode = connection.getResponseCode();
+ _responseMessage = connection.getResponseMessage();
+ } else {
+ if (connection.getHeaderField(0) == null) throw new UnknownHostException( connection.getURL().toExternalForm() );
+
+ StringTokenizer st = new StringTokenizer( connection.getHeaderField(0) );
+ st.nextToken();
+ if (!st.hasMoreTokens()) {
+ _responseCode = HttpURLConnection.HTTP_OK;
+ _responseMessage = "OK";
+ } else try {
+ _responseCode = Integer.parseInt( st.nextToken() );
+ _responseMessage = getRemainingTokens( st );
+ } catch (NumberFormatException e) {
+ _responseCode = HttpURLConnection.HTTP_INTERNAL_ERROR;
+ _responseMessage = "Cannot parse response header";
+ }
+ }
+ }
+
+ private boolean needStatusWorkaround() {
+ final String jdkVersion = System.getProperty( "java.version" );
+ return jdkVersion.startsWith( "1.2" ) || jdkVersion.startsWith( "1.3" );
+ }
+
+
+ private String getRemainingTokens( StringTokenizer st ) {
+ StringBuffer messageBuffer = new StringBuffer( st.hasMoreTokens() ? st.nextToken() : "" );
+ while (st.hasMoreTokens()) {
+ messageBuffer.append( ' ' ).append( st.nextToken() );
+ }
+ return messageBuffer.toString();
+ }
+
+
+ private void readHeaders( URLConnection connection ) throws IOException {
+ loadHeaders( connection );
+ if (connection instanceof HttpURLConnection) {
+ readResponseHeader( (HttpURLConnection) connection );
+ } else {
+ _responseCode = HttpURLConnection.HTTP_OK;
+ _responseMessage = "OK";
+ if (connection.getContentType().startsWith( "text" )) {
+ setContentTypeHeader( connection.getContentType() + "; charset=" + FILE_ENCODING );
+ }
+ }
+ }
+
+
+ private void loadHeaders( URLConnection connection ) {
+ if (HttpUnitOptions.isLoggingHttpHeaders()) {
+ System.out.println( "Header:: " + connection.getHeaderField(0) );
+ }
+ for (int i = 1; true; i++) {
+ String headerFieldKey = connection.getHeaderFieldKey( i );
+ String headerField = connection.getHeaderField(i);
+ if (headerFieldKey == null || headerField == null) break;
+ if (HttpUnitOptions.isLoggingHttpHeaders()) {
+ System.out.println( "Header:: " + headerFieldKey + ": " + headerField );
+ }
+ addHeader( headerFieldKey.toUpperCase(), headerField );
+ }
+
+ if (connection.getContentType() != null) {
+ setContentTypeHeader( connection.getContentType() );
+ }
+ }
+
+
+
+ private void addHeader( String key, String field ) {
+ _headers.put( key, HttpUnitUtils.withNewValue( (String[]) _headers.get( key ), field ) );
+ }
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/HttpsProtocolSupport.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/HttpsProtocolSupport.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/HttpsProtocolSupport.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,170 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2003-2007, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.security.Provider;
+import java.security.Security;
+
+
+/**
+ * Encapsulates support for the HTTPS protocol.
+ *
+ * @author Russell Gold
+ **/
+public abstract class HttpsProtocolSupport {
+
+ /** The name of the system parameter used by java.net to locate protocol handlers. **/
+ private final static String PROTOCOL_HANDLER_PKGS = "java.protocol.handler.pkgs";
+
+
+ // Sun Microsystems:
+ public final static String SunJSSE_PROVIDER_CLASS = "com.sun.net.ssl.internal.ssl.Provider";
+ // 741145: "sun.net.www.protocol.https";
+ public final static String SunJSSE_PROVIDER_CLASS2 = "sun.net.www.protocol.https";
+ public final static String SunSSL_PROTOCOL_HANDLER = "com.sun.net.ssl.internal.www.protocol";
+
+ // IBM WebSphere
+ // both ibm packages are inside ibmjsseprovider.jar that comes with WebSphere
+ public final static String IBMJSSE_PROVIDER_CLASS = "com.ibm.jsse.IBMJSSEProvider";
+ public final static String IBMSSL_PROTOCOL_HANDLER = "com.ibm.net.ssl.www.protocol";
+
+ /** The name of the JSSE class which provides support for SSL. **/
+ private static String JSSE_PROVIDER_CLASS=SunJSSE_PROVIDER_CLASS;
+ /** The name of the JSSE class which supports the https protocol. **/
+ private static String SSL_PROTOCOL_HANDLER = SunSSL_PROTOCOL_HANDLER ;
+
+ private static Class _httpsProviderClass;
+
+ private static boolean _httpsSupportVerified;
+
+ private static boolean _httpsProtocolSupportEnabled;
+
+ /**
+ * use the given SSL providers - reset the one used so far
+ * @param className
+ * @param handlerName
+ */
+ public static void useProvider(String className,String handlerName) {
+ _httpsProviderClass = null;
+ JSSE_PROVIDER_CLASS =className;
+ SSL_PROTOCOL_HANDLER =handlerName;
+ }
+
+ /**
+ * use the IBM WebShpere handlers
+ */
+ public static void useIBM() {
+ useProvider(IBMJSSE_PROVIDER_CLASS,IBMSSL_PROTOCOL_HANDLER);
+ }
+
+ /**
+ * Returns true if the JSSE extension is installed.
+ */
+ static boolean hasHttpsSupport() {
+ if (!_httpsSupportVerified) {
+ try {
+ getHttpsProviderClass();
+ } catch (ClassNotFoundException e) {
+ }
+ _httpsSupportVerified = true;
+ }
+ return _httpsProviderClass != null;
+ }
+
+
+ /**
+ * Attempts to register the JSSE extension if it is not already registered. Will throw an exception if unable to
+ * register the extension.
+ */
+ static void verifyProtocolSupport( String protocol ) {
+ if (protocol.equalsIgnoreCase( "http" )) {
+ return;
+ } else if (protocol.equalsIgnoreCase( "https" )) {
+ validateHttpsProtocolSupport();
+ }
+ }
+
+
+ private static void validateHttpsProtocolSupport() {
+ if (!_httpsProtocolSupportEnabled) {
+ verifyHttpsSupport();
+ _httpsProtocolSupportEnabled = true;
+ }
+ }
+
+ private static void verifyHttpsSupport() {
+ try {
+ Class providerClass = getHttpsProviderClass();
+ if (!hasProvider( providerClass )) Security.addProvider( (Provider) providerClass.newInstance() );
+ registerSSLProtocolHandler();
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException( "https support requires the Java Secure Sockets Extension. See http://java.sun.com/products/jsse" );
+ } catch (Throwable e) {
+ throw new RuntimeException( "Unable to enable https support. Make sure that you have installed JSSE " +
+ "as described in http://java.sun.com/products/jsse/install.html: " + e );
+ }
+ }
+
+
+ /**
+ * get the Https Provider Class
+ * if it's been set already return it - otherwise
+ * check with the Security package and take the first available provider
+ * if all fails take the default provider class
+ * @return the HttpsProviderClass
+ * @throws ClassNotFoundException
+ */
+ public static Class getHttpsProviderClass() throws ClassNotFoundException {
+ if (_httpsProviderClass == null) {
+ // [ 1520925 ] SSL patch
+ Provider[] sslProviders = Security.getProviders("SSLContext.SSLv3");
+ if (sslProviders.length > 0) {
+ _httpsProviderClass = sslProviders[0].getClass();
+ }
+ if (_httpsProviderClass == null) {
+ _httpsProviderClass = Class.forName( JSSE_PROVIDER_CLASS );
+ }
+ }
+ return _httpsProviderClass;
+ }
+
+
+ private static boolean hasProvider( Class providerClass ) {
+ Provider[] list = Security.getProviders();
+ for (int i = 0; i < list.length; i++) {
+ if (list[i].getClass().equals( providerClass )) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * register the Secure Socket Layer Protocol Handler
+ */
+ private static void registerSSLProtocolHandler() {
+ String list = System.getProperty( PROTOCOL_HANDLER_PKGS );
+ if (list == null || list.length() == 0) {
+ System.setProperty( PROTOCOL_HANDLER_PKGS, SSL_PROTOCOL_HANDLER );
+ } else if (list.indexOf( SSL_PROTOCOL_HANDLER ) < 0) {
+ // [ 1516007 ] Default SSL provider not being used
+ System.setProperty( PROTOCOL_HANDLER_PKGS, list + " | " + SSL_PROTOCOL_HANDLER );
+ }
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/IllegalRequestParameterException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/IllegalRequestParameterException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/IllegalRequestParameterException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,28 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2001, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+/**
+ * This exception is thrown on an attempt to set a form parameter in a way not possible from a browser.
+ * @author Russell Gold
+ **/
+abstract
+public class IllegalRequestParameterException extends RuntimeException {}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/MessageBodyWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/MessageBodyWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/MessageBodyWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,176 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2004,2007 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import com.meterware.httpunit.protocol.ParameterCollection;
+import com.meterware.httpunit.protocol.MessageBody;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.URL;
+import java.net.URLConnection;
+
+
+/**
+ * A web request which contains a non-empty message body. Note that such requests
+ * must use the http
or https
protocols.
+ **/
+abstract
+public class MessageBodyWebRequest extends WebRequest {
+
+ protected MessageBody _body;
+ private boolean _mimeEncoded;
+
+
+ /**
+ * Constructs a web request using a specific absolute url string.
+ **/
+ protected MessageBodyWebRequest( String urlString, boolean mimeEncoded ) {
+ super( urlString );
+ _mimeEncoded = mimeEncoded;
+ }
+
+
+ /**
+ * Constructs a web request using a specific absolute url string.
+ **/
+ protected MessageBodyWebRequest( String urlString, MessageBody messageBody ) {
+ super( urlString );
+ _body = messageBody;
+ }
+
+
+ /**
+ * Constructs a web request with a specific target.
+ **/
+ protected MessageBodyWebRequest( URL urlBase, String urlString, String target, boolean mimeEncoded ) {
+ super( urlBase, urlString, target );
+ _mimeEncoded = mimeEncoded;
+ }
+
+
+ /**
+ * Constructs a web request for a form submitted via a button.
+ *
+ * @since 1.6
+ **/
+ protected MessageBodyWebRequest( WebForm sourceForm, ParameterHolder parameterHolder, SubmitButton button, int x, int y ) {
+ super( sourceForm, parameterHolder, button, x, y );
+ _mimeEncoded = parameterHolder.isSubmitAsMime();
+ setHeaderField( REFERER_HEADER_NAME, sourceForm.getBaseURL().toExternalForm() );
+ }
+
+
+ /**
+ * Constructs a web request for a form submitted via script.
+ **/
+ protected MessageBodyWebRequest( WebForm sourceForm ) {
+ super( sourceForm, WebRequest.newParameterHolder( sourceForm ) );
+ _mimeEncoded = sourceForm.isSubmitAsMime();
+ setHeaderField( REFERER_HEADER_NAME, sourceForm.getBaseURL().toExternalForm() );
+ }
+
+
+ /**
+ * Subclasses may override this method to provide a message body for the
+ * request.
+ **/
+ protected MessageBody getMessageBody() {
+ return _body;
+ }
+
+
+//---------------------------------- WebRequest methods --------------------------------
+
+
+ protected void writeMessageBody( OutputStream stream ) throws IOException {
+ getMessageBody().writeTo( stream, getParameterHolder() );
+ }
+
+
+ /**
+ * Performs any additional processing necessary to complete the request.
+ **/
+ protected void completeRequest( URLConnection connection ) throws IOException {
+ super.completeRequest( connection );
+ connection.setDoInput( true );
+ connection.setDoOutput( true );
+
+ OutputStream stream = connection.getOutputStream();
+ writeMessageBody( stream );
+ stream.flush();
+ stream.close();
+ }
+
+
+ protected String getContentType() {
+ return getMessageBody().getContentType();
+ }
+
+
+ public boolean isMimeEncoded() {
+ return _mimeEncoded;
+ }
+
+//============================= class InputStreamMessageBody ======================================
+
+ /**
+ * A method request message body read directly from an input stream.
+ **/
+ public static class InputStreamMessageBody extends MessageBody {
+
+
+ public InputStreamMessageBody( InputStream source, String contentType ) {
+ super( null );
+ _source = source;
+ _contentType = contentType;
+ }
+
+
+ /**
+ * Returns the content type of this message body.
+ **/
+ public String getContentType() {
+ return _contentType;
+ }
+
+
+ /**
+ * Transmits the body of this request as a sequence of bytes.
+ **/
+ public void writeTo( OutputStream outputStream, ParameterCollection parameters ) throws IOException {
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ outputStream.write( buffer, 0, count );
+ count = _source.read( buffer, 0, buffer.length );
+ } while (count != -1);
+
+ _source.close();
+ }
+
+
+ private InputStream _source;
+ private String _contentType;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/NoSuchFrameException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/NoSuchFrameException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/NoSuchFrameException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,41 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+class NoSuchFrameException extends RuntimeException {
+
+ NoSuchFrameException( String frameName ) {
+ _frameName = frameName;
+ }
+
+
+ public String getMessage() {
+ return "No frame named " + _frameName + " is currently active";
+ }
+
+
+ private String _frameName;
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/NodeUtils.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/NodeUtils.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/NodeUtils.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,262 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.Stack;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import com.meterware.httpunit.parsing.HTMLParserFactory;
+
+
+/**
+ * Some common utilities for manipulating DOM nodes.
+ **/
+public class NodeUtils {
+
+ /**
+ * get the attribute with the given name from the given node as an int value
+ * @param node - the node to look in
+ * @param attributeName - the attribute's name to look for
+ * @param defaultValue
+ * @return - the value - defaultValue as default
+ */
+ public static int getAttributeValue( Node node, String attributeName, int defaultValue ) {
+ NamedNodeMap nnm = node.getAttributes();
+ Node attribute = nnm.getNamedItem( attributeName );
+ if (attribute == null) {
+ return defaultValue;
+ } else try {
+ return Integer.parseInt( attribute.getNodeValue() );
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * get the attribute with the given name from the given node
+ * @param node - the node to look in
+ * @param attributeName - the attribute's name to look for
+ * @return - the value - "" as default
+ */
+ public static String getNodeAttribute( Node node, String attributeName ) {
+ return getNodeAttribute( node, attributeName, "" );
+ }
+
+
+ /**
+ * get the attribute with the given name from the given node
+ * @param node - the node to look in
+ * @param attributeName - the attribute's name to look for
+ * @param defaultValue
+ * @return - the value - defaultValue as default
+ */
+ public static String getNodeAttribute( Node node, String attributeName, String defaultValue ) {
+ NamedNodeMap attributes = node.getAttributes();
+ if (attributes == null) return defaultValue;
+
+ Node attribute = attributes.getNamedItem( attributeName );
+ return (attribute == null) ? defaultValue : attribute.getNodeValue();
+ }
+
+ /**
+ * set the attribute with the given attribute to the given value in the given node
+ * @param node
+ * @param attributeName - the attribute's name to look for
+ * @param value - the value to set
+ */
+ static void setNodeAttribute( Node node, String attributeName, String value ) {
+ ((Element)node).setAttributeNS(null, attributeName, value );
+ }
+
+ /**
+ * remove the given attribute from the given node based on the attribute's name
+ * @param node
+ * @param attributeName
+ */
+ static void removeNodeAttribute( Node node, String attributeName ) {
+ ((Element)node).removeAttribute( attributeName );
+ }
+
+ /**
+ * check whether the given Attribute in the Node is Present
+ * @param node - the node to check
+ * @param attributeName - the attribute name to check
+ * @return true if the attribute is present
+ */
+ public static boolean isNodeAttributePresent( Node node, final String attributeName ) {
+ return node.getAttributes().getNamedItem( attributeName ) != null;
+ }
+
+
+ /**
+ * common Node action methods
+ */
+ interface NodeAction {
+ /**
+ * Does appropriate processing on specified element. Will return false if the subtree below the element
+ * should be skipped.
+ */
+ public boolean processElement( PreOrderTraversal traversal, Element element );
+
+ /**
+ * Processes a text node.
+ */
+ public void processTextNode( PreOrderTraversal traversal, Node textNode );
+ }
+
+ /**
+ * Converts the DOM trees rooted at the specified nodes to text, ignoring
+ * any HTML tags.
+ **/
+ public static String asText( NodeList rootNodes ) {
+ final StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
+ NodeAction action = new NodeAction() {
+ public boolean processElement( PreOrderTraversal traversal, Element node ) {
+ String nodeName = node.getNodeName().toLowerCase();
+ if (nodeName.equals( "p" ) || nodeName.equals( "br" ) || nodeName.equalsIgnoreCase( "tr" )) {
+ sb.append( "\n" );
+ } else if (nodeName.equals( "td" ) || nodeName.equalsIgnoreCase( "th" )) {
+ sb.append( " | " );
+ } else if (nodeName.equals( "img" ) && HttpUnitOptions.getImagesTreatedAsAltText()) {
+ sb.append( getNodeAttribute( node, "alt" ) );
+ }
+ return true;
+ }
+ public void processTextNode( PreOrderTraversal traversal, Node textNode ) {
+ sb.append( HTMLParserFactory.getHTMLParser().getCleanedText( textNode.getNodeValue() ) );
+ }
+ };
+ new PreOrderTraversal( rootNodes ).perform( action );
+ return sb.toString();
+ }
+
+
+ static class PreOrderTraversal {
+
+ private Stack _pendingNodes = new Stack();
+ private Stack _traversalContext = new Stack();
+ private static final Object POP_CONTEXT = new Object();
+
+
+ public PreOrderTraversal( NodeList rootNodes ) {
+ pushNodeList( rootNodes );
+ }
+
+
+ public PreOrderTraversal( Node rootNode ) {
+ pushNodeList( rootNode.getLastChild() );
+ }
+
+
+ public void pushBaseContext( Object context ) {
+ _traversalContext.push( context );
+ }
+
+
+ public void pushContext( Object context ) {
+ _traversalContext.push( context );
+ _pendingNodes.push( POP_CONTEXT );
+ }
+
+
+ public Iterator getContexts() {
+ Stack stack = _traversalContext;
+ return getTopDownIterator( stack );
+ }
+
+
+ public Object getRootContext() {
+ return _traversalContext.firstElement();
+ }
+
+
+ private Iterator getTopDownIterator( final Stack stack ) {
+ return new Iterator() {
+ private ListIterator _forwardIterator = stack.listIterator( stack.size() );
+
+ public boolean hasNext() {
+ return _forwardIterator.hasPrevious();
+ }
+
+ public Object next() {
+ return _forwardIterator.previous();
+ }
+
+ public void remove() {
+ _forwardIterator.remove();
+ }
+ };
+ }
+
+
+ /**
+ * Returns the most recently pushed context which implements the specified class.
+ * Will return null if no matching context is found.
+ */
+ public Object getClosestContext( Class matchingClass ) {
+ for (int i = _traversalContext.size()-1; i >= 0; i-- ) {
+ Object o = _traversalContext.elementAt( i );
+ if (matchingClass.isInstance(o)) return o;
+ }
+ return null;
+ }
+
+
+ public void perform( NodeAction action ) {
+ while (!_pendingNodes.empty()) {
+ final Object object = _pendingNodes.pop();
+ if (object == POP_CONTEXT) {
+ _traversalContext.pop();
+ } else {
+ Node node = (Node) object;
+ if (node.getNodeType() == Node.TEXT_NODE) {
+ action.processTextNode( this, node );
+ } else if (node.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ } else
+ action.processElement( this, (Element) node );
+ pushNodeList( node.getLastChild() );
+ }
+ }
+ }
+
+
+ private void pushNodeList( NodeList nl ) {
+ if (nl != null) {
+ for (int i = nl.getLength()-1; i >= 0; i--) {
+ _pendingNodes.push( nl.item(i) );
+ }
+ }
+ }
+
+
+ private void pushNodeList( Node lastChild ) {
+ for (Node node = lastChild; node != null; node = node.getPreviousSibling()) { _pendingNodes.push( node ); }
+ }
+ }
+
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/NotHTMLException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/NotHTMLException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/NotHTMLException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,35 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2002, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+class NotHTMLException extends RuntimeException {
+
+ NotHTMLException( String contentType ) {
+ _contentType = contentType;
+ }
+
+
+ public String getMessage() {
+ return "The content type of the response is '" + _contentType + "': it must be 'text/html' in order to be recognized as HTML";
+ }
+
+
+ private String _contentType;
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ParameterHolder.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ParameterHolder.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ParameterHolder.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,111 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.protocol.UploadFileSpec;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+import com.meterware.httpunit.protocol.ParameterCollection;
+
+import java.io.IOException;
+
+
+/**
+ * This abstract class is extended by classes which hold parameters for web requests. Note that it is an abstract class
+ * rather than an interface in order to keep its methods package-local.
+ *
+ * @author Russell Gold
+ **/
+abstract class ParameterHolder implements ParameterCollection {
+
+ /**
+ * Specifies the position at which an image button (if any) was clicked. This default implementation does nothing.
+ **/
+ void selectImageButtonPosition( SubmitButton imageButton, int x, int y ) {}
+
+
+ /**
+ * Iterates through the fixed, predefined parameters in this holder, recording them in the supplied parameter processor.\
+ * These parameters always go on the URL, no matter what encoding method is used.
+ **/
+ abstract
+ void recordPredefinedParameters( ParameterProcessor processor ) throws IOException;
+
+
+ /**
+ * Returns an array of all parameter names in this collection.
+ **/
+ abstract
+ String[] getParameterNames();
+
+
+ /**
+ * Returns the multiple default values of the named parameter.
+ **/
+ abstract
+ String[] getParameterValues( String name );
+
+
+ /**
+ * Removes a parameter name from this collection.
+ **/
+ abstract
+ void removeParameter( String name );
+
+
+ /**
+ * Sets the value of a parameter in a web request.
+ **/
+ abstract
+ void setParameter( String name, String value );
+
+
+ /**
+ * Sets the multiple values of a parameter in a web request.
+ **/
+ abstract
+ void setParameter( String name, String[] values );
+
+
+ /**
+ * Sets the multiple values of a file upload parameter in a web request.
+ **/
+ abstract
+ void setParameter( String name, UploadFileSpec[] files );
+
+
+ /**
+ * Returns true if the specified name is that of a file parameter. The default implementation returns false.
+ */
+ boolean isFileParameter( String name ) {
+ return false;
+ }
+
+
+ /**
+ * Returns the character set encoding for the request.
+ **/
+ String getCharacterSet() {
+ return HttpUnitUtils.DEFAULT_CHARACTER_SET;
+ }
+
+
+ abstract
+ boolean isSubmitAsMime();
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ParsedHTML.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ParsedHTML.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ParsedHTML.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,1205 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Document;
+import org.w3c.dom.html.*;
+
+import java.net.URL;
+import java.util.*;
+import java.io.IOException;
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.dom.HTMLContainerElement;
+import com.meterware.httpunit.dom.HTMLDocumentImpl;
+import com.meterware.httpunit.dom.HTMLControl;
+
+/**
+ * @author Russell Gold
+ * @author Benoit Xhenseval
+ **/
+public class ParsedHTML {
+
+ final static private HTMLElement[] NO_ELEMENTS = new HTMLElement[0];
+
+ final static private String[] TEXT_ELEMENTS = { "p", "h1", "h2", "h3", "h4", "h5", "h6" };
+
+ private Node _rootNode;
+
+ private URL _baseURL;
+
+ private FrameSelector _frame;
+
+ private String _baseTarget;
+
+ private String _characterSet;
+
+ private WebResponse _response;
+
+ private boolean _updateElements = true;
+
+ private boolean _enableNoScriptNodes;
+
+ /** map of element IDs to elements. **/
+ private HashMap _elementsByID = new HashMap();
+
+ /** map of element names to lists of elements. **/
+ private HashMap _elementsByName = new HashMap();
+
+ /** map of DOM elements to HTML elements **/
+ private ElementRegistry _registry = new ElementRegistry();
+
+ private ArrayList _blocksList = new ArrayList();
+ private TextBlock[] _blocks;
+
+ private ArrayList _tableList = new ArrayList();
+ private WebTable[] _tables;
+
+ private ArrayList _frameList = new ArrayList();
+ private WebFrame[] _frames;
+
+
+
+ ParsedHTML( WebResponse response, FrameSelector frame, URL baseURL, String baseTarget, Node rootNode, String characterSet ) {
+ _response = response;
+ _frame = frame;
+ _baseURL = baseURL;
+ _baseTarget = baseTarget;
+ _rootNode = rootNode;
+ _characterSet = characterSet;
+ }
+
+
+ /**
+ * Returns the forms found in the page in the order in which they appear.
+ *
+ * @return an array of objects representing the forms in the page or portion of a page.
+ **/
+ public WebForm[] getForms() {
+ HTMLCollection forms = ((HTMLContainerElement) _rootNode).getForms();
+ WebForm[] result = new WebForm[ forms.getLength() ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = getWebForm( forms.item( i ) );
+ }
+ return result;
+ }
+
+
+ private WebForm getWebForm( Node node ) {
+ WebForm webForm = (WebForm) _registry.getRegisteredElement( node );
+ return webForm != null ? webForm : (WebForm) _registry.registerElement( node, toWebForm( (Element) node ) );
+ }
+
+
+ /**
+ * Returns the links found in the page in the order in which they appear.
+ **/
+ public WebLink[] getLinks() {
+ HTMLCollection links = ((HTMLContainerElement) _rootNode).getLinks();
+ WebLink[] result = new WebLink[ links.getLength() ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (WebLink) _registry.getRegisteredElement( links.item( i ) );
+ if (result[i] == null) {
+ result[i] = new WebLink( _response, _baseURL, links.item( i ), _frame, _baseTarget, _characterSet );
+ _registry.registerElement( links.item( i ), result[i] );
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns a proxy for each applet found embedded in this page.
+ */
+ public WebApplet[] getApplets() {
+ HTMLCollection applets = ((HTMLContainerElement) _rootNode).getApplets();
+ WebApplet[] result = new WebApplet[ applets.getLength() ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (WebApplet) _registry.getRegisteredElement( applets.item( i ) );
+ if (result[i] == null) {
+ result[i] = new WebApplet( _response, (HTMLAppletElement) applets.item( i ), _baseTarget );
+ _registry.registerElement( applets.item( i ), result[i] );
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the images found in the page in the order in which they appear.
+ */
+ public WebImage[] getImages() {
+ HTMLCollection images = ((HTMLContainerElement) _rootNode).getImages();
+ WebImage[] result = new WebImage[ images.getLength() ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (WebImage) _registry.getRegisteredElement( images.item( i ) );
+ if (result[i] == null) {
+ result[i] = new WebImage( _response, this, _baseURL, (HTMLImageElement) images.item( i ), _frame, _baseTarget, _characterSet );
+ _registry.registerElement( images.item( i ), result[i] );
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the top-level block elements found in the page in the order in which they appear.
+ */
+ public TextBlock[] getTextBlocks() {
+ if (_blocks == null) {
+ loadElements();
+ _blocks = (TextBlock[]) _blocksList.toArray( new TextBlock[ _blocksList.size() ] );
+ }
+ return _blocks;
+ }
+
+
+ /**
+ * Returns the first text block found in the page which matches the specified predicate and value.
+ */
+ public TextBlock getFirstMatchingTextBlock( HTMLElementPredicate predicate, Object criteria ) {
+ TextBlock[] blocks = getTextBlocks();
+ for (int i = 0; i < blocks.length; i++) {
+ if (predicate.matchesCriteria( blocks[i], criteria )) return blocks[i];
+ }
+ return null;
+ }
+
+
+ public TextBlock getNextTextBlock( TextBlock block ) {
+ int index = _blocksList.indexOf( block );
+ if (index < 0 || index == _blocksList.size() - 1) return null;
+ return (TextBlock) _blocksList.get( index+1 );
+ }
+
+
+ /**
+ * Returns the top-level tables found in the page in the order in which they appear.
+ **/
+ public WebTable[] getTables() {
+ if (_tables == null) {
+ loadElements();
+ _tables = (WebTable[]) _tableList.toArray( new WebTable[ _tableList.size() ] );
+ }
+ return _tables;
+ }
+
+
+ /**
+ * Returns the HTMLElement with the specified ID.
+ */
+ public HTMLElement getElementWithID( String id ) {
+ return (HTMLElement) getElementWithID( id, HTMLElement.class );
+ }
+
+
+ /**
+ * Returns the HTML elements with the specified name.
+ */
+ public HTMLElement[] getElementsWithName( String name ) {
+ loadElements();
+ ArrayList elements = (ArrayList) _elementsByName.get( name );
+ return elements == null ? NO_ELEMENTS : (HTMLElement[]) elements.toArray( new HTMLElement[ elements.size() ] );
+ }
+
+
+ /**
+ * Returns the HTML elements with an attribute with the specified name and value.
+ * @param name - the name of the attribute to check
+ * @param value - the value of the attribute to check
+ */
+ public HTMLElement[] getElementsWithAttribute( String name, String value ) {
+ loadElements();
+ ArrayList elements = new ArrayList();
+ for (Iterator i = _registry.iterator(); i.hasNext();) {
+ HTMLElement element = (HTMLElement) i.next();
+ String aValue=element.getAttribute( name );
+ if (value.equals(aValue )) {
+ //System.err.println(element.getTagName()+"("+name+")="+aValue);
+ elements.add( element );
+ }
+ }
+ return (HTMLElement[]) elements.toArray( new HTMLElement[ elements.size() ] );
+ }
+
+
+ /**
+ * Returns a list of HTML element names contained in this HTML section.
+ */
+ public String[] getElementNames() {
+ loadElements();
+ return (String[]) _elementsByName.keySet().toArray( new String[ _elementsByName.size() ] );
+ }
+
+
+ /**
+ * get the elements with the given tagname
+ * @param dom - the node to start from
+ * @param name - the name of the attribute to look for
+ * @return
+ */
+ HTMLElement[] getElementsByTagName( Node dom, String name ) {
+ loadElements();
+ if (dom instanceof Element) {
+ return getElementsFromList( ((Element) dom).getElementsByTagName( name ) );
+ } else {
+ return getElementsFromList( ((Document) dom).getElementsByTagName( name ) );
+ }
+ }
+
+
+ private HTMLElement[] getElementsFromList( NodeList nl ) {
+ HTMLElement[] elements = new HTMLElement[ nl.getLength() ];
+ for (int i = 0; i < elements.length; i++) {
+ Node node = nl.item(i);
+ elements[i] = (HTMLElement) _registry.getRegisteredElement( node );
+ if (elements[i] == null) {
+ elements[i] = toDefaultElement( (Element) node );
+ _registry.registerElement( node, elements[i] );
+ }
+ }
+ return elements;
+ }
+
+
+ /**
+ * Returns the form found in the page with the specified ID.
+ **/
+ public WebForm getFormWithID( String id ) {
+ return (WebForm) getElementWithID( id, WebForm.class );
+ }
+
+
+ /**
+ * Returns the link found in the page with the specified ID.
+ **/
+ public WebLink getLinkWithID( String id ) {
+ return (WebLink) getElementWithID( id, WebLink.class );
+
+ }
+
+
+ private Object getElementWithID( String id, final Class klass ) {
+ loadElements();
+ return whenCast( _elementsByID.get( id ), klass );
+ }
+
+
+ private Object whenCast( Object o, Class klass ) {
+ return klass.isInstance( o ) ? o : null;
+ }
+
+
+ /**
+ * Returns the first link found in the page matching the specified criteria.
+ **/
+ public WebForm getFirstMatchingForm( HTMLElementPredicate predicate, Object criteria ) {
+ WebForm[] forms = getForms();
+ for (int i = 0; i < forms.length; i++) {
+ if (predicate.matchesCriteria( forms[i], criteria )) return forms[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns all links found in the page matching the specified criteria.
+ **/
+ public WebForm[] getMatchingForms( HTMLElementPredicate predicate, Object criteria ) {
+ ArrayList matches = new ArrayList();
+ WebForm[] forms = getForms();
+ for (int i = 0; i < forms.length; i++) {
+ if (predicate.matchesCriteria( forms[i], criteria )) matches.add( forms[i] );
+ }
+ return (WebForm[]) matches.toArray( new WebForm[ matches.size() ] );
+ }
+
+
+ /**
+ * Returns the form found in the page with the specified name.
+ **/
+ public WebForm getFormWithName( String name ) {
+ return getFirstMatchingForm( WebForm.MATCH_NAME, name );
+ }
+
+
+ /**
+ * interpret the given script element
+ * @param element
+ */
+ void interpretScriptElement( Element element ) {
+ // proposed patch 1152036
+ // not enabled by wf@bitplan.com since it would brake
+ // com.meterware.httpunit.javascript.NekoEnhancedScriptingTest - testNoScriptSections
+ //if (!HttpUnitOptions.isScriptingEnabled()) {
+ // return;
+ //}
+ String script = getScript( element );
+ if (script != null) {
+ try {
+ _updateElements = false;
+ String language = NodeUtils.getNodeAttribute( element, "language", null );
+ if (!getResponse().getScriptingHandler().supportsScriptLanguage( language ))
+ _enableNoScriptNodes = true;
+ getResponse().getScriptingHandler().runScript( language, script );
+ } finally {
+ clearCaches();
+ }
+ }
+ }
+
+
+ /**
+ * get the script for the given node
+ * @param scriptNode
+ * @return the script
+ */
+ private String getScript( Node scriptNode ) {
+ String scriptLocation = NodeUtils.getNodeAttribute( scriptNode, "src", null );
+ if (scriptLocation == null) {
+ return NodeUtils.asText( scriptNode.getChildNodes() );
+ } else {
+ try {
+ return getIncludedScript( scriptLocation );
+ } catch (IOException e) {
+ throw new RuntimeException( "Error loading included script: " + e );
+ }
+ }
+ }
+
+
+ /**
+ * Returns the contents of an included script, given its src attribute.
+ * @param srcAttribute the location of the script.
+ * @return the contents of the script.
+ * @throws java.io.IOException if there is a problem retrieving the script
+ */
+ String getIncludedScript( String srcAttribute ) throws IOException {
+ WebRequest req = new GetMethodWebRequest( getBaseURL(), srcAttribute );
+ WebWindow window = getResponse().getWindow();
+ if (window == null) throw new IllegalStateException( "Unable to retrieve script included by this response, since it was loaded by getResource(). Use getResponse() instead.");
+ return window.getResource( req ).getText();
+ }
+
+
+ /**
+ * If noscript node content is enabled, returns null - otherwise returns a concealing element.
+ */
+ private HTMLElement toNoscriptElement( Element element ) {
+ HTMLElement result=null;
+ if (!_enableNoScriptNodes)
+ result=new NoScriptElement( element );
+ return result;
+ }
+
+
+ static class HtmlElementRecorder {
+
+ protected void recordHtmlElement( NodeUtils.PreOrderTraversal pot, Node node, HTMLElement htmlElement ) {
+ if (htmlElement != null) {
+ addToMaps( pot, node, htmlElement );
+ addToLists( pot, htmlElement );
+ }
+ }
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ for (Iterator i = pot.getContexts(); i.hasNext();) {
+ Object o = i.next();
+ if (o instanceof ParsedHTML) ((ParsedHTML) o).addToList( htmlElement );
+ }
+ }
+
+ protected void addToMaps( NodeUtils.PreOrderTraversal pot, Node node, HTMLElement htmlElement ) {
+ for (Iterator i = pot.getContexts(); i.hasNext();) {
+ Object o = i.next();
+ if (o instanceof ParsedHTML) ((ParsedHTML) o).addToMaps( node, htmlElement );
+ }
+ }
+
+ }
+
+
+ abstract static class HTMLElementFactory extends HtmlElementRecorder {
+ abstract HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element );
+
+ void recordElement( NodeUtils.PreOrderTraversal pot, Element element, ParsedHTML parsedHTML ) {
+ HTMLElement htmlElement = toHTMLElement( pot, parsedHTML, element );
+ recordHtmlElement( pot, element, htmlElement );
+ }
+
+ protected boolean isRecognized( ClientProperties properties ) { return true; }
+ protected boolean addToContext() { return false; }
+
+ final protected ParsedHTML getParsedHTML( NodeUtils.PreOrderTraversal pot ) {
+ return (ParsedHTML) getClosestContext( pot, ParsedHTML.class );
+ }
+
+ final protected Object getClosestContext( NodeUtils.PreOrderTraversal pot, Class aClass ) {
+ return pot.getClosestContext( aClass );
+ }
+
+ protected ParsedHTML getRootContext( NodeUtils.PreOrderTraversal pot ) {
+ return (ParsedHTML) pot.getRootContext();
+ }
+ }
+
+
+ static class DefaultElementFactory extends HTMLElementFactory {
+
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ // [ 1531005 ] getElementsWithAttribute **FIX**
+ //if (element.getAttribute( "id" ).equals( "" )) {
+ // return null;
+ //}
+ return parsedHTML.toDefaultElement( element );
+ }
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {}
+ }
+
+
+ private HTMLElement toDefaultElement( Element element ) {
+ return new HTMLElementBase( element ) {
+ public ScriptableDelegate newScriptable() { return new HTMLElementScriptable( this ); }
+ public ScriptableDelegate getParentDelegate() { return getResponse().getDocumentScriptable(); }
+ };
+ }
+
+
+ static class WebFormFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebForm( element );
+ }
+ }
+
+
+ static class WebLinkFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toLinkAnchor( element );
+ }
+ }
+
+
+ static class TextBlockFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toTextBlock( element );
+ }
+
+
+ protected boolean addToContext() {
+ return true;
+ }
+
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ for (Iterator i = pot.getContexts(); i.hasNext();) {
+ Object o = i.next();
+ if (!(o instanceof ParsedHTML)) continue;
+ ((ParsedHTML) o).addToList( htmlElement );
+ break;
+ }
+ }
+
+ }
+
+
+ static class ScriptFactory extends HTMLElementFactory {
+
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return null;
+ }
+
+ void recordElement( NodeUtils.PreOrderTraversal pot, Element element, ParsedHTML parsedHTML ) {
+ parsedHTML.interpretScriptElement( element );
+ }
+ }
+
+
+ static class NoScriptFactory extends HTMLElementFactory {
+
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toNoscriptElement( element );
+ }
+
+ protected boolean addToContext() {
+ return true;
+ }
+ }
+
+
+ static class WebFrameFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebFrame( element );
+ }
+ }
+
+
+ static class WebIFrameFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebIFrame( element );
+ }
+
+
+ protected boolean isRecognized( ClientProperties properties ) {
+ return properties.isIframeSupported();
+ }
+
+
+ protected boolean addToContext() {
+ return true;
+ }
+ }
+
+
+ static class WebImageFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebImage( element );
+ }
+ }
+
+
+ static class WebAppletFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebApplet( element );
+ }
+ protected boolean addToContext() { return true; }
+ }
+
+
+ static class WebTableFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toWebTable( element );
+ }
+ protected boolean addToContext() { return true; }
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ for (Iterator i = pot.getContexts(); i.hasNext();) {
+ Object o = i.next();
+ if (o instanceof ParsedHTML) ((ParsedHTML) o).addToList( htmlElement );
+ if (o instanceof TableCell) break;
+ }
+ }
+ }
+
+
+ static class TableRowFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ WebTable wt = getWebTable( pot );
+ if (wt == null) return null;
+ return wt.newTableRow( (HTMLTableRowElement) element );
+ }
+ private WebTable getWebTable( NodeUtils.PreOrderTraversal pot ) {
+ return (WebTable) getClosestContext( pot, WebTable.class );
+ }
+ protected boolean addToContext() { return true; }
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ getWebTable( pot ).addRow( (TableRow) htmlElement );
+ }
+ }
+
+
+ static class TableCellFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ TableRow tr = getTableRow( pot );
+ if (tr == null) return null;
+ return tr.newTableCell( (HTMLTableCellElement) element );
+ }
+ private TableRow getTableRow( NodeUtils.PreOrderTraversal pot ) {
+ return (TableRow) getClosestContext( pot, TableRow.class );
+ }
+ protected boolean addToContext() { return true; }
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ getTableRow( pot ).addTableCell( (TableCell) htmlElement );
+ }
+ }
+
+ static class FormControlFactory extends HTMLElementFactory {
+
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ HTMLFormElement form = ((HTMLControl) element).getForm();
+ if (form == null) {
+ return newControlWithoutForm( parsedHTML, element );
+ } else {
+ return parsedHTML.getWebForm( form ).newFormControl( element );
+ }
+ }
+
+ private HTMLElement newControlWithoutForm( ParsedHTML parsedHTML, Element element ) {
+ if ((element.getNodeName().equalsIgnoreCase( "button" ) || element.getNodeName().equalsIgnoreCase( "input" )) &&
+ isValidNonFormButtonType( NodeUtils.getNodeAttribute( element, "type" ) )) {
+ return parsedHTML.toButtonWithoutForm( element );
+ } else {
+ return null;
+ }
+ }
+
+
+ private boolean isValidNonFormButtonType( String buttonType ) {
+ return buttonType.equals( "" ) || buttonType.equalsIgnoreCase( "button" );
+ }
+ }
+
+
+ static class WebListFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ return parsedHTML.toOrderedList( element );
+ }
+
+ protected boolean addToContext() { return true; }
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ TextBlock textBlock = getTextBlock( pot );
+ if (textBlock != null) textBlock.addList( (WebList) htmlElement );
+ }
+
+ private TextBlock getTextBlock( NodeUtils.PreOrderTraversal pot ) {
+ return (TextBlock) getClosestContext( pot, TextBlock.class );
+ }
+ }
+
+
+ static class ListItemFactory extends HTMLElementFactory {
+ HTMLElement toHTMLElement( NodeUtils.PreOrderTraversal pot, ParsedHTML parsedHTML, Element element ) {
+ WebList webList = getWebList( pot );
+ if (webList == null) return null;
+ return webList.addNewItem( element );
+ }
+
+ private WebList getWebList( NodeUtils.PreOrderTraversal pot ) {
+ return (WebList) getClosestContext( pot, WebList.class );
+ }
+
+ protected boolean addToContext() { return true; }
+
+ protected void addToLists( NodeUtils.PreOrderTraversal pot, HTMLElement htmlElement ) {
+ }
+ }
+
+
+ private static HashMap _htmlFactoryClasses = new HashMap();
+ private static HTMLElementFactory _defaultFactory = new DefaultElementFactory();
+
+ static {
+ _htmlFactoryClasses.put( "a", new WebLinkFactory() );
+ _htmlFactoryClasses.put( "area", new WebLinkFactory() );
+ _htmlFactoryClasses.put( "form", new WebFormFactory() );
+ _htmlFactoryClasses.put( "img", new WebImageFactory() );
+ _htmlFactoryClasses.put( "applet", new WebAppletFactory() );
+ _htmlFactoryClasses.put( "table", new WebTableFactory() );
+ _htmlFactoryClasses.put( "tr", new TableRowFactory() );
+ _htmlFactoryClasses.put( "td", new TableCellFactory() );
+ _htmlFactoryClasses.put( "th", new TableCellFactory() );
+ _htmlFactoryClasses.put( "frame", new WebFrameFactory() );
+ _htmlFactoryClasses.put( "iframe", new WebIFrameFactory() );
+ _htmlFactoryClasses.put( "script", new ScriptFactory() );
+ _htmlFactoryClasses.put( "noscript", new NoScriptFactory() );
+ _htmlFactoryClasses.put( "ol", new WebListFactory() );
+ _htmlFactoryClasses.put( "ul", new WebListFactory() );
+ _htmlFactoryClasses.put( "li", new ListItemFactory() );
+
+ for (int i = 0; i < TEXT_ELEMENTS.length; i++) {
+ _htmlFactoryClasses.put( TEXT_ELEMENTS[i], new TextBlockFactory() );
+ }
+
+ for (Iterator i = Arrays.asList( FormControl.getControlElementTags() ).iterator(); i.hasNext();) {
+ _htmlFactoryClasses.put( i.next(), new FormControlFactory() );
+ }
+ }
+
+ private static HTMLElementFactory getHTMLElementFactory( String tagName ) {
+ final HTMLElementFactory factory = (HTMLElementFactory) _htmlFactoryClasses.get( tagName );
+ return factory != null ? factory : _defaultFactory;
+ }
+
+
+ private void loadElements() {
+ if (!_updateElements) return;
+
+ NodeUtils.NodeAction action = new NodeUtils.NodeAction() {
+ public boolean processElement( NodeUtils.PreOrderTraversal pot, Element element ) {
+ HTMLElementFactory factory = getHTMLElementFactory( element.getNodeName().toLowerCase() );
+ if (factory == null || !factory.isRecognized( getClientProperties() )) return true;
+ if (pot.getClosestContext( ContentConcealer.class ) != null) return true;
+
+ if (!_registry.hasNode( element )) factory.recordElement( pot, element, ParsedHTML.this );
+ if (factory.addToContext()) pot.pushContext( _registry.getRegisteredElement( element ) );
+
+ return true;
+ }
+ public void processTextNode( NodeUtils.PreOrderTraversal pot, Node textNode ) {
+ if (textNode.getNodeValue().trim().length() == 0) return;
+
+ Node parent = textNode.getParentNode();
+ if (!parent.getNodeName().equalsIgnoreCase( "body" )) return;
+ if (pot.getClosestContext( ContentConcealer.class ) != null) return;
+ new HtmlElementRecorder().recordHtmlElement( pot, textNode, newTextBlock( textNode ) );
+ }
+ };
+ NodeUtils.PreOrderTraversal nt = new NodeUtils.PreOrderTraversal( getRootNode() );
+ nt.pushBaseContext( this );
+ nt.perform( action );
+
+ _updateElements = false;
+ }
+
+
+ private ClientProperties getClientProperties() {
+ WebWindow window = _response.getWindow();
+ return window == null ? ClientProperties.getDefaultProperties() : window.getClient().getClientProperties();
+ }
+
+
+ private Button toButtonWithoutForm( Element element ) {
+ return new Button( _response, (HTMLControl) element );
+ }
+
+
+ private WebForm toWebForm( Element element ) {
+ return new WebForm( _response, _baseURL, element, _frame, _baseTarget, _characterSet, _registry );
+ }
+
+
+ private WebFrame toWebFrame( Element element ) {
+ return new WebFrame( _response, _baseURL, element, _frame );
+ }
+
+
+ private WebFrame toWebIFrame( Element element ) {
+ return new WebIFrame( _baseURL, element, _frame );
+ }
+
+
+ /**
+ * convert the given child to a link anchor
+ * @param child
+ * @return
+ */
+ private WebLink toLinkAnchor( Element child ) {
+ return (!isWebLink( child )) ? null : new WebLink( _response, _baseURL, child, _frame, _baseTarget, _characterSet );
+ }
+
+
+ /**
+ * check whether the given node is a Web link by checking that
+ * the node is of type "A"
+ * @param node - the node to check
+ * @return whether the given node represents a web link
+ */
+ public static boolean isWebLink( Node node ) {
+ /*
+ * Bug report [ 1156972 ] isWebLink doesn't recognize all anchor tags
+ * by fregienj claims this be changed to check whether the case-insensitive node name is "A"
+ * -> should be isAnchor method and getAnchor
+ */
+ boolean result=false;
+ String tagName = ((Element) node).getTagName();
+ if (!tagName.equalsIgnoreCase( "area" ) && !tagName.equalsIgnoreCase( "a")) {
+ } else {
+ // pre 1.7 code - still active
+ result=(node.getAttributes().getNamedItem( "href" ) != null);
+ // proposed patch - not activated
+ // result=true;
+ }
+ return result;
+ }
+
+
+ private WebImage toWebImage( Element child ) {
+ return new WebImage( _response, this, _baseURL, (HTMLImageElement) child, _frame, _baseTarget, _characterSet );
+ }
+
+
+ private WebApplet toWebApplet( Element element ) {
+ return new WebApplet( _response, (HTMLAppletElement) element, _baseTarget );
+ }
+
+
+ private WebTable toWebTable( Element element ) {
+ return new WebTable( _response, _frame, element, _baseURL, _baseTarget, _characterSet );
+ }
+
+
+ private TextBlock toTextBlock( Element element ) {
+ return new TextBlock( _response, _frame, _baseURL, _baseTarget, element, _characterSet );
+ }
+
+
+ private TextBlock newTextBlock( Node textNode ) {
+ return new TextBlock( _response, _frame, _baseURL, _baseTarget, textNode, _characterSet );
+ }
+
+
+ private WebList toOrderedList( Element element ) {
+ return new WebList( _response, _frame, _baseURL, _baseTarget, element, _characterSet );
+ }
+
+
+ private void addToMaps( Node node, HTMLElement htmlElement ) {
+ _registry.registerElement( node, htmlElement );
+ if (htmlElement.getID() != null) _elementsByID.put( htmlElement.getID(), htmlElement );
+ if (htmlElement.getName() != null) addNamedElement( htmlElement.getName(), htmlElement );
+ }
+
+
+ private void addNamedElement( String name, HTMLElement htmlElement ) {
+ List list = (List) _elementsByName.get( name );
+ if (list == null) _elementsByName.put( name, list = new ArrayList() );
+ list.add( htmlElement );
+ }
+
+
+ private void addToList( HTMLElement htmlElement ) {
+ ArrayList list = getListForElement( htmlElement );
+ if (list != null) list.add( htmlElement );
+ }
+
+
+ private ArrayList getListForElement( HTMLElement element ) {
+ if (element instanceof WebTable) return _tableList;
+ if (element instanceof WebFrame) return _frameList;
+ if (element instanceof BlockElement) return _blocksList;
+ return null;
+ }
+
+
+ /**
+ * Returns the first link which contains the specified text.
+ **/
+ public WebLink getLinkWith( String text ) {
+ return getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, text );
+ }
+
+
+ /**
+ * Returns the link which contains the first image with the specified text as its 'alt' attribute.
+ **/
+ public WebLink getLinkWithImageText( String text ) {
+ WebImage image = getImageWithAltText( text );
+ return image == null ? null : image.getLink();
+ }
+
+
+ /**
+ * Returns the link found in the page with the specified name.
+ **/
+ public WebLink getLinkWithName( String name ) {
+ return getFirstMatchingLink( WebLink.MATCH_NAME, name );
+ }
+
+
+ /**
+ * Returns the first link found in the page matching the specified criteria.
+ **/
+ public WebLink getFirstMatchingLink( HTMLElementPredicate predicate, Object criteria ) {
+ WebLink[] links = getLinks();
+ for (int i = 0; i < links.length; i++) {
+ if (predicate.matchesCriteria( links[i], criteria )) return links[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns all links found in the page matching the specified criteria.
+ **/
+ public WebLink[] getMatchingLinks( HTMLElementPredicate predicate, Object criteria ) {
+ ArrayList matches = new ArrayList();
+ WebLink[] links = getLinks();
+ for (int i = 0; i < links.length; i++) {
+ if (predicate.matchesCriteria( links[i], criteria )) matches.add( links[i] );
+ }
+ return (WebLink[]) matches.toArray( new WebLink[ matches.size() ] );
+ }
+
+
+ /**
+ * Returns the image found in the page with the specified name.
+ **/
+ public WebImage getImageWithName( String name ) {
+ WebImage[] images = getImages();
+ for (int i = 0; i < images.length; i++) {
+ if (HttpUnitUtils.matches( name, images[i].getName() )) return images[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the first image found in the page with the specified src attribute.
+ **/
+ public WebImage getImageWithSource( String source ) {
+ WebImage[] images = getImages();
+ for (int i = 0; i < images.length; i++) {
+ if (HttpUnitUtils.matches( source, images[i].getSource() )) return images[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the first image found in the page with the specified alt attribute.
+ **/
+ public WebImage getImageWithAltText( String altText ) {
+ WebImage[] images = getImages();
+ for (int i = 0; i < images.length; i++) {
+ if (HttpUnitUtils.matches( altText, images[i].getAltText() )) return images[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the first table in the response which matches the specified predicate and value.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getFirstMatchingTable( HTMLElementPredicate predicate, Object criteria ) {
+ return getTableSatisfyingPredicate( getTables(), predicate, criteria );
+ }
+
+ /**
+ * Returns the tables in the response which match the specified predicate and value.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected tables, or null if none are found
+ **/
+ public WebTable[] getMatchingTables( HTMLElementPredicate predicate, Object criteria ) {
+ return getTablesSatisfyingPredicate( getTables(), predicate, criteria );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as the full text of
+ * its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableStartingWith( String text ) {
+ return getFirstMatchingTable( WebTable.MATCH_FIRST_NONBLANK_CELL, text );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as a prefix of the text
+ * in its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableStartingWithPrefix( String text ) {
+ return getFirstMatchingTable( WebTable.MATCH_FIRST_NONBLANK_CELL_PREFIX, text );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as its summary attribute.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableWithSummary( String summary ) {
+ return getFirstMatchingTable( WebTable.MATCH_SUMMARY, summary );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as its ID attribute.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableWithID( String ID ) {
+ return getFirstMatchingTable( WebTable.MATCH_ID, ID );
+ }
+
+
+ /**
+ * Returns a copy of the domain object model associated with this page.
+ **/
+ public Node getDOM() {
+ return getRootNode().cloneNode( /* deep */ true );
+ }
+
+//---------------------------------- Object methods --------------------------------
+
+
+ public String toString() {
+ return _baseURL.toExternalForm() + System.getProperty( "line.separator" ) +
+ _rootNode;
+ }
+
+
+//---------------------------------- package members --------------------------------
+
+
+ /**
+ * Specifies the root node for this HTML fragment. It will be either an HTMLDocument or an HTMLElement
+ * representing a page fragment.
+ */
+ void setRootNode( Node rootNode ) {
+ if (_rootNode != null && rootNode != _rootNode )
+ throw new IllegalStateException( "The root node has already been defined as " + _rootNode + " and cannot be redefined as " + rootNode );
+ _rootNode = rootNode;
+ if (rootNode instanceof HTMLDocumentImpl) ((HTMLDocumentImpl) rootNode).setIFramesEnabled( getClientProperties().isIframeSupported());
+ clearCaches();
+ }
+
+
+ private void clearCaches() {
+ _tables = null;
+ _frames = null;
+ _blocks = null;
+ _updateElements = true;
+ }
+
+
+ /**
+ * Returns the base URL for this HTML segment.
+ **/
+ URL getBaseURL() {
+ return _baseURL;
+ }
+
+
+ WebResponse getResponse() {
+ return _response;
+ }
+
+
+ /**
+ * Returns the domain object model associated with this page, to be used internally.
+ **/
+ Node getOriginalDOM() {
+ return getRootNode();
+ }
+
+
+ HTMLElement getElement( Node node ) {
+ return (HTMLElement) _registry.getRegisteredElement( node );
+ }
+
+
+ /**
+ * Returns the frames found in the page in the order in which they appear.
+ **/
+ public WebFrame[] getFrames() {
+ if (_frames == null) {
+ loadElements();
+ _frames = (WebFrame[]) _frameList.toArray( new WebFrame[ _frameList.size() ] );
+ }
+ return _frames;
+ }
+
+
+//---------------------------------- private members --------------------------------
+
+
+ Node getRootNode() {
+ if (_rootNode == null) throw new IllegalStateException( "The root node has not been specified" );
+ return _rootNode;
+ }
+
+
+ /**
+ * Returns the table with the specified text in its summary attribute.
+ **/
+ private WebTable getTableSatisfyingPredicate( WebTable[] tables, HTMLElementPredicate predicate, Object value ) {
+ for (int i = 0; i < tables.length; i++) {
+ if (predicate.matchesCriteria( tables[i], value )) {
+ return tables[i];
+ } else {
+ for (int j = 0; j < tables[i].getRowCount(); j++) {
+ for (int k = 0; k < tables[i].getColumnCount(); k++) {
+ TableCell cell = tables[i].getTableCell(j,k);
+ if (cell != null) {
+ WebTable[] innerTables = cell.getTables();
+ if (innerTables.length != 0) {
+ WebTable result = getTableSatisfyingPredicate( innerTables, predicate, value );
+ if (result != null) return result;
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the tables which match the specified criteria.
+ **/
+ private WebTable[] getTablesSatisfyingPredicate(WebTable[] tables, HTMLElementPredicate predicate, Object value) {
+ ArrayList matches = new ArrayList();
+ for (int i = 0; i < tables.length; i++) {
+ if (predicate.matchesCriteria(tables[i], value)) {
+ matches.add(tables[i]);
+ }
+ for (int j = 0; j < tables[i].getRowCount(); j++) {
+ for (int k = 0; k < tables[i].getColumnCount(); k++) {
+ TableCell cell = tables[i].getTableCell(j, k);
+ if (cell != null) {
+ WebTable[] innerTables = cell.getTables();
+ if (innerTables.length != 0) {
+ WebTable[] result = getTablesSatisfyingPredicate(innerTables, predicate, value);
+ if (result != null && result.length > 0) {
+ for (int l = 0; l < result.length; l++) {
+ matches.add(result[l]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(matches.size() > 0) {
+ return (WebTable[]) matches.toArray( new WebTable[ matches.size() ] );
+ } else {
+ return null;
+ }
+ }
+
+
+ class WebIFrame extends WebFrame implements ContentConcealer {
+
+ public WebIFrame( URL baseURL, Node frameNode, FrameSelector parentFrame ) {
+ super( _response, baseURL, frameNode, parentFrame );
+ }
+ }
+
+
+ /**
+ * NoScript Element
+ */
+ class NoScriptElement extends HTMLElementBase implements ContentConcealer {
+
+ public NoScriptElement( Node node ) {
+ super( node );
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return null;
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return null;
+ }
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/PostMethodWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/PostMethodWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/PostMethodWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,142 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2002, 2004, 2007 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.protocol.MessageBody;
+import com.meterware.httpunit.protocol.URLEncodedString;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+
+/**
+ * An HTTP request using the POST method.
+ **/
+public class PostMethodWebRequest extends MessageBodyWebRequest {
+
+ /**
+ * Constructs a web request using a specific absolute url string.
+ **/
+ public PostMethodWebRequest( String urlString ) {
+ this( urlString, false );
+ }
+
+
+ /**
+ * Constructs a web request using a specific absolute url string, with optional mime encoding.
+ **/
+ public PostMethodWebRequest( String urlString, boolean mimeEncoded ) {
+ super( urlString, mimeEncoded );
+ }
+
+
+ /**
+ * Constructs a web request with a specific target.
+ **/
+ public PostMethodWebRequest( URL urlBase, String urlString, String target ) {
+ this( urlBase, urlString, target, false );
+ }
+
+
+ /**
+ * Constructs a web request with a specific target, with optional mime encoding.
+ **/
+ public PostMethodWebRequest( URL urlBase, String urlString, String target, boolean mimeEncoded ) {
+ super( urlBase, urlString, target, mimeEncoded );
+ }
+
+
+ /**
+ * Constructs a web request using a specific absolute url string and input stream.
+ * @param urlString the URL to which the request should be issued
+ * @param source an input stream which will provide the body of this request
+ * @param contentType the MIME content type of the body, including any character set
+ **/
+ public PostMethodWebRequest( String urlString, InputStream source, String contentType ) {
+ super( urlString, false );
+ _body = new InputStreamMessageBody( source, contentType );
+ }
+
+
+ /**
+ * Returns the HTTP method defined for this request.
+ **/
+ public String getMethod() {
+ return "POST";
+ }
+
+
+ /**
+ * Returns the query string defined for this request.
+ **/
+ public String getQueryString() {
+ try {
+ URLEncodedString encoder = new URLEncodedString();
+ getParameterHolder().recordPredefinedParameters( encoder );
+ return encoder.getString();
+ } catch (IOException e) {
+ throw new RuntimeException( "Programming error: " + e ); // should never happen
+ }
+ }
+
+
+ /**
+ * Returns true if selectFile may be called with this parameter.
+ */
+ protected boolean maySelectFile( String parameterName ) {
+ return isMimeEncoded() && isFileParameter( parameterName );
+ }
+
+//----------------------------- MessageBodyWebRequest methods ---------------------------
+
+
+ protected MessageBody getMessageBody() {
+ if (_body == null) {
+ _body = MessageBody.createPostMethodMessageBody( isMimeEncoded(), getCharacterSet() );
+ }
+ return _body;
+ }
+
+//----------------------------------- package members -----------------------------------
+
+
+ /**
+ * Constructs a web request for a form submitted by clicking a button.
+ **/
+ PostMethodWebRequest( WebForm sourceForm, SubmitButton button, int x, int y ) {
+ this( sourceForm, sourceForm, button, x, y );
+ }
+
+
+ PostMethodWebRequest( WebForm sourceForm, ParameterHolder parameterHolder, SubmitButton button, int x, int y ) {
+ super( sourceForm, parameterHolder, button, x, y );
+ }
+
+
+ /**
+ * Constructs a web request for a form submitted via a script.
+ **/
+ PostMethodWebRequest( WebForm sourceForm ) {
+ super( sourceForm );
+ }
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/PutMethodWebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/PutMethodWebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/PutMethodWebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,61 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001,2007 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import com.meterware.httpunit.protocol.MessageBody;
+
+import java.io.InputStream;
+
+/**
+ * A web request using the PUT protocol.
+ *
+ * The objectives of this class are to suport an HTTP PUT petition
+ * so we can test this HTTP requests.
+ *
+ * Documentation See the HTTP 1.1 [spec]
+ *
+ * @author Tom Watkins
+ * @author Deepa Dihr
+ * @author Marcos Tarruella
+ * @author Russell Gold
+ *
+ **/
+public class PutMethodWebRequest extends MessageBodyWebRequest {
+
+
+ /**
+ * Constructs a web request using a specific absolute url string and input stream.
+ * @param url the URL to which the request should be issued
+ * @param source an input stream which will provide the body of this request
+ * @param contentType the MIME content type of the body, including any character set
+ **/
+ public PutMethodWebRequest( String url, InputStream source, String contentType ) {
+ super( url, new InputStreamMessageBody( source, contentType ) );
+ }
+
+
+ /**
+ * Returns 'PUT' to indicate the method.
+ **/
+ public String getMethod() {
+ return "PUT";
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/RadioButtonFormControl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/RadioButtonFormControl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/RadioButtonFormControl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,48 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2007, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import com.meterware.httpunit.dom.HTMLInputElementImpl;
+
+public class RadioButtonFormControl extends BooleanFormControl {
+
+ public String getType() {
+ return RADIO_BUTTON_TYPE;
+ }
+
+ public RadioButtonFormControl( WebForm form, HTMLInputElementImpl element ) {
+ super( form, element );
+ }
+
+
+ /**
+ * Returns true if only one control of this kind can have a value.
+ **/
+ public boolean isExclusive() {
+ return true;
+ }
+
+
+ public String getQueryValue() {
+ return getValueAttribute();
+ }
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/RadioGroupFormControl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/RadioGroupFormControl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/RadioGroupFormControl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,164 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2007,2008 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.meterware.httpunit.controls.IllegalParameterValueException;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+/**
+ * Radio button control
+ */
+public class RadioGroupFormControl extends FormControl {
+
+ private List _buttonList = new ArrayList();
+ private RadioButtonFormControl[] _buttons;
+ private String[] _allowedValues;
+
+
+ public String getType() {
+ return UNDEFINED_TYPE;
+ }
+
+ /**
+ * construct Radiobuttons for a form
+ * @param form
+ */
+ public RadioGroupFormControl( WebForm form ) {
+ super( form );
+ }
+
+
+ /**
+ * add a radio button
+ * @param control
+ */
+ void addRadioButton( RadioButtonFormControl control ) {
+ _buttonList.add( control );
+ _buttons = null;
+ _allowedValues = null;
+ }
+
+
+ /**
+ * get the values for the buttons
+ * @return an array of String values
+ */
+ public String[] getValues() {
+ for (int i = 0; i < getButtons().length; i++) {
+ if (getButtons()[i].isChecked()) return getButtons()[i].getValues();
+ }
+ return NO_VALUE;
+ }
+
+
+ /**
+ * Returns the option values defined for this radio button group.
+ **/
+ public String[] getOptionValues() {
+ ArrayList valueList = new ArrayList();
+ FormControl[] buttons = getButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ valueList.addAll( Arrays.asList( buttons[i].getOptionValues() ) );
+ }
+ return (String[]) valueList.toArray( new String[ valueList.size() ] );
+ }
+
+
+ /**
+ * Returns the options displayed for this radio button group.
+ */
+ protected String[] getDisplayedOptions() {
+ ArrayList valueList = new ArrayList();
+ FormControl[] buttons = getButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ valueList.addAll( Arrays.asList( buttons[i].getDisplayedOptions() ) );
+ }
+ return (String[]) valueList.toArray( new String[ valueList.size() ] );
+ }
+
+
+ Object getDelegate() {
+ ScriptableDelegate[] delegates = new ScriptableDelegate[ getButtons().length ];
+ for (int i = 0; i < delegates.length; i++) {
+ delegates[i] = (ScriptableDelegate) getButtons()[i].getScriptingHandler();
+ }
+ return delegates;
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ for (int i = 0; i < getButtons().length; i++) getButtons()[i].addValues( processor, characterSet );
+ }
+
+
+ /**
+ * Remove any required values for this control from the list, throwing an exception if they are missing.
+ **/
+ void claimRequiredValues( List values ) {
+ for (int i = 0; i < getButtons().length; i++) {
+ getButtons()[i].claimRequiredValues( values );
+ }
+ }
+
+
+ protected void claimUniqueValue( List values ) {
+ int matchingButtonIndex = -1;
+ for (int i = 0; i < getButtons().length && matchingButtonIndex < 0; i++) {
+ if (!getButtons()[i].isReadOnly() && values.contains( getButtons()[i].getQueryValue() )) matchingButtonIndex = i;
+ }
+ if (matchingButtonIndex <0) throw new IllegalParameterValueException( getButtons()[0].getName(), values, getAllowedValues() );
+
+ boolean wasChecked = getButtons()[ matchingButtonIndex ].isChecked();
+ for (int i = 0; i < getButtons().length; i++) {
+ if (!getButtons()[i].isReadOnly()) getButtons()[i].setChecked( i == matchingButtonIndex );
+ }
+ values.remove( getButtons()[ matchingButtonIndex ].getQueryValue() );
+ if (!wasChecked) getButtons()[ matchingButtonIndex ].sendOnClickEvent();
+ }
+
+
+ protected void reset() {
+ for (int i = 0; i < getButtons().length; i++) getButtons()[i].reset();
+ }
+
+
+ private String[] getAllowedValues() {
+ if (_allowedValues == null) {
+ _allowedValues = new String[ getButtons().length ];
+ for (int i = 0; i < _allowedValues.length; i++) {
+ _allowedValues[i] = getButtons()[i].getQueryValue();
+ }
+ }
+ return _allowedValues;
+ }
+
+
+ private RadioButtonFormControl[] getButtons() {
+ if (_buttons == null) _buttons = (RadioButtonFormControl[]) _buttonList.toArray( new RadioButtonFormControl[ _buttonList.size() ] );
+ return _buttons;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/RecursiveRedirectionException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/RecursiveRedirectionException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/RecursiveRedirectionException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,98 @@
+package com.meterware.httpunit;
+
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.net.URL;
+
+/**
+ * Class used to indicate when a request to a resource resulted in an HTTP
+ * redirect response that lead to a recursive loop of redirections
+ *
+ * @author James Abley
+ */
+public class RecursiveRedirectionException extends RuntimeException {
+
+ private URL url;
+
+ /**
+ * Create a new RecursiveRedirectionException
with the
+ * specified URL and cause.
+ *
+ * @param url
+ * the {@link URL}that caused the recursive loop to be detected
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()}method). (A null value is permitted, and
+ * indicates that the cause is nonexistent or unknown.)
+ */
+ public RecursiveRedirectionException(URL url, Throwable cause) {
+ super(cause);
+ this.url = url;
+ }
+
+ /**
+ * Create a new RecursiveRedirectionException
with the
+ * specified URL and detail message.
+ *
+ * @param url
+ * the URL
that caused the recursive loop to be
+ * detected. The URL is saved for later retrieval by
+ * {@link #getURL()}
+ * @param message
+ * the detail message. The detail message is saved for later
+ * retrieval by {@link #getMessage()}
+ */
+ public RecursiveRedirectionException(URL url, String message) {
+ super(message);
+ this.url = url;
+ }
+
+ /**
+ * Create a new RecursiveRedirectionException
with the
+ * specified URL, detail message and cause.
+ *
+ * @param url
+ * the URL
that caused the recursive loop to be
+ * detected. The URL is saved for later retrieval by
+ * {@link #getURL()}
+ * @param message
+ * the detail message. The detail message is saved for later
+ * retrieval by {@link #getMessage()}
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()}method). (A null value is permitted, and
+ * indicates that the cause is nonexistent or unknown.)
+ */
+ public RecursiveRedirectionException(URL url, String message,
+ Throwable cause) {
+ super(message, cause);
+ this.url = url;
+ }
+
+ /**
+ * Returns the URL that caused this exception to be thrown.
+ *
+ * @return the URL
that gave rise to this Exception
+ */
+ public URL getURL() {
+ return url;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/RequestContext.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/RequestContext.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/RequestContext.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,47 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.xml.sax.SAXException;
+
+/**
+ * The context for a request which could have subrequests.
+ *
+ * @author Russell Gold
+ **/
+class RequestContext {
+
+ private ArrayList _newResponses = new ArrayList();
+
+ void addNewResponse( WebResponse response ) {
+ _newResponses.add( response );
+ }
+
+
+ void runScripts() throws SAXException {
+ for (Iterator iterator = _newResponses.iterator(); iterator.hasNext();) {
+ WebResponse response = (WebResponse) iterator.next();
+ HttpUnitOptions.getScriptingEngine().load( response );
+ }
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ResetButton.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ResetButton.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ResetButton.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,47 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2003,2007 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.dom.HTMLControl;
+
+
+/**
+ * Represents a form 'reset' button.
+ *
+ * @author Russell Gold
+ **/
+public class ResetButton extends Button {
+
+ public String getType() {
+ return RESET_BUTTON_TYPE;
+ }
+
+ ResetButton( WebForm form, HTMLControl control ) {
+ super( form, control );
+ }
+
+
+ /**
+ * overridden button action
+ */
+ protected void doButtonAction(int x,int y) {
+ getForm().reset();
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/ScriptException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/ScriptException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/ScriptException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,33 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * An exception thrown when there is a problem running a script.
+ *
+ * @author Russell Gold
+ **/
+public class ScriptException extends RuntimeException {
+
+ public ScriptException( String s ) {
+ super( s );
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/SubmitButton.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/SubmitButton.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/SubmitButton.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,265 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, 2007, 2008 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+import com.meterware.httpunit.dom.HTMLControl;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+
+/**
+ * This class represents a submit button in an HTML form.
+ **/
+public class SubmitButton extends Button {
+
+ private boolean _fake;
+
+
+ public String getType() {
+ return (isImageButton()?IMAGE_BUTTON_TYPE:SUBMIT_BUTTON_TYPE);
+ }
+
+ /**
+ * Returns true if this submit button is an image map.
+ **/
+ public boolean isImageButton() {
+ return _isImageButton;
+ }
+
+
+ /**
+ * Performs the action associated with clicking this button after running any 'onClick' script.
+ * For a submit button this typically submits the form.
+ *
+ * @since 1.6
+ */
+ public void click( int x, int y ) throws IOException, SAXException {
+ if (!isImageButton())
+ throw new IllegalStateException( "May only specify positions for an image button" );
+ doOnClickSequence(x,y);
+ }
+
+
+//--------------------------------- Button methods ----------------------------------------------
+
+ /**
+ * do the button Action
+ * @param x - x coordinate
+ * @param y - y coordinate
+ */
+ protected void doButtonAction(int x,int y) throws IOException, SAXException {
+ getForm().doFormSubmit( this ,x,y);
+ }
+
+
+//------------------------------------ Object methods ----------------------------------------
+
+
+ public String toString() {
+ return "Submit with " + getName() + "=" + getValue();
+ }
+
+
+ public int hashCode() {
+ return getName().hashCode() + getValue().hashCode();
+ }
+
+
+ public boolean equals( Object o ) {
+ return getClass().equals( o.getClass() ) && equals( (SubmitButton) o );
+ }
+
+
+//------------------------------------------ package members ----------------------------------
+
+
+ SubmitButton( WebForm form, HTMLControl control ) {
+ super( form, control );
+ _isImageButton = control.getType().equalsIgnoreCase( IMAGE_BUTTON_TYPE );
+ }
+
+
+ SubmitButton( WebForm form ) {
+ super( form );
+ _isImageButton = false;
+ }
+
+
+ static SubmitButton createFakeSubmitButton( WebForm form ) {
+ return new SubmitButton( form, /* fake */ true );
+ }
+
+
+ private SubmitButton( WebForm form, boolean fake ) {
+ this( form );
+ _fake = fake;
+ }
+
+
+ /**
+ * getter for the fake flag
+ * Returns true for synthetic submit buttons, created by HttpUnit in forms that contain no
+ * submit buttons, or used during {@link WebForm#submitNoButton()} call.
+ * @return - whether this button is a faked button inserted by httpunit
+ */
+ public boolean isFake() {
+ return _fake;
+ }
+
+
+ /**
+ * flag that the button was pressed
+ * @param pressed
+ */
+ void setPressed( boolean pressed ) {
+ _pressed = pressed;
+ }
+
+
+ void setLocation( int x, int y ) {
+ _x = x;
+ _y = y;
+ }
+
+
+//--------------------------------- FormControl methods ----------------------------------------------------------------
+
+
+ /**
+ * Returns the current value(s) associated with this control. These values will be transmitted to the server
+ * if the control is 'successful'.
+ **/
+ protected String[] getValues() {
+ return (isDisabled() || !_pressed) ? NO_VALUE : toArray( getValue() );
+ }
+
+ /**
+ * should we allow unnamed Image Buttons?
+ */
+ private static boolean allowUnnamedImageButton=false;
+
+ /**
+ * @return the allowUnnamedImageButton
+ */
+ public static boolean isAllowUnnamedImageButton() {
+ return allowUnnamedImageButton;
+ }
+
+ /**
+ * @param allowUnnamedImageButton the allowUnnamedImageButton to set
+ */
+ public static void setAllowUnnamedImageButton(boolean allowUnnamedImageButton) {
+ SubmitButton.allowUnnamedImageButton = allowUnnamedImageButton;
+ }
+
+
+ /**
+ * return whether this is a validImageButton
+ * @return true if it is an image Button
+ */
+ public boolean isValidImageButton() {
+ String buttonName = getName();
+ boolean valid=this.isImageButton();
+ if (!allowUnnamedImageButton)
+ valid=valid && buttonName != null && buttonName.length() > 0;
+ return valid;
+ }
+
+ /**
+ * return the name of the positionParameter for this button (if this is an image Button)
+ * @param direction e.g. "x" or "y"
+ * @return the name e.g. "image.x" or just "x"
+ */
+ public String positionParameterName(String direction) {
+ // [ 1443333 ] Allow unnamed Image input elments to submit x,y values
+ String buttonName = getName();
+ String buttonPrefix="";
+ if (buttonName != null && buttonName.length() > 0) {
+ buttonPrefix=buttonName+".";
+ }
+ return buttonPrefix+direction;
+ }
+
+ /**
+ * addValues if not disabled and pressed
+ * @param processor - the ParameterProcessor used
+ * @param characterSet - the active character set
+ * @throws IOException if addValues fails
+ */
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ if (_pressed && !isDisabled()) {
+ String buttonName = getName();
+ if (buttonName != null && buttonName.length() > 0 && getValue().length() > 0) {
+ processor.addParameter( getName(), getValue(), characterSet );
+ }
+ if (isValidImageButton()) {
+ processor.addParameter( positionParameterName("x"), Integer.toString( _x ), characterSet );
+ processor.addParameter( positionParameterName("y"), Integer.toString( _y ), characterSet );
+ }
+ } // if
+ }
+
+
+//------------------------------------------ private members ----------------------------------
+
+
+ private String[] _value = new String[1];
+ private final boolean _isImageButton;
+ private boolean _pressed;
+ private int _x;
+ private int _y;
+
+
+ private String[] toArray( String value ) {
+ _value[0] = value;
+ return _value;
+ }
+
+
+ private boolean equals( SubmitButton button ) {
+ return getName().equals( button.getName() ) &&
+ (getName().length() == 0 || getValue().equals( button.getValue() ));
+ }
+
+ public void throwDisabledException() {
+ throw new DisabledSubmitButtonException( this );
+ }
+
+ /**
+ * This exception is thrown on an attempt to define a form request with a button not defined on that form.
+ **/
+ class DisabledSubmitButtonException extends DisabledButtonException {
+
+
+ DisabledSubmitButtonException( SubmitButton button ) {
+ super(button);
+ }
+
+
+ public String getMessage() {
+ return "The specified button (name='" + _name + "' value='" + _value
+ + "' is disabled and may not be used to submit this form.";
+ }
+
+ }
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/TableCell.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/TableCell.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/TableCell.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,73 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import java.net.URL;
+
+import org.w3c.dom.html.HTMLTableCellElement;
+
+
+/**
+ * A single cell in an HTML table.
+ **/
+public class TableCell extends BlockElement {
+
+ private HTMLTableCellElement _element;
+
+
+ /**
+ * Returns the number of columns spanned by this cell.
+ **/
+ public int getColSpan() {
+ return _element.getColSpan();
+ }
+
+
+ /**
+ * Returns the number of rows spanned by this cell.
+ **/
+ public int getRowSpan() {
+ return _element.getRowSpan();
+ }
+
+
+ /**
+ * Returns the text value of this cell.
+ * @deprecated as of 1.6, use #getText()
+ */
+ public String asText() {
+ return getText();
+ }
+
+
+
+
+//---------------------------------------- package methods -----------------------------------------
+
+
+ TableCell( WebResponse response, FrameSelector frame, HTMLTableCellElement element, URL url, String parentTarget, String characterSet ) {
+ super( response, frame, url, parentTarget, element, characterSet );
+ _element = element;
+ }
+
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/TableRow.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/TableRow.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/TableRow.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,71 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2007, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import org.w3c.dom.Element;
+import org.w3c.dom.html.HTMLTableCellElement;
+import org.w3c.dom.html.HTMLTableRowElement;
+
+import java.util.ArrayList;
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+/**
+ * @author Russell Gold
+ */
+public class TableRow extends HTMLElementBase {
+
+ private ArrayList _cells = new ArrayList();
+ private WebTable _webTable;
+ private HTMLTableRowElement _element;
+
+
+ TableRow( WebTable webTable, HTMLTableRowElement element ) {
+ super( element );
+ _element = element;
+ _webTable = webTable;
+ }
+
+
+ TableCell[] getCells() {
+
+ return (TableCell[]) _cells.toArray( new TableCell[ _cells.size() ]);
+ }
+
+
+ TableCell newTableCell( HTMLTableCellElement element ) {
+ return _webTable.newTableCell( element );
+ }
+
+
+ void addTableCell( TableCell cell ) {
+ _cells.add( cell );
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return _webTable.getParentDelegate();
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/TextBlock.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/TextBlock.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/TextBlock.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,81 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.w3c.dom.Node;
+
+import java.net.URL;
+import java.util.ArrayList;
+
+/**
+ * A class which represents a block of text in a web page. Experimental.
+ *
+ * @author Russell Gold
+ * @since 1.6
+ **/
+public class TextBlock extends BlockElement {
+
+ private ArrayList _lists = new ArrayList();
+ /** Predicate to match part or all of a block's class attribute. **/
+ public final static HTMLElementPredicate MATCH_CLASS;
+ /** Predicate to match the tag associated with a block (case insensitive). **/
+ public final static HTMLElementPredicate MATCH_TAG;
+
+
+ public TextBlock( WebResponse response, FrameSelector frame, URL baseURL, String baseTarget, Node rootNode, String characterSet ) {
+ super( response, frame, baseURL, baseTarget, rootNode, characterSet );
+ }
+
+
+ /**
+ * Returns any lists embedded in this text block.
+ */
+ public WebList[] getLists() {
+ return (WebList[]) (_lists.toArray( new WebList[ _lists.size() ] ) );
+ }
+
+
+ void addList( WebList webList ) {
+ _lists.add( webList );
+ }
+
+
+ String[] getFormats( int characterPosition ) {
+ return null;
+ }
+
+
+ static {
+ MATCH_CLASS = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ if (criteria == null) criteria = "";
+ return ((BlockElement) htmlElement).getClassName().equalsIgnoreCase( criteria.toString() );
+ };
+ };
+
+
+ MATCH_TAG = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ if (criteria == null) criteria = "";
+ return criteria.toString().equalsIgnoreCase( ((BlockElement) htmlElement).getTagName() );
+ };
+ };
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/UncheckedParameterHolder.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/UncheckedParameterHolder.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/UncheckedParameterHolder.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,174 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2003, 2007-2008 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.protocol.UploadFileSpec;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+
+import java.io.IOException;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+final class UncheckedParameterHolder extends ParameterHolder implements ParameterProcessor {
+
+ private static final String[] NO_VALUES = new String[ 0 ];
+ private final String _characterSet;
+
+ private Hashtable _parameters = new Hashtable();
+ private boolean _submitAsMime;
+
+
+ UncheckedParameterHolder() {
+ _characterSet = HttpUnitOptions.getDefaultCharacterSet();
+ }
+
+
+ UncheckedParameterHolder( WebRequestSource source ) {
+ _characterSet = source.getCharacterSet();
+ _submitAsMime = source.isSubmitAsMime();
+
+ try {
+ source.recordPredefinedParameters( this );
+ source.recordParameters( this );
+ } catch (IOException e) {
+ throw new RuntimeException( "This should never happen" );
+ }
+ }
+
+
+//----------------------------------- ParameterProcessor methods -------------------------------------------------------
+
+
+ public void addParameter( String name, String value, String characterSet ) throws IOException {
+ Object[] values = (Object[]) _parameters.get( name );
+ _parameters.put( name, HttpUnitUtils.withNewValue( values, value ) );
+ }
+
+
+ public void addFile( String parameterName, UploadFileSpec fileSpec ) throws IOException {
+ Object[] values = (Object[]) _parameters.get( parameterName );
+ _parameters.put( parameterName, HttpUnitUtils.withNewValue( values, fileSpec ) );
+ }
+
+
+//----------------------------------- ParameterHolder methods ----------------------------------------------------------
+
+
+ /**
+ * Specifies the position at which an image button (if any) was clicked.
+ **/
+ void selectImageButtonPosition( SubmitButton imageButton, int x, int y ) {
+ if (imageButton.isValidImageButton()) {
+ setParameter( imageButton.positionParameterName("x"), Integer.toString( x ) );
+ setParameter( imageButton.positionParameterName("y"), Integer.toString( y ) );
+ }
+ }
+
+
+ /**
+ * Does nothing, since unchecked requests treat all parameters the same.
+ **/
+ void recordPredefinedParameters( ParameterProcessor processor ) throws IOException {
+ }
+
+
+ /**
+ * Iterates through the parameters in this holder, recording them in the supplied parameter processor.
+ **/
+ public void recordParameters( ParameterProcessor processor ) throws IOException {
+ Enumeration e = _parameters.keys();
+
+ while (e.hasMoreElements()) {
+ String name = (String) e.nextElement();
+ Object[] values = (Object[]) _parameters.get( name );
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] instanceof String || values[i] == null) {
+ processor.addParameter( name, (String) values[i], _characterSet );
+ } else if (values[i] instanceof UploadFileSpec) {
+ processor.addFile( name, (UploadFileSpec) values[i] );
+ }
+ }
+ }
+ }
+
+
+ String[] getParameterNames() {
+ return (String[]) _parameters.keySet().toArray( new String[ _parameters.size() ] );
+ }
+
+
+ String getParameterValue( String name ) {
+ String[] values = getParameterValues( name );
+ return values.length == 0 ? null : values[0];
+ }
+
+
+ String[] getParameterValues( String name ) {
+ Object[] values = (Object[]) _parameters.get( name );
+ if (values == null) return NO_VALUES;
+
+ String[] result = new String[ values.length ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = values[i] instanceof UploadFileSpec ? ((UploadFileSpec) values[i]).getFileName() : values[i].toString();
+ }
+ return result;
+ }
+
+
+ void removeParameter( String name ) {
+ _parameters.remove( name );
+ }
+
+
+ void setParameter( String name, String value ) {
+ _parameters.put( name, new Object[] { value } );
+ }
+
+
+ void setParameter( String name, String[] values ) {
+ _parameters.put( name, values );
+ }
+
+
+ void setParameter( String name, UploadFileSpec[] files ) {
+ _parameters.put( name, files );
+ }
+
+
+ boolean isFileParameter( String name ) {
+ return true;
+ }
+
+
+ String getCharacterSet() {
+ return _characterSet;
+ }
+
+
+ boolean isSubmitAsMime() {
+ return _submitAsMime;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/UnsupportedActionException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/UnsupportedActionException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/UnsupportedActionException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,35 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * An exception thrown when an action URL is not supported.
+ *
+ * @author Russell Gold
+ * @since 1.6
+ **/
+public class UnsupportedActionException extends RuntimeException {
+
+ public UnsupportedActionException( String message ) {
+ super( message );
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebApplet.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebApplet.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebApplet.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,217 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, 2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URLClassLoader;
+import java.applet.Applet;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.List;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.html.HTMLAppletElement;
+import org.xml.sax.SAXException;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+
+/**
+ * This class represents the embedding of an applet in a web page.
+ *
+ * @author Oliver Imbusch
+ * @author Russell Gold
+ **/
+public class WebApplet extends HTMLElementBase {
+
+ private WebResponse _response;
+ private String _baseTarget;
+
+ private Applet _applet;
+ private HashMap _parameters;
+ private String[] _parameterNames;
+
+ final private String CLASS_EXTENSION = ".class";
+ private HTMLAppletElement _element;
+
+
+ public WebApplet( WebResponse response, HTMLAppletElement element, String baseTarget ) {
+ super( element );
+ _element = element;
+ _response = response;
+ _baseTarget = baseTarget;
+ }
+
+
+ /**
+ * Returns the URL of the codebase used to find the applet classes
+ */
+ public URL getCodeBaseURL() throws MalformedURLException {
+ return new URL( _response.getURL(), getCodeBase() );
+ }
+
+
+ private String getCodeBase() {
+ final String codeBaseAttribute = _element.getCodeBase();
+ return codeBaseAttribute.endsWith( "/" ) ? codeBaseAttribute : (codeBaseAttribute + "/");
+ }
+
+
+ /**
+ * Returns the name of the applet main class.
+ */
+ public String getMainClassName() {
+ String className = _element.getCode();
+ if (className.endsWith( CLASS_EXTENSION )) {
+ className = className.substring( 0, className.lastIndexOf( CLASS_EXTENSION ));
+ }
+ className = className.replace( '/', '.' ).replace( '\\', '.' );
+ return className;
+ }
+
+
+ /**
+ * Returns the width of the panel in which the applet will be drawn.
+ */
+ public int getWidth() {
+ return Integer.parseInt( getAttribute( "width" ) );
+ }
+
+
+ /**
+ * Returns the height of the panel in which the applet will be drawn.
+ */
+ public int getHeight() {
+ return Integer.parseInt( getAttribute( "height" ) );
+ }
+
+
+ /**
+ * Returns the archive specification.
+ */
+ public String getArchiveSpecification() {
+ String specification = getParameter( "archive" );
+ if (specification == null) specification = getAttribute( "archive" );
+ return specification;
+ }
+
+
+ List getArchiveList() throws MalformedURLException {
+ ArrayList al = new ArrayList();
+ StringTokenizer st = new StringTokenizer( getArchiveSpecification(), "," );
+ while (st.hasMoreTokens()) al.add( new URL( getCodeBaseURL(), st.nextToken() ) );
+ return al;
+ }
+
+
+ /**
+ * Returns an array containing the names of the parameters defined for the applet.
+ */
+ public String[] getParameterNames() {
+ if (_parameterNames == null) {
+ ArrayList al = new ArrayList( getParameterMap().keySet() );
+ _parameterNames = (String[]) al.toArray( new String[ al.size() ] );
+ }
+ return _parameterNames;
+ }
+
+
+ /**
+ * Returns the value of the specified applet parameter, or null if not defined.
+ */
+ public String getParameter( String name ) {
+ return (String) getParameterMap().get( name );
+ }
+
+
+ private Map getParameterMap() {
+ if (_parameters == null) {
+ _parameters = new HashMap();
+ NodeList nl = ((Element) getNode()).getElementsByTagName( "param" );
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ _parameters.put( NodeUtils.getNodeAttribute( n, "name", "" ), NodeUtils.getNodeAttribute( n, "value", "" ) );
+ }
+ }
+ return _parameters;
+ }
+
+
+ public Applet getApplet() throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
+ if (_applet == null) {
+ ClassLoader cl = new URLClassLoader( getClassPath(), null );
+ Object o = cl.loadClass( getMainClassName() ).newInstance();
+ if (!(o instanceof Applet)) throw new RuntimeException( getMainClassName() + " is not an Applet" );
+ _applet = (Applet) o;
+ _applet.setStub( new AppletStubImpl( this ) );
+ }
+ return _applet;
+ }
+
+
+ private URL[] getClassPath() throws MalformedURLException {
+ List classPath = getArchiveList();
+ classPath.add( getCodeBaseURL() );
+ return (URL[]) classPath.toArray( new URL[ classPath.size() ] );
+ }
+
+
+ String getBaseTarget() {
+ return _baseTarget;
+ }
+
+
+ WebApplet[] getAppletsInPage() {
+ try {
+ return _response.getApplets();
+ } catch (SAXException e) {
+ HttpUnitUtils.handleException(e); // should never happen.
+ return null;
+ }
+ }
+
+
+ void sendRequest( URL url, String target ) {
+ WebRequest wr = new GetMethodWebRequest( null, url.toExternalForm(), target );
+ try {
+ _response.getWindow().getResponse( wr );
+ } catch (IOException e) {
+ e.printStackTrace(); //To change body of catch statement use Options | File Templates.
+ throw new RuntimeException( e.toString() );
+ } catch (SAXException e) {
+ }
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return _response.getDocumentScriptable();
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebClient.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebClient.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebClient.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,743 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004,2007 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.PasswordAuthentication;
+
+import java.util.*;
+
+import org.xml.sax.SAXException;
+
+import com.meterware.httpunit.cookies.Cookie;
+import com.meterware.httpunit.cookies.CookieJar;
+
+
+/**
+ * The context for a series of web requests. This class manages cookies used to maintain
+ * session context, computes relative URLs, and generally emulates the browser behavior
+ * needed to build an automated test of a web site.
+ *
+ * @author Russell Gold
+ * @author Jan Ohrstrom
+ * @author Seth Ladd
+ * @author Oliver Imbusch
+ **/
+abstract
+public class WebClient {
+
+ private ArrayList _openWindows = new ArrayList();
+
+ /** The current main window. **/
+ private WebWindow _mainWindow = new WebWindow( this );
+
+ /** An authorization string to be sent with every request, whether challenged or not. May be null. **/
+ private String _fixedAuthorizationString;
+
+ /** An authorization string to be sent with the next request only. May be null. **/
+ private String _authorizationString;
+
+ private String _proxyAuthorizationString;
+ private Hashtable _credentials = new Hashtable();
+
+
+ public WebWindow getMainWindow() {
+ return _mainWindow;
+ }
+
+
+ public void setMainWindow( WebWindow mainWindow ) {
+ if (!_openWindows.contains( mainWindow )) throw new IllegalArgumentException( "May only select an open window owned by this client" );
+ _mainWindow = mainWindow;
+ }
+
+
+ public WebWindow[] getOpenWindows() {
+ return (WebWindow[]) _openWindows.toArray( new WebWindow[ _openWindows.size() ] );
+ }
+
+
+ public WebWindow getOpenWindow( String name ) {
+ if (name == null || name.length() == 0) return null;
+ for (Iterator i = _openWindows.iterator(); i.hasNext();) {
+ WebWindow window = (WebWindow) i.next();
+ if (name.equals( window.getName() )) return window;
+ }
+ return null;
+ }
+
+
+ /**
+ * Submits a GET method request and returns a response.
+ * @exception SAXException thrown if there is an error parsing the retrieved page
+ **/
+ public WebResponse getResponse( String urlString ) throws IOException, SAXException {
+ return _mainWindow.getResponse( urlString );
+ }
+
+
+ /**
+ * Submits a web request and returns a response. This is an alternate name for the getResponse method.
+ */
+ public WebResponse sendRequest( WebRequest request ) throws IOException, SAXException {
+ return _mainWindow.sendRequest( request );
+ }
+
+
+ /**
+ * Returns the response representing the current top page in the main window.
+ */
+ public WebResponse getCurrentPage() {
+ return _mainWindow.getCurrentPage();
+ }
+
+
+ /**
+ * Submits a web request and returns a response, using all state developed so far as stored in
+ * cookies as requested by the server.
+ * @exception SAXException thrown if there is an error parsing the retrieved page
+ **/
+ public WebResponse getResponse( WebRequest request ) throws IOException, SAXException {
+ return _mainWindow.getResponse( request );
+ }
+
+
+ /**
+ * Returns the name of the currently active frames in the main window.
+ **/
+ public String[] getFrameNames() {
+ return _mainWindow.getFrameNames();
+ }
+
+
+ /**
+ * Returns the response associated with the specified frame name in the main window.
+ * Throws a runtime exception if no matching frame is defined.
+ **/
+ public WebResponse getFrameContents( String frameName ) {
+ return _mainWindow.getFrameContents( frameName );
+ }
+
+
+ /**
+ * Returns the response associated with the specified frame name in the main window.
+ * Throws a runtime exception if no matching frame is defined.
+ *
+ * @since 1.6
+ **/
+ public WebResponse getFrameContents( FrameSelector targetFrame ) {
+ return _mainWindow.getFrameContents( targetFrame );
+ }
+
+
+ /**
+ * Returns the resource specified by the request. Does not update the client or load included framesets or scripts.
+ * May return null if the resource is a JavaScript URL which would normally leave the client unchanged.
+ */
+ public WebResponse getResource( WebRequest request ) throws IOException {
+ return _mainWindow.getResource( request );
+ }
+
+
+ /**
+ * Resets the state of this client, removing all cookies, frames, and per-client headers. This does not affect
+ * any listeners or preferences which may have been set.
+ **/
+ public void clearContents() {
+ _mainWindow = new WebWindow( this );
+ _cookieJar.clear();
+ _headers = new HeaderDictionary();
+ }
+
+
+ /**
+ * Defines a cookie to be sent to the server on every request.
+ * @deprecated as of 1.6, use #putCookie instead.
+ **/
+ public void addCookie( String name, String value ) {
+ _cookieJar.addCookie( name, value );
+ }
+
+
+ /**
+ * Defines a cookie to be sent to the server on every request. This overrides any previous setting for this cookie name.
+ **/
+ public void putCookie( String name, String value ) {
+ _cookieJar.putCookie( name, value );
+ }
+
+
+ /**
+ * Returns the name of all the active cookies which will be sent to the server.
+ **/
+ public String[] getCookieNames() {
+ return _cookieJar.getCookieNames();
+ }
+
+ /**
+ * Returns an object containing the details of the named cookie
+ * @since [ 1488617 ] alternate patch for cookie bug #1371204
+ */
+ public Cookie getCookieDetails( String name ) {
+ return _cookieJar.getCookie( name );
+ }
+
+ /**
+ * Returns the value of the specified cookie.
+ **/
+ public String getCookieValue( String name ) {
+ return _cookieJar.getCookieValue( name );
+ }
+
+
+ /**
+ * Returns the properties associated with this client.
+ */
+ public ClientProperties getClientProperties() {
+ if (_clientProperties == null) {
+ _clientProperties = ClientProperties.getDefaultProperties().cloneProperties();
+ }
+ return _clientProperties;
+ }
+
+
+ /**
+ * Specifies the user agent identification. Used to trigger browser-specific server behavior.
+ * @deprecated as of 1.4.6. Use ClientProperties#setUserAgent instead.
+ **/
+ public void setUserAgent( String userAgent ) {
+ getClientProperties().setUserAgent( userAgent );
+ }
+
+
+ /**
+ * Returns the current user agent setting.
+ * @deprecated as of 1.4.6. Use ClientProperties#getUserAgent instead.
+ **/
+ public String getUserAgent() {
+ return getClientProperties().getUserAgent();
+ }
+
+
+ /**
+ * Sets a username and password for a basic authentication scheme.
+ * @deprecated as of 1.7. Use #setAuthentication for more accurate emulation of browser behavior.
+ **/
+ public void setAuthorization( String userName, String password ) {
+ _fixedAuthorizationString = "Basic " + Base64.encode( userName + ':' + password );
+ }
+
+
+ /**
+ * Specifies a username and password for on-demand authentication. Will only send
+ * the authorization header when challenged for the specified realm.
+ * @param realm the realm for which the credentials apply.
+ * @param username the user to authenticate
+ * @param password the credentials for the user
+ */
+ public void setAuthentication( String realm, String username, String password ) {
+ _credentials.put( realm, new PasswordAuthentication( username, password.toCharArray() ) );
+ }
+
+
+ PasswordAuthentication getCredentialsForRealm( String realm ) {
+ return ((PasswordAuthentication) _credentials.get( realm ));
+ }
+
+ /**
+ * Specifies a proxy server to use for requests from this client.
+ */
+ public abstract void setProxyServer( String proxyHost, int proxyPort );
+
+ /**
+ * Specifies a proxy server to use, along with a user and password for authentication.
+ *
+ * @since 1.6
+ */
+ public void setProxyServer( String proxyHost, int proxyPort, String userName, String password ) {
+ setProxyServer( proxyHost, proxyPort );
+ _proxyAuthorizationString = "Basic " + Base64.encode( userName + ':' + password );
+ }
+
+
+ /**
+ * Clears the proxy server settings.
+ */
+ public void clearProxyServer() {
+ }
+
+
+ /**
+ * Returns the name of the active proxy server.
+ */
+ public String getProxyHost() {
+ return System.getProperty( "proxyHost" );
+ }
+
+
+ /**
+ * Returns the number of the active proxy port, or 0 is none is specified.
+ */
+ public int getProxyPort() {
+ try {
+ return Integer.parseInt( System.getProperty( "proxyPort" ) );
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+
+
+
+ /**
+ * Sets the value for a header field to be sent with all requests. If the value set is null,
+ * removes the header from those to be sent.
+ **/
+ public void setHeaderField( String fieldName, String fieldValue ) {
+ _headers.put( fieldName, fieldValue );
+ }
+
+
+ /**
+ * Returns the value for the header field with the specified name. This method will ignore the case of the field name.
+ */
+ public String getHeaderField( String fieldName ) {
+ return (String) _headers.get( fieldName );
+ }
+
+
+ /**
+ * Specifies whether an exception will be thrown when an error status (4xx or 5xx) is detected on a response.
+ * Defaults to the value returned by HttpUnitOptions.getExceptionsThrownOnErrorStatus.
+ **/
+ public void setExceptionsThrownOnErrorStatus( boolean throwExceptions ) {
+ _exceptionsThrownOnErrorStatus = throwExceptions;
+ }
+
+
+ /**
+ * Returns true if an exception will be thrown when an error status (4xx or 5xx) is detected on a response.
+ **/
+ public boolean getExceptionsThrownOnErrorStatus() {
+ return _exceptionsThrownOnErrorStatus;
+ }
+
+
+ /**
+ * Adds a listener to watch for requests and responses.
+ */
+ public void addClientListener( WebClientListener listener ) {
+ synchronized (_clientListeners) {
+ if (listener != null && !_clientListeners.contains( listener )) _clientListeners.add( listener );
+ }
+ }
+
+
+ /**
+ * Removes a listener to watch for requests and responses.
+ */
+ public void removeClientListener( WebClientListener listener ) {
+ synchronized (_clientListeners) {
+ _clientListeners.remove( listener );
+ }
+ }
+
+
+ /**
+ * Adds a listener to watch for window openings and closings.
+ */
+ public void addWindowListener( WebWindowListener listener ) {
+ synchronized (_windowListeners) {
+ if (listener != null && !_windowListeners.contains( listener )) _windowListeners.add( listener );
+ }
+ }
+
+
+ /**
+ * Removes a listener to watch for window openings and closings.
+ */
+ public void removeWindowListener( WebWindowListener listener ) {
+ synchronized (_windowListeners) {
+ _windowListeners.remove( listener );
+ }
+ }
+
+
+ /**
+ * Returns the next javascript alert without removing it from the queue.
+ */
+ public String getNextAlert() {
+ return _alerts.isEmpty() ? null : (String) _alerts.getFirst();
+ }
+
+
+ /**
+ * Returns the next javascript alert and removes it from the queue. If the queue is empty,
+ * will return an empty string.
+ */
+ public String popNextAlert() {
+ if (_alerts.isEmpty()) return "";
+ return (String) _alerts.removeFirst();
+ }
+
+
+ /**
+ * Specifies the object which will respond to all dialogs.
+ **/
+ public void setDialogResponder( DialogResponder responder ) {
+ _dialogResponder = responder;
+ }
+
+
+//------------------------------------------ protected members -----------------------------------
+
+
+ protected WebClient() {
+ _openWindows.add( _mainWindow );
+ }
+
+
+ /**
+ * Creates a web response object which represents the response to the specified web request.
+ * @param request the request to which the response should be generated
+ * @param targetFrame the frame in which the response should be stored
+ **/
+ abstract
+ protected WebResponse newResponse( WebRequest request, FrameSelector targetFrame ) throws IOException;
+
+
+ /**
+ * Writes the message body for the request.
+ **/
+ final protected void writeMessageBody( WebRequest request, OutputStream stream ) throws IOException {
+ request.writeMessageBody( stream );
+ }
+
+
+ /**
+ * Returns the value of all current header fields.
+ **/
+ protected Dictionary getHeaderFields( URL targetURL ) {
+ Hashtable result = (Hashtable) _headers.clone();
+ result.put( "User-Agent", getClientProperties().getUserAgent() );
+ if (getClientProperties().isAcceptGzip()) result.put( "Accept-Encoding", "gzip" );
+ AddHeaderIfNotNull( result, "Cookie", _cookieJar.getCookieHeaderField( targetURL ) );
+ if (_authorizationString == null) _authorizationString = _fixedAuthorizationString;
+ AddHeaderIfNotNull( result, "Authorization", _authorizationString );
+ AddHeaderIfNotNull( result, "Proxy-Authorization", _proxyAuthorizationString );
+ _authorizationString = null;
+ return result;
+ }
+
+
+ private void AddHeaderIfNotNull( Hashtable result, final String headerName, final String headerValue ) {
+ if (headerValue != null) result.put( headerName, headerValue );
+ }
+
+
+ /**
+ * Updates this web client based on a received response. This includes updating
+ * cookies and frames. This method is required by ServletUnit, which cannot call the updateWindow method directly.
+ **/
+ final
+ protected void updateMainWindow( FrameSelector frame, WebResponse response ) throws IOException, SAXException {
+ getMainWindow().updateWindow( frame.getName(), response, new RequestContext() );
+ }
+
+
+//------------------------------------------------- package members ----------------------------------------------------
+
+
+ void tellListeners( WebRequest request ) {
+ List listeners;
+
+ synchronized (_clientListeners) {
+ listeners = new ArrayList( _clientListeners );
+ }
+
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ ((WebClientListener) i.next()).requestSent( this, request );
+ }
+ }
+
+
+ void tellListeners( WebResponse response ) {
+ List listeners;
+
+ synchronized (_clientListeners) {
+ listeners = new ArrayList( _clientListeners );
+ }
+
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ ((WebClientListener) i.next()).responseReceived( this, response );
+ }
+ }
+
+
+ void updateClient( WebResponse response ) throws IOException {
+ if (getClientProperties().isAcceptCookies()) _cookieJar.updateCookies( response.getCookieJar() );
+ validateHeaders( response );
+ }
+
+
+ /**
+ * Support Request [ 1288796 ] getCookieJar() in WebClient
+ * @deprecated - use with care - was not public in the past
+ * @return the cookie jar
+ */
+ public CookieJar getCookieJar() {
+ return _cookieJar;
+ }
+
+
+ void updateFrameContents( WebWindow requestWindow, String requestTarget, WebResponse response, RequestContext requestContext ) throws IOException, SAXException {
+ if (response.getFrame() == FrameSelector.NEW_FRAME) {
+ WebWindow window = new WebWindow( this, requestWindow.getCurrentPage() );
+ if (!WebRequest.NEW_WINDOW.equalsIgnoreCase( requestTarget )) window.setName( requestTarget );
+ response.setFrame( window.getTopFrame() );
+ window.updateFrameContents( response, requestContext );
+ _openWindows.add( window );
+ reportWindowOpened( window );
+ } else if (response.getFrame().getWindow() != null && response.getFrame().getWindow() != requestWindow) {
+ response.getFrame().getWindow().updateFrameContents( response, requestContext );
+ } else {
+ if (response.getFrame() == FrameSelector.TOP_FRAME) response.setFrame( requestWindow.getTopFrame() );
+ requestWindow.updateFrameContents( response, requestContext );
+ }
+ }
+
+
+ void close( WebWindow window ) {
+ if (!_openWindows.contains( window )) throw new IllegalStateException( "Window is already closed" );
+ _openWindows.remove( window );
+ if (_openWindows.isEmpty()) _openWindows.add( new WebWindow( this ) );
+ if (window.equals( _mainWindow )) _mainWindow = (WebWindow) _openWindows.get(0);
+ reportWindowClosed( window );
+ }
+
+
+ private void reportWindowOpened( WebWindow window ) {
+ List listeners;
+
+ synchronized (_windowListeners) {
+ listeners = new ArrayList( _windowListeners );
+ }
+
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ ((WebWindowListener) i.next()).windowOpened( this, window );
+ }
+ }
+
+
+ private void reportWindowClosed( WebWindow window ) {
+ List listeners;
+
+ synchronized (_windowListeners) {
+ listeners = new ArrayList( _windowListeners );
+ }
+
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ ((WebWindowListener) i.next()).windowClosed( this, window );
+ }
+ }
+
+//------------------------------------------ package members ------------------------------------
+
+
+ boolean getConfirmationResponse( String message ) {
+ return _dialogResponder.getConfirmation( message );
+ }
+
+
+ String getUserResponse( String message, String defaultResponse ) {
+ return _dialogResponder.getUserResponse( message, defaultResponse );
+ }
+
+
+ /**
+ * simulate an alert by remembering the alert message on a Stack
+ * @param message - the alert message to post
+ */
+ void postAlert( String message ) {
+ _alerts.addLast( message );
+ }
+
+//------------------------------------------ private members -------------------------------------
+
+ /** The list of alerts generated by JavaScript. **/
+ private LinkedList _alerts = new LinkedList();
+
+ /** The currently defined cookies. **/
+ private CookieJar _cookieJar = new CookieJar();
+
+
+ /** A map of header names to values. **/
+ private HeaderDictionary _headers = new HeaderDictionary();
+
+ private boolean _exceptionsThrownOnErrorStatus = HttpUnitOptions.getExceptionsThrownOnErrorStatus();
+
+ private final List _clientListeners = new ArrayList();
+
+ private final List _windowListeners = new ArrayList();
+
+ private DialogResponder _dialogResponder = new DialogAdapter();
+
+ private ClientProperties _clientProperties;
+
+
+ /**
+ * Examines the headers in the response and throws an exception if appropriate.
+ * @parm response - the response to validate
+ **/
+ private void validateHeaders( WebResponse response ) throws HttpException {
+ if (!getExceptionsThrownOnErrorStatus())
+ return;
+ // see feature request [ 914314 ] Add HttpException.getResponse for better reporting
+ // for possible improvements here
+ if (response.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
+ throw new HttpInternalErrorException( response.getURL() );
+ } else if (response.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
+ throw new HttpNotFoundException( response.getResponseMessage(), response.getURL() );
+ } else if (response.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) {
+ throw new HttpException( response.getResponseCode(), response.getResponseMessage(), response.getURL() );
+ }
+ }
+
+
+ FrameSelector findFrame( String target ) {
+ for (int i = 0; i < _openWindows.size(); i++) {
+ WebWindow webWindow = (WebWindow) _openWindows.get( i );
+ FrameSelector frame = webWindow.getFrame( target );
+ if (frame != null) return frame;
+ }
+ return null;
+ }
+
+
+ /**
+ * Sends a request and returns a response after dealing with any authentication challenge. If challenged and able
+ * to respond, resends the request after setting the authentication header (which will apply only for the that request).
+ * @param request the original request
+ * @param targetFrame the frame into which the result will be stored
+ * @return a response from the server
+ * @throws IOException if an exception (including authorization failure) occurs
+ */
+ WebResponse createResponse( WebRequest request, FrameSelector targetFrame ) throws IOException {
+ WebResponse response = newResponse( request, targetFrame );
+ AuthenticationChallenge challenge = new AuthenticationChallenge( this, request, response.getHeaderField( "WWW-Authenticate" ) );
+ if (!challenge.needToAuthenticate()) {
+ return response;
+ } else {
+ setOnetimeAuthenticationHeader( challenge.createAuthenticationHeader() );
+ WebResponse response2 = newResponse( request, targetFrame );
+ if (response2.getHeaderField( "WWW-Authenticate" ) != null && getExceptionsThrownOnErrorStatus()) {
+ throw AuthenticationChallenge.createException( response2.getHeaderField( "WWW-Authenticate" ) );
+ }
+ return response2;
+ }
+ }
+
+
+ private void setOnetimeAuthenticationHeader( String authorizationHeader ) {
+ _authorizationString = authorizationHeader;
+ }
+
+//==================================================================================================
+
+
+ static public class HeaderDictionary extends Hashtable {
+
+ public void addEntries( Dictionary source ) {
+ for (Enumeration e = source.keys(); e.hasMoreElements(); ) {
+ Object key = e.nextElement();
+ put( key, source.get( key ) );
+ }
+ }
+
+
+ public boolean containsKey( Object key ) {
+ return super.containsKey( matchPreviousFieldName( key.toString() ) );
+ }
+
+
+ public Object get( Object fieldName ) {
+ return super.get( matchPreviousFieldName( fieldName.toString() ) );
+ }
+
+
+ public Object put( Object fieldName, Object fieldValue ) {
+ fieldName = matchPreviousFieldName( fieldName.toString() );
+ Object oldValue = super.get( fieldName );
+ if (fieldValue == null) {
+ remove( fieldName );
+ } else {
+ super.put( fieldName, fieldValue );
+ }
+ return oldValue;
+ }
+
+
+ /**
+ * If a matching field name with different case is already known, returns the older name.
+ * Otherwise, returns the specified name.
+ **/
+ private String matchPreviousFieldName( String fieldName ) {
+ for (Enumeration e = keys(); e.hasMoreElements(); ) {
+ String key = (String) e.nextElement();
+ if (key.equalsIgnoreCase( fieldName )) return key;
+ }
+ return fieldName;
+ }
+
+
+ }
+
+}
+
+
+//==================================================================================================
+
+
+class RedirectWebRequest extends WebRequest {
+
+
+ RedirectWebRequest( WebResponse response ) {
+ super( response.getURL(), response.getHeaderField( "Location" ), response.getFrame(), response.getFrameName() );
+ if (response.getReferer() != null) setHeaderField( "Referer", response.getReferer() );
+ }
+
+
+ /**
+ * Returns the HTTP method defined for this request.
+ **/
+ public String getMethod() {
+ return "GET";
+ }
+}
+
+
+
+
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebClientListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebClientListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebClientListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,43 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+
+/**
+ * A listener for messages sent and received by a web client.
+ *
+ * @author Oliver Imbusch
+ * @author Russell Gold
+ **/
+public interface WebClientListener {
+
+ /**
+ * Invoked when the web client sends a request.
+ */
+ public void requestSent( WebClient src, WebRequest req );
+
+
+ /**
+ * Invoked when the web client receives a response.
+ */
+ public void responseReceived( WebClient src, WebResponse resp );
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebConversation.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebConversation.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebConversation.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,196 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.io.IOException;
+
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Properties;
+
+
+/**
+ * The context for a series of HTTP requests. This class manages cookies used to maintain
+ * session context, computes relative URLs, and generally emulates the browser behavior
+ * needed to build an automated test of a web site.
+ *
+ * @author Russell Gold
+ **/
+public class WebConversation extends WebClient {
+
+ private String _proxyHost;
+ private int _proxyPort;
+ private int _connectTimeout = -1;
+ private int _readTimeout = -1;
+
+
+ /**
+ * Creates a new web conversation.
+ **/
+ public WebConversation() {
+ }
+
+
+//---------------------------------- protected members --------------------------------
+
+
+ /**
+ * Creates a web response object which represents the response to the specified web request.
+ **/
+ protected WebResponse newResponse( WebRequest request, FrameSelector targetFrame ) throws MalformedURLException, IOException {
+ Properties savedProperties = (Properties) System.getProperties().clone();
+ try {
+ if (_proxyHost != null) {
+ System.setProperty( "proxyHost", _proxyHost );
+ System.setProperty( "proxyPort", Integer.toString( _proxyPort ) );
+ }
+ URLConnection connection = openConnection( getRequestURL( request ) );
+ // [ 1518901 ] enable http connect and read timeouts (needs JDK 1.5)
+ // XXX enable for 1.7 release in 2008
+ // comment out if you need this and have JDK 1.5
+ // if (_connectTimeout>=0) connection.setConnectTimeout( _connectTimeout );
+ // if (_readTimeout>=0) connection.setReadTimeout( _readTimeout );
+ if (HttpUnitOptions.isLoggingHttpHeaders()) {
+ String urlString = request.getURLString();
+ System.out.println( "\nConnecting to " + request.getURL().getHost() );
+ System.out.println( "Sending:: " + request.getMethod() + " " + urlString );
+ }
+ sendHeaders( connection, getHeaderFields( request.getURL() ) );
+ sendHeaders( connection, request.getHeaderDictionary() );
+ request.completeRequest( connection );
+ return new HttpWebResponse( this, targetFrame, request, connection, getExceptionsThrownOnErrorStatus() );
+ } finally {
+ System.setProperties( savedProperties );
+ }
+ }
+
+
+ public void clearProxyServer() {
+ _proxyHost = null;
+ }
+
+
+ /**
+ * set the proxy server to the given proxyHost with the given proxy Port
+ * @param proxyHost - the hostname of the proxy e.g. proxy.somedomain.org
+ * @param proxyPort - the number of the port to use e.g. 8080
+ */
+ public void setProxyServer( String proxyHost, int proxyPort ) {
+ _proxyHost = proxyHost;
+ _proxyPort = proxyPort;
+ }
+
+
+ /**
+ * @return the _connectTimeout -1 means it is not set (the default)
+ */
+ public int get_connectTimeout() {
+ return _connectTimeout;
+ }
+
+
+ /**
+ * set the connectionTimout -1 means it is not set (the default)
+ * @param timeout the _connectTimeout to set
+ */
+ public void set_connectTimeout(int timeout) {
+ _connectTimeout = timeout;
+ }
+
+
+ /**
+ * @return the _readTimeout -1 means it is not set (the default)
+ */
+ public int get_readTimeout() {
+ return _readTimeout;
+ }
+
+
+ /**
+ * @param timeout the _readTimeout to set -1 means it is not set (the default)
+ */
+ public void set_readTimeout(int timeout) {
+ _readTimeout = timeout;
+ }
+
+
+ /**
+ * get the Uniform Resource Locator for this request
+ * @param request
+ * @return the URL
+ * @throws MalformedURLException
+ */
+ private URL getRequestURL( WebRequest request ) throws MalformedURLException {
+ DNSListener dnsListener = getClientProperties().getDnsListener();
+ if (dnsListener == null) return request.getURL();
+
+ String hostName = request.getURL().getHost();
+ String portPortion = request.getURL().getPort() == -1 ? "" : (":" + request.getURL().getPort());
+ setHeaderField( "Host", hostName + portPortion );
+ String actualHost = dnsListener.getIpAddress( hostName );
+ if (HttpUnitOptions.isLoggingHttpHeaders()) System.out.println( "Rerouting request to :: " + actualHost );
+ return new URL( request.getURL().getProtocol(), actualHost, request.getURL().getPort(), request.getURL().getFile() );
+ }
+
+
+//---------------------------------- private members --------------------------------
+
+
+ /**
+ * open a connection for the given uniform resource locator
+ * @param url - the url to use
+ */
+ private URLConnection openConnection( URL url ) throws MalformedURLException, IOException {
+ URLConnection connection = url.openConnection();
+ if (connection instanceof HttpURLConnection) ((HttpURLConnection) connection).setInstanceFollowRedirects( false );
+ connection.setUseCaches( false );
+ return connection;
+ }
+
+
+ /**
+ * send the headers for the given connection based on the given Dictionary of headers
+ * @param connection
+ * @param headers
+ */
+ private void sendHeaders( URLConnection connection, Dictionary headers ) {
+ boolean sendReferer = getClientProperties().isSendReferer();
+ for (Enumeration e = headers.keys(); e.hasMoreElements();) {
+ String key = (String) e.nextElement();
+ if ( sendReferer || !"referer".equalsIgnoreCase( key ) ) {
+ connection.setRequestProperty( key, (String) headers.get( key ) );
+ if (HttpUnitOptions.isLoggingHttpHeaders()) {
+ if (key.equalsIgnoreCase( "authorization" ) || key.equalsIgnoreCase( "proxy-authorization") ) {
+ System.out.println( "Sending:: " + key + ": " + headers.get( key ) );
+ } else {
+ System.out.println( "Sending:: " + key + ": " + connection.getRequestProperty( key ) );
+ }
+ }
+ } else if (HttpUnitOptions.isLoggingHttpHeaders()) {
+ System.out.println( "Blocked sending referer:: "+ connection.getRequestProperty( key ) );
+ }
+ } // for
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebForm.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebForm.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebForm.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,1154 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.NamedDelegate;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.FormScriptable;
+import com.meterware.httpunit.protocol.UploadFileSpec;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+
+import java.io.IOException;
+import java.io.File;
+import java.net.URL;
+import java.net.UnknownServiceException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.html.HTMLFormElement;
+import org.w3c.dom.html.HTMLCollection;
+import org.xml.sax.SAXException;
+
+
+/**
+ * This class represents a form in an HTML page. Users of this class may examine the parameters
+ * defined for the form, the structure of the form (as a DOM), or the text of the form. They
+ * may also create a {@link WebRequest} to simulate the submission of the form.
+ *
+ * @author Russell Gold
+ **/
+public class WebForm extends WebRequestSource {
+ private static final FormParameter UNKNOWN_PARAMETER = new FormParameter();
+
+ private final static String[] NO_VALUES = new String[0];
+
+ private Button[] _buttons;
+
+ /** The submit buttons in this form. **/
+ private SubmitButton[] _submitButtons;
+
+ /** The character set in which the form will be submitted. **/
+ private String _characterSet;
+
+ private Vector _buttonVector;
+
+ private FormControl[] _presetParameters;
+ private ArrayList _presets;
+
+ private ElementRegistry _registry;
+
+
+
+ /** Predicate to match a link's name. **/
+ public final static HTMLElementPredicate MATCH_NAME;
+ private HTMLFormElement _domElement;
+
+
+ /**
+ * Submits this form using the web client from which it was originally obtained.
+ **/
+ public WebResponse submit() throws IOException, SAXException {
+ return submit( getDefaultButton() );
+ }
+
+
+ /**
+ * Submits this form using the web client from which it was originally obtained.
+ * Will usually return the result of that submission; however, if the submit button's 'onclick'
+ * or the form's 'onsubmit' event is triggered and
+ * inhibits the submission, will return the updated contents of the frame containing this form.
+ **/
+ public WebResponse submit( SubmitButton button ) throws IOException, SAXException {
+ WebResponse result=submit(button,0,0);
+ return result;
+ }
+
+
+ /**
+ * Submits this form using the web client from which it was originally obtained.
+ * Will usually return the result of that submission; however, if the submit button's 'onclick'
+ * or the form's 'onsubmit' event is triggered and
+ * inhibits the submission, will return the updated contents of the frame containing this form.
+ * @since 1.6
+ **/
+ public WebResponse submit( SubmitButton button, int x, int y ) throws IOException, SAXException {
+ WebResponse result=null;
+ if (button==null || button.doOnClickSequence(x, y)) {
+ result= doFormSubmit( button, x, y );
+ } else {
+ result=getCurrentFrameContents();
+ }
+ return result;
+ }
+
+
+ /**
+ * Submits this form using the web client from which it was originally obtained, ignoring any buttons defined for the form.
+ * @since 1.6
+ **/
+ public WebResponse submitNoButton() throws SAXException, IOException {
+ return submit( SubmitButton.createFakeSubmitButton( this /* fake */ ) );
+ }
+
+
+ protected WebResponse submitRequest( String event, WebRequest request ) throws IOException, SAXException {
+ try {
+ return super.submitRequest( event, request );
+ } catch (UnknownServiceException e) {
+ throw new UnsupportedActionException( "HttpUnit does not support " + request.getURL().getProtocol() + " URLs in form submissions" );
+ }
+ }
+
+
+ /**
+ * Submits the form without also invoking the button's "onclick" event.
+ */
+ WebResponse doFormSubmit( SubmitButton button ) throws IOException, SAXException {
+ return submitRequest( getAttribute( "onsubmit" ), getRequest( button ) );
+ }
+
+
+ WebResponse doFormSubmit( SubmitButton button, int x, int y ) throws IOException, SAXException {
+ return submitRequest( getAttribute( "onsubmit" ), getRequest( button, x, y ) );
+ }
+
+
+ /**
+ * Returns the method defined for this form.
+ **/
+ public String getMethod() {
+ return getAttribute( "method", "GET" );
+ }
+
+
+ /**
+ * Returns the action defined for this form.
+ **/
+ public String getAction() {
+ return getDestination();
+ }
+
+
+ /**
+ * Returns true if a parameter with given name exists in this form.
+ **/
+ public boolean hasParameterNamed( String soughtName ) {
+ return getFormParameters().containsKey( soughtName );
+ }
+
+
+ /**
+ * Returns true if a parameter starting with a given name exists,
+ **/
+ public boolean hasParameterStartingWithPrefix( String prefix ) {
+ String[] names = getParameterNames();
+ for (int i = 0; i < names.length; i++) {
+ if (names[i].startsWith( prefix )) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns an array containing all of the buttons defined for this form.
+ **/
+ public Button[] getButtons() {
+ if (_buttons == null) {
+ FormControl[] controls = getFormControls();
+ ArrayList buttonList = new ArrayList();
+ for (int i = 0; i < controls.length; i++) {
+ FormControl control = controls[ i ];
+ if (control instanceof Button) buttonList.add( control );
+ }
+ _buttons = (Button[]) buttonList.toArray( new Button[ buttonList.size() ] );
+ }
+ return _buttons;
+ }
+
+
+ public Button getButton( HTMLElementPredicate predicate, Object criteria ) {
+ Button[] buttons = getButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ if (predicate.matchesCriteria( buttons[i], criteria )) return buttons[i];
+ }
+ return null;
+ }
+
+
+ /**
+ * Convenience method which returns the button with the specified ID.
+ */
+ public Button getButtonWithID( String buttonID ) {
+ return getButton( Button.WITH_ID, buttonID );
+ }
+
+
+ /**
+ * Returns an array containing the submit buttons defined for this form.
+ **/
+ public SubmitButton[] getSubmitButtons() {
+ if (_submitButtons == null) {
+ Vector buttons = getSubmitButtonVector();
+ _submitButtons = new SubmitButton[ buttons.size() ];
+ buttons.copyInto( _submitButtons );
+ }
+ return _submitButtons;
+ }
+
+
+ /**
+ * Returns the submit button defined in this form with the specified name.
+ * If more than one such button exists, will return the first found.
+ * If no such button is found, will return null.
+ **/
+ public SubmitButton getSubmitButton( String name ) {
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ if (buttons[i].getName().equals( name )) {
+ return buttons[i];
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the submit button defined in this form with the specified name and value.
+ * If more than one such button exists, will return the first found.
+ * If no such button is found, will return null.
+ **/
+ public SubmitButton getSubmitButton( String name, String value ) {
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ if (buttons[i].getName().equals( name ) && buttons[i].getValue().equals( value )) {
+ return buttons[i];
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the submit button defined in this form with the specified ID.
+ * If more than one such button exists, will return the first found.
+ * If no such button is found, will return null.
+ **/
+ public SubmitButton getSubmitButtonWithID( String ID ) {
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ if (buttons[i].getID().equals( ID )) {
+ return buttons[i];
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Creates and returns a web request which will simulate the submission of this form with a button with the specified name and value.
+ **/
+ public WebRequest getRequest( String submitButtonName, String submitButtonValue ) {
+ SubmitButton sb = getSubmitButton( submitButtonName, submitButtonValue );
+ if (sb == null) throw new IllegalSubmitButtonException( submitButtonName, submitButtonValue );
+ return getRequest( sb );
+ }
+
+
+ /**
+ * Creates and returns a web request which will simulate the submission of this form with a button with the specified name.
+ **/
+ public WebRequest getRequest( String submitButtonName ) {
+ SubmitButton sb = getSubmitButton( submitButtonName );
+ if (sb == null) throw new IllegalSubmitButtonException( submitButtonName, "" );
+ return getRequest( sb );
+ }
+
+
+ /**
+ * Creates and returns a web request which will simulate the submission of this form by pressing the specified button.
+ * If the button is null, simulates the pressing of the default button.
+ **/
+ public WebRequest getRequest( SubmitButton button ) {
+ return getRequest( button, 0, 0 );
+ }
+
+
+ /**
+ * Creates and returns a web request which will simulate the submission of this form by pressing the specified button.
+ * If the button is null, simulates the pressing of the default button.
+ * @param button - the submitbutton to be pressed - may be null
+ * @param x - the x position
+ * @param y - the y position
+ **/
+ public WebRequest getRequest( SubmitButton button, int x, int y ) {
+ if (button == null)
+ button = getDefaultButton();
+
+ if (HttpUnitOptions.getParameterValuesValidated()) {
+ if (button == null) {
+ throw new IllegalUnnamedSubmitButtonException();
+ } else if (button.isFake()) {
+ // bypass checks
+ } else if (!getSubmitButtonVector().contains( button )) {
+ throw new IllegalSubmitButtonException( button );
+ } else if (!button.wasEnabled()) {
+ // this is too late for the check of isDisabled()
+ // onclick has already been done ...
+ // [ 1289151 ] Order of events in button.click() is wrong
+ button.throwDisabledException();
+ }
+ }
+
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ buttons[i].setPressed( false );
+ }
+ button.setPressed( true );
+
+ if (getMethod().equalsIgnoreCase( "post" )) {
+ return new PostMethodWebRequest( this, button, x, y );
+ } else {
+ return new GetMethodWebRequest( this, WebRequest.newParameterHolder( this ), button, x, y );
+ }
+ }
+
+
+ /**
+ * Creates and returns a web request which includes the specified button. If no button is specified, will include
+ * the default button, if any. No parameter validation will be done on the returned request and no scripts
+ * will be run when it is submitted.
+ **/
+ public WebRequest newUnvalidatedRequest( SubmitButton button ) {
+ return newUnvalidatedRequest( button, 0, 0 );
+ }
+
+
+ /**
+ * Creates and returns a web request which includes the specified button and position. If no button is specified,
+ * will include the default button, if any. No parameter validation will be done on the returned request
+ * and no scripts will be run when it is submitted.
+ **/
+ public WebRequest newUnvalidatedRequest( SubmitButton button, int x, int y ) {
+ if (button == null) button = getDefaultButton();
+
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ buttons[i].setPressed( false );
+ }
+ button.setPressed( true );
+
+ if (getMethod().equalsIgnoreCase( "post" )) {
+ return new PostMethodWebRequest( this, new UncheckedParameterHolder( this ), button, x, y );
+ } else {
+ return new GetMethodWebRequest( this, new UncheckedParameterHolder( this ), button, x, y );
+ }
+ }
+
+
+ private WebRequest getScriptedSubmitRequest() {
+ SubmitButton[] buttons = getSubmitButtons();
+ for (int i = 0; i < buttons.length; i++) {
+ buttons[i].setPressed( false );
+ }
+
+ if (getMethod().equalsIgnoreCase( "post" )) {
+ return new PostMethodWebRequest( this );
+ } else {
+ return new GetMethodWebRequest( this );
+ }
+
+ }
+
+
+ /**
+ * Returns the default value of the named parameter. If the parameter does not exist returns null.
+ **/
+ public String getParameterValue( String name ) {
+ String[] values = getParameterValues( name );
+ return values.length == 0 ? null : values[0];
+ }
+
+
+ /**
+ * Returns the displayed options defined for the specified parameter name.
+ **/
+ public String[] getOptions( String name ) {
+ return getParameter( name ).getOptions();
+ }
+
+
+ /**
+ * Returns the option values defined for the specified parameter name.
+ **/
+ public String[] getOptionValues( String name ) {
+ return getParameter( name ).getOptionValues();
+ }
+
+
+ /**
+ * Returns true if the named parameter accepts multiple values.
+ **/
+ public boolean isMultiValuedParameter( String name ) {
+ return getParameter( name ).isMultiValuedParameter();
+ }
+
+
+ /**
+ * Returns the number of text parameters in this form with the specified name.
+ **/
+ public int getNumTextParameters( String name ) {
+ return getParameter( name ).getNumTextParameters();
+ }
+
+
+ /**
+ * Returns true if the named parameter accepts free-form text.
+ **/
+ public boolean isTextParameter( String name ) {
+ return getParameter( name ).isTextParameter();
+ }
+
+
+ /**
+ * Returns true if this form is to be submitted using mime encoding (the default is URL encoding).
+ **/
+ public boolean isSubmitAsMime() {
+ return "multipart/form-data".equalsIgnoreCase( getAttribute( "enctype" ) );
+ }
+
+
+ public FormScriptable getScriptableObject() {
+ return (FormScriptable) getScriptingHandler();
+ }
+
+ /**
+ * Resets all parameters to their initial values.
+ */
+ public void reset() {
+ if (handleEvent("onreset"))
+ resetControls();
+ }
+
+
+ private void resetControls() {
+ FormControl[] controls = getFormControls();
+ for (int i = 0; i < controls.length; i++) {
+ controls[i].reset();
+ }
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+//---------------------------------- WebRequestSource methods --------------------------------
+
+ /**
+ * Returns the character set encoding for this form.
+ **/
+ public String getCharacterSet() {
+ return _characterSet;
+ }
+
+
+ /**
+ * Returns true if the named parameter accepts files for upload.
+ **/
+ public boolean isFileParameter( String name ) {
+ return getParameter( name ).isFileParameter();
+ }
+
+
+ /**
+ * Returns an array containing the names of the parameters defined for this form.
+ **/
+ public String[] getParameterNames() {
+ ArrayList parameterNames = new ArrayList( getFormParameters().keySet() );
+ return (String[]) parameterNames.toArray( new String[ parameterNames.size() ] );
+ }
+
+
+ /**
+ * Returns the multiple default values of the named parameter.
+ **/
+ public String[] getParameterValues( String name ) {
+ final FormParameter parameter = getParameter( name );
+ return parameter.getValues();
+ }
+
+
+ /**
+ * Returns true if the named parameter is read-only. If more than one control exists with the same name,
+ * will return true only if all such controls are read-only.
+ **/
+ public boolean isReadOnlyParameter( String name ) {
+ return getParameter( name ).isReadOnlyParameter();
+ }
+
+
+ /**
+ * Returns true if the named parameter is disabled. If more than one control exists with the same name,
+ * will return true only if all such controls are read-only.
+ **/
+ public boolean isDisabledParameter( String name ) {
+ return getParameter( name ).isDisabledParameter();
+ }
+
+
+ /**
+ * Returns true if the named parameter is hidden. If more than one control exists with the same name,
+ * will return true only if all such controls are hidden.
+ **/
+ public boolean isHiddenParameter( String name ) {
+ return getParameter( name ).isHiddenParameter();
+ }
+
+
+ /**
+ * Creates and returns a web request which will simulate the submission of this form with an unnamed submit button.
+ **/
+ public WebRequest getRequest() {
+ return getRequest( (SubmitButton) null );
+ }
+
+
+ /**
+ * Creates and returns a web request based on the current state of this form. No parameter validation will be done
+ * and there is no guarantee over the order of parameters transmitted.
+ */
+ public WebRequest newUnvalidatedRequest() {
+ return newUnvalidatedRequest( null );
+ }
+
+
+ /**
+ * Records a parameter defined by including it in the destination URL. Ignores any parameters whose name matches
+ * a form control.
+ **/
+ protected void addPresetParameter( String name, String value ) {
+ FormControl[] formControls = getFormControls();
+ for (int i = 0; i < formControls.length; i++) {
+ if (formControls[i].getName().equals( name)) return;
+ }
+ _presets.add( new PresetFormParameter( this, name, value ) );
+ }
+
+
+ protected String getEmptyParameterValue() {
+ return null;
+ }
+
+
+//---------------------------------- ParameterHolder methods --------------------------------
+
+
+ /**
+ * Specifies the position at which an image button (if any) was clicked.
+ **/
+ void selectImageButtonPosition( SubmitButton imageButton, int x, int y ) {
+ imageButton.setLocation( x, y );
+ }
+
+
+ /**
+ * Iterates through the fixed, predefined parameters in this holder, recording them in the supplied parameter processor.\
+ * These parameters always go on the URL, no matter what encoding method is used.
+ **/
+
+ void recordPredefinedParameters( ParameterProcessor processor ) throws IOException {
+ FormControl[] controls = getPresetParameters();
+ for (int i = 0; i < controls.length; i++) {
+ controls[i].addValues( processor, getCharacterSet() );
+ }
+ }
+
+
+ /**
+ * Iterates through the parameters in this holder, recording them in the supplied parameter processor.
+ **/
+ public void recordParameters( ParameterProcessor processor ) throws IOException {
+ FormControl[] controls = getFormControls();
+ for (int i = 0; i < controls.length; i++) {
+ controls[i].addValues( processor, getCharacterSet() );
+ }
+ }
+
+
+ /**
+ * Removes a parameter name from this collection.
+ **/
+ public void removeParameter( String name ) {
+ setParameter( name, NO_VALUES );
+ }
+
+
+ /**
+ * Sets the value of a parameter in this form.
+ * @param name - the name of the parameter
+ * @param value - the value of the parameter
+ **/
+ public void setParameter( String name, String value ) {
+ setParameter( name, new String[] { value } );
+ }
+
+
+ /**
+ * Sets the multiple values of a parameter in this form. This is generally used when there are multiple
+ * controls with the same name in the form.
+ */
+ public void setParameter( String name, final String[] values ) {
+ FormParameter parameter = getParameter( name );
+ if (parameter == UNKNOWN_PARAMETER) throw new NoSuchParameterException( name );
+ if (parameter.isFileParameter()) {
+ throw new InvalidFileParameterException(name,values);
+ }
+ parameter.setValues( values );
+ }
+
+
+ /**
+ * Sets the multiple values of a file upload parameter in a web request.
+ **/
+ public void setParameter( String name, UploadFileSpec[] files ) {
+ FormParameter parameter = getParameter( name );
+ if ((parameter == null) || (!parameter.isFileParameter()))
+ throw new NoSuchParameterException( name );
+ parameter.setFiles( files );
+ }
+
+
+ /**
+ * Sets the single value of a file upload parameter in this form.
+ * A more convenient way to do this than using {@link #setParameter(String,com.meterware.httpunit.protocol.UploadFileSpec[])}
+ * @since 1.6
+ */
+ public void setParameter( String name, File file ) {
+ setParameter( name, new UploadFileSpec[] { new UploadFileSpec( file ) } );
+ }
+
+
+ /**
+ * Toggles the value of the specified checkbox parameter.
+ * @param name the name of the checkbox parameter
+ * @throws IllegalArgumentException if the specified parameter is not a checkbox or there is more than one
+ * control with that name.
+ * @since 1.5.4
+ */
+ public void toggleCheckbox( String name ) {
+ FormParameter parameter = getParameter( name );
+ if (parameter == null) throw new NoSuchParameterException( name );
+ parameter.toggleCheckbox();
+ }
+
+
+ /**
+ * Toggles the value of the specified checkbox parameter.
+ * @param name the name of the checkbox parameter
+ * @param value of the checkbox parameter
+ * @throws IllegalArgumentException if the specified parameter is not a checkbox or if there is no checkbox
+ * with the specified name and value.
+ * @since 1.6
+ */
+ public void toggleCheckbox( String name, String value ) {
+ FormParameter parameter = getParameter( name );
+ if (parameter == null) throw new NoSuchParameterException( name );
+ parameter.toggleCheckbox( value );
+ }
+
+
+ /**
+ * Sets the value of the specified checkbox parameter.
+ * @param name the name of the checkbox parameter
+ * @param state the new state of the checkbox
+ * @throws IllegalArgumentException if the specified parameter is not a checkbox or there is more than one
+ * control with that name.
+ * @since 1.5.4
+ */
+ public void setCheckbox( String name, boolean state ) {
+ FormParameter parameter = getParameter( name );
+ if (parameter == null) throw new NoSuchParameterException( name );
+ parameter.setValue( state );
+ }
+
+
+ /**
+ * Sets the value of the specified checkbox parameter.
+ * @param name the name of the checkbox parameter
+ * @param value of the checkbox parameter
+ * @param state the new state of the checkbox
+ * @throws IllegalArgumentException if the specified parameter is not a checkbox or if there is no checkbox
+ * with the specified name and value.
+ * @since 1.6
+ */
+ public void setCheckbox( String name, String value, boolean state ) {
+ FormParameter parameter = getParameter( name );
+ if (parameter == null) throw new NoSuchParameterException( name );
+ parameter.setValue( value, state );
+ }
+
+
+ public class Scriptable extends HTMLElementScriptable implements NamedDelegate, FormScriptable {
+ public String getAction() { return WebForm.this.getAction(); }
+ public void setAction( String newAction ) { setDestination( newAction ); _presetParameters = null; }
+
+
+ public void submit() throws IOException, SAXException {
+ submitRequest( getScriptedSubmitRequest() );
+ }
+
+
+ public void reset() throws IOException, SAXException {
+ resetControls();
+ }
+
+
+ public String getName() {
+ return WebForm.this.getID().length() != 0 ? WebForm.this.getID() : WebForm.this.getName();
+ }
+
+
+ /**
+ * get the Object for the given propertyName
+ * @param propertyName - the name of the property to get
+ * @return the Object for the property
+ */
+ public Object get( String propertyName ) {
+ if (propertyName.equals( "target" )) {
+ return getTarget();
+ } else if (propertyName.equals( "action" )) {
+ return getAction();
+ } else if (propertyName.equals( "length" )) {
+ return new Integer(getFormControls().length);
+ } else {
+ final FormParameter parameter = getParameter( propertyName );
+ if (parameter != UNKNOWN_PARAMETER) return parameter.getScriptableObject();
+ FormControl control = getControlWithID( propertyName );
+ return control == null ? super.get( propertyName ) : control.getScriptingHandler();
+ }
+ }
+
+
+ /**
+ * Sets the value of the named property. Will throw a runtime exception if the property does not exist or
+ * cannot accept the specified value.
+ * @param propertyName - the name of the property
+ * @param value - the new value
+ **/
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equals( "target" )) {
+ setTargetAttribute( value.toString() );
+ } else if (propertyName.equals( "action" )) {
+ setAction( value.toString() );
+ } else if (value instanceof String) {
+ setParameterValue( propertyName, (String) value );
+ } else if (value instanceof Number) {
+ setParameterValue( propertyName, HttpUnitUtils.trimmedValue( (Number) value ) );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+
+
+ public void setParameterValue( String name, String value ) {
+ final Object scriptableObject = getParameter( name ).getScriptableObject();
+ if (scriptableObject instanceof ScriptableDelegate) {
+ ((ScriptableDelegate) scriptableObject).set( "value", value );
+ } else if (scriptableObject instanceof ScriptableDelegate[]) {
+ ((ScriptableDelegate[]) scriptableObject)[0].set( "value", value );
+ }
+ }
+
+
+ public ScriptableDelegate[] getElementDelegates() {
+ FormControl[] controls = getFormControls();
+ ScriptableDelegate[] result = new ScriptableDelegate[ controls.length ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (ScriptableDelegate) controls[i].getScriptingHandler();
+ }
+ return result;
+ }
+
+
+ public ScriptableDelegate[] getElementsByTagName( String name ) throws SAXException {
+ return getDelegates( getHTMLPage().getElementsByTagName( getElement(), name ) );
+ }
+
+
+ Scriptable() {
+ super( WebForm.this );
+ }
+ }
+
+
+//---------------------------------- package members --------------------------------
+
+ /**
+ * Contructs a web form given the URL of its source page and the DOM extracted
+ * from that page.
+ **/
+ WebForm( WebResponse response, URL baseURL, Node node, FrameSelector frame, String defaultTarget, String characterSet, ElementRegistry registry ) {
+ super( response, node, baseURL, "action", frame, defaultTarget );
+ _characterSet = characterSet;
+ _registry = registry;
+ _domElement = (HTMLFormElement) node;
+ }
+
+
+ /**
+ * Returns the form control which is part of this form with the specified ID.
+ */
+ public FormControl getControlWithID( String id ) {
+ FormControl[] controls = getFormControls();
+ for (int i = 0; i < controls.length; i++) {
+ FormControl control = controls[i];
+ if (control.getID().equals(id)) return control;
+ }
+ return null;
+ }
+
+
+//---------------------------------- private members --------------------------------
+
+ private SubmitButton getDefaultButton() {
+ if (getSubmitButtons().length == 1) {
+ return getSubmitButtons()[0];
+ } else {
+ return getSubmitButton( "" );
+ }
+ }
+
+
+ /**
+ * get the Vector of submit buttons - will always contain at least
+ * one button - if the original vector has none a faked submit button will be added
+ * @return a Vector with the submit buttons
+ */
+ private Vector getSubmitButtonVector() {
+ if (_buttonVector == null) {
+ _buttonVector = new Vector();
+ FormControl[] controls = getFormControls();
+ for (int i = 0; i < controls.length; i++) {
+ FormControl control = controls[ i ];
+ if (control instanceof SubmitButton) {
+ SubmitButton sb=(SubmitButton)control;
+ sb.rememberEnableState();
+ _buttonVector.add( sb );
+ }
+ }
+
+ /**
+ * make sure that there is always at least one submit button
+ * if none is in the Vector add a faked one
+ */
+ if (_buttonVector.isEmpty())
+ _buttonVector.addElement( SubmitButton.createFakeSubmitButton( this ) );
+ }
+ return _buttonVector;
+ }
+
+
+ private FormControl[] getPresetParameters() {
+ if (_presetParameters == null) {
+ _presets = new ArrayList();
+ loadDestinationParameters();
+ _presetParameters = (FormControl[]) _presets.toArray( new FormControl[ _presets.size() ] );
+ }
+ return _presetParameters;
+ }
+
+
+ FormControl newFormControl( Node child ) {
+ return FormControl.newFormParameter( this, child );
+ }
+
+
+ /**
+ * Returns an array of form parameter attributes for this form.
+ **/
+ private FormControl[] getFormControls() {
+ HTMLCollection controlElements = _domElement.getElements();
+ FormControl[] controls = new FormControl[ controlElements.getLength() ];
+ for (int i = 0; i < controls.length; i++) {
+ controls[i] = getControlForNode( controlElements.item( i ) );
+ }
+ return controls;
+ }
+
+
+ private FormControl getControlForNode( Node node ) {
+ if (_registry.hasNode( node )) {
+ return (FormControl) _registry.getRegisteredElement( node );
+ } else {
+ return (FormControl) _registry.registerElement( node, newFormControl( node ) );
+ }
+ }
+
+
+ /**
+ * get the form parameter with the given name
+ * @param name
+ * @return the form parameter with this name
+ */
+ public FormParameter getParameter( String name ) {
+ final FormParameter parameter = ((FormParameter) getFormParameters().get( name ));
+ return parameter != null ? parameter : UNKNOWN_PARAMETER;
+ }
+
+
+ /**
+ * Returns a map of parameter name to form parameter objects. Each form parameter object represents the set of form
+ * controls with a particular name. Unnamed parameters are ignored.
+ */
+ private Map getFormParameters() {
+ Map formParameters = new HashMap();
+ loadFormParameters( formParameters, getPresetParameters() );
+ loadFormParameters( formParameters, getFormControls() );
+ return formParameters;
+ }
+
+
+ private void loadFormParameters( Map formParameters, FormControl[] controls ) {
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].getName().length() == 0) continue;
+ FormParameter parameter = (FormParameter) formParameters.get( controls[i].getName() );
+ if (parameter == null) {
+ parameter = new FormParameter();
+ formParameters.put( controls[i].getName(), parameter );
+ }
+ parameter.addControl( controls[i] );
+ }
+ }
+
+
+ static {
+ MATCH_NAME = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ return HttpUnitUtils.matches( ((WebForm) htmlElement).getName(), (String) criteria );
+ }
+ };
+
+ }
+
+
+//===========================---===== exception class NoSuchParameterException =========================================
+
+ /**
+ * This exception is thrown on an attempt to set a file parameter to a non file type
+ **/
+ class InvalidFileParameterException extends IllegalRequestParameterException {
+
+
+ /**
+ * construct a new InvalidFileParameterException for the given parameter name and value list
+ * @param parameterName
+ * @param values
+ */
+ InvalidFileParameterException( String parameterName, String[] values ) {
+ _parameterName = parameterName;
+ _values=values;
+ }
+
+
+ /**
+ * get the message for this exception
+ */
+ public String getMessage() {
+ String valueList="";
+ String delim="";
+ for (int i=0;i<_values.length;i++) {
+ valueList+=delim+"'"+_values[i]+"'";
+ delim=", ";
+ }
+ String msg="The file parameter with the name '"+_parameterName+"' must have type File but the string values "+valueList+" where supplied";
+ return msg;
+ }
+
+
+ private String _parameterName;
+ private String[] _values;
+ }
+
+ /**
+ * This exception is thrown on an attempt to set a parameter to a value not permitted to it by the form.
+ **/
+ class NoSuchParameterException extends IllegalRequestParameterException {
+
+
+ NoSuchParameterException( String parameterName ) {
+ _parameterName = parameterName;
+ }
+
+
+ public String getMessage() {
+ return "No parameter named '" + _parameterName + "' is defined in the form";
+ }
+
+
+ private String _parameterName;
+
+ }
+
+
+//============================= exception class IllegalUnnamedSubmitButtonException ======================================
+
+
+ /**
+ * This exception is thrown on an attempt to define a form request with a button not defined on that form.
+ **/
+ class IllegalUnnamedSubmitButtonException extends IllegalRequestParameterException {
+
+
+ IllegalUnnamedSubmitButtonException() {
+ }
+
+
+ public String getMessage() {
+ return "This form has more than one submit button, none unnamed. You must specify the button to be used.";
+ }
+
+ }
+
+
+//============================= exception class IllegalSubmitButtonException ======================================
+
+
+ /**
+ * This exception is thrown on an attempt to define a form request with a button not defined on that form.
+ **/
+ class IllegalSubmitButtonException extends IllegalRequestParameterException {
+
+
+ IllegalSubmitButtonException( SubmitButton button ) {
+ _name = button.getName();
+ _value = button.getValue();
+ }
+
+
+ IllegalSubmitButtonException( String name, String value ) {
+ _name = name;
+ _value = value;
+ }
+
+
+ public String getMessage() {
+ return "Specified submit button (name=\"" + _name + "\" value=\"" + _value + "\") not part of this form.";
+ }
+
+
+ private String _name;
+ private String _value;
+
+ }
+
+//============================= exception class IllegalUnnamedSubmitButtonException ======================================
+
+
+
+}
+
+
+
+//========================================== class PresetFormParameter =================================================
+
+
+ class PresetFormParameter extends FormControl {
+
+ PresetFormParameter( WebForm form, String name, String value ) {
+ super( form );
+ _name = name;
+ _value = value;
+ }
+
+
+ /**
+ * Returns the name of this control..
+ **/
+ public String getName() {
+ return _name;
+ }
+
+
+ /**
+ * Returns true if this control is read-only.
+ **/
+ public boolean isReadOnly() {
+ return true;
+ }
+
+
+ /**
+ * Returns true if this control accepts free-form text.
+ **/
+ public boolean isTextControl() {
+ return true;
+ }
+
+
+ /**
+ * Remove any required values for this control from the list, throwing an exception if they are missing.
+ **/
+ void claimRequiredValues( List values ) {
+ if (_value != null) claimValueIsRequired( values, _value );
+ }
+
+
+ public String getType() {
+ return UNDEFINED_TYPE;
+ }
+
+ /**
+ * Returns the current value(s) associated with this control. These values will be transmitted to the server
+ * if the control is 'successful'.
+ **/
+ public String[] getValues() {
+ if (_values == null) _values = new String[] { _value };
+ return _values;
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ processor.addParameter( _name, _value, characterSet );
+ }
+
+
+ private String _name;
+ private String _value;
+ private String[] _values;
+ }
+
+
+
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebFrame.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebFrame.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebFrame.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,85 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+import java.net.URL;
+
+import org.w3c.dom.Node;
+
+/**
+ * A frame in a web page.
+ **/
+class WebFrame extends HTMLElementBase {
+
+ private FrameSelector _selector;
+
+ private WebResponse _response;
+ private Node _element;
+
+ private URL _baseURL;
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return _response.getDocumentScriptable();
+ }
+
+
+//---------------------------------------- package methods -----------------------------------------
+
+
+ WebFrame( WebResponse response, URL baseURL, Node frameNode, FrameSelector parentFrame ) {
+ super( frameNode );
+ _response = response;
+ _element = frameNode;
+ _baseURL = baseURL;
+ _selector = getFrameSelector( parentFrame );
+ }
+
+
+ String getFrameName() {
+ return _selector.getName();
+ }
+
+
+ FrameSelector getSelector() {
+ return _selector;
+ }
+
+
+ private FrameSelector getFrameSelector( FrameSelector parentFrame ) {
+ return FrameHolder.newNestedFrame( parentFrame, super.getName() );
+ }
+
+
+ WebRequest getInitialRequest() {
+ return new GetMethodWebRequest( _baseURL,
+ HttpUnitUtils.trimFragment( NodeUtils.getNodeAttribute( _element, "src" ) ),
+ _selector );
+ }
+
+
+ boolean hasInitialRequest() {
+ return NodeUtils.getNodeAttribute( _element, "src" ).length() > 0;
+ }
+
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebImage.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebImage.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebImage.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,116 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2006, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.NamedDelegate;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+
+import java.net.URL;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.html.HTMLImageElement;
+
+
+/**
+ * Represents an image in an HTML document.
+ *
+ * @author Russell Gold
+ **/
+public class WebImage extends FixedURLWebRequestSource {
+
+ private HTMLImageElement _element;
+ private ParsedHTML _parsedHTML;
+
+
+ WebImage( WebResponse response, ParsedHTML parsedHTML, URL baseURL, HTMLImageElement element, FrameSelector sourceFrame, String defaultTarget, String characterSet ) {
+ super( response, element, baseURL, "src", sourceFrame, defaultTarget, characterSet );
+ _element = element;
+ _parsedHTML = parsedHTML;
+ }
+
+
+ public String getName() {
+ return _element.getName();
+ }
+
+
+ public String getSource() {
+ return _element.getSrc();
+ }
+
+
+ public String getAltText() {
+ return _element.getAlt();
+ }
+
+
+ public WebLink getLink() {
+ return _parsedHTML.getFirstMatchingLink( new HTMLElementPredicate() {
+
+ public boolean matchesCriteria( Object link, Object parentNode ) {
+ for (Node parent = (Node) parentNode; parent != null; parent = parent.getParentNode()) {
+ if (parent.equals( ((WebLink) link).getElement() )) return true;
+ }
+ return false;
+ }
+ }, _element.getParentNode() );
+ }
+
+
+
+ public class Scriptable extends HTMLElementScriptable implements NamedDelegate {
+
+ public Scriptable() {
+ super( WebImage.this );
+ }
+
+
+ public String getName() {
+ return WebImage.this.getID().length() != 0 ? WebImage.this.getID() : WebImage.this.getName();
+ }
+
+
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "src" )) {
+ return getSource();
+ } else if(propertyName.equalsIgnoreCase( "name" )) {
+ return getName();
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equalsIgnoreCase( "src" )) {
+ if (value != null) _element.setSrc( value.toString() );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+ }
+
+//---------------------------------- WebRequestSource methods ------------------------------------------
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebLink.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebLink.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebLink.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,208 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.NamedDelegate;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.dom.HTMLElementImpl;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+/**
+ * This class represents a link in an HTML page. Users of this class may examine the
+ * structure of the link (as a DOM), or create a {@link WebRequest} to simulate clicking
+ * on the link.
+ *
+ * @author Russell Gold
+ * @author Russell Gold
+ * @since 1.6
+ **/
+public class WebList extends HTMLElementBase {
+
+ /** Indicator of an ordered list (HTML tag <ol>) */
+ public static final int ORDERED_LIST = 1;
+
+ /** Indicator of a bullet list (HTML tag <ul>) */
+ public static final int BULLET_LIST = 2;
+
+ private WebResponse _response;
+ private FrameSelector _frame;
+ private URL _baseURL;
+ private String _baseTarget;
+ private String _characterSet;
+
+ private ArrayList _items = new ArrayList();
+ private int _listType;
+
+
+ public WebList( WebResponse response, FrameSelector frame, URL baseURL, String baseTarget, Element element, String characterSet ) {
+ super( element );
+ if (element.getNodeName().equalsIgnoreCase( "ol" )) {
+ _listType = ORDERED_LIST;
+ } else if (element.getNodeName().equalsIgnoreCase( "ul" )) {
+ _listType = BULLET_LIST;
+ }
+ _response = response;
+ _frame = frame;
+ _baseURL = baseURL;
+ _baseTarget = baseTarget;
+ _characterSet = characterSet;
+ }
+
+
+ public int getListType() {
+ return _listType;
+ }
+
+
+ public TextBlock[] getItems() {
+ return (TextBlock[]) _items.toArray( new TextBlock[ _items.size() ] );
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return _response.getDocumentScriptable();
+ }
+
+
+ TextBlock addNewItem( Element element ) {
+ TextBlock listItem = new TextBlock( _response, _frame, _baseURL, _baseTarget, element, _characterSet );
+ _items.add( listItem );
+ return listItem;
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequest.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequest.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequest.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,665 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2004,2007 Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.protocol.UploadFileSpec;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+/**
+ * A request sent to a web server.
+ **/
+abstract
+public class WebRequest {
+
+ static final String REFERER_HEADER_NAME = "Referer";
+
+ private static URLStreamHandler JAVASCRIPT_STREAM_HANDLER = new JavascriptURLStreamHandler();
+ private static URLStreamHandler HTTPS_STREAM_HANDLER = new HttpsURLStreamHandler();
+
+ private final ParameterHolder _parameterHolder;
+
+ private URL _urlBase;
+ private FrameSelector _sourceFrame;
+ private String _requestTarget;
+ private String _urlString;
+ private Hashtable _headers;
+ private WebRequestSource _webRequestSource;
+ private WebResponse _referringPage;
+
+ private SubmitButton _button;
+ private Element _sourceElement;
+ private String _characterSet;
+
+
+ /**
+ * Sets the value of a header to be sent with this request. A header set here will override any matching header set
+ * in the WebClient when the request is actually sent.
+ * @param headerName - the name of the header
+ * @param headerValue - the value to be set
+ */
+ public void setHeaderField( String headerName, String headerValue ) {
+ getHeaderDictionary().put( headerName, headerValue );
+ }
+
+ /**
+ * Returns a copy of the headers to be sent with this request.
+ * @return the dictionary of headers
+ **/
+ public Dictionary getHeaders() {
+ return (Dictionary) getHeaderDictionary().clone();
+ }
+
+
+ /**
+ * Returns the final URL associated with this web request.
+ * @return the Uniform Resource Locator for this Web request
+ * @throws MalformedURLException if the URL is not o.k.
+ **/
+ public URL getURL() throws MalformedURLException {
+ if (getURLBase() == null || getURLBase().toString().indexOf( "?" ) < 0) {
+ return newURL( getURLBase(), getURLString() );
+ } else {
+ final String urlBaseString = getURLBase().toString();
+ URL newurlbase = new URL( urlBaseString.substring( 0, urlBaseString.indexOf( "?" ) ) );
+ return newURL( newurlbase, getURLString() );
+ }
+ }
+
+
+ /**
+ * Creates a new URL, handling the case where the relative URL begins with a '?'
+ * @param base - the URL to start from
+ * @param spec - additional specification string
+ * @return the URL
+ */
+ private URL newURL( final URL base, final String spec ) throws MalformedURLException {
+ if (spec.toLowerCase().startsWith( "javascript:" )) {
+ return new URL( "javascript", null, -1, spec.substring( "javascript:".length() ), JAVASCRIPT_STREAM_HANDLER );
+ } else if (spec.toLowerCase().startsWith( "https:" ) && !HttpsProtocolSupport.hasHttpsSupport()) {
+ return new URL( "https", null, -1, spec.substring( "https:".length() ), HTTPS_STREAM_HANDLER );
+ } else {
+ if (getURLBase() == null || getURLString().indexOf( ':' ) > 0) {
+ if (getURLString().indexOf(':') <= 0) {
+ throw new RuntimeException( "No protocol specified in URL '" + getURLString() + "'" );
+ }
+ HttpsProtocolSupport.verifyProtocolSupport( getURLString().substring( 0, getURLString().indexOf( ':' ) ) );
+ }
+ return spec.startsWith( "?" ) ? new URL( base + spec ) : newCombinedURL( base, spec );
+ }
+ }
+
+
+ private URL newCombinedURL( final URL base, final String spec ) throws MalformedURLException {
+ if (base == null) return new URL( getNormalizedURL( spec ) );
+ else if (spec.startsWith( ".." )) return new URL( getNormalizedURL( getURLDirectory( base ) + spec ) );
+ else return new URL( base, getNormalizedURL( spec ) );
+ }
+
+
+ private String getURLDirectory( final URL base ) {
+ String url = base.toExternalForm();
+ int i = url.lastIndexOf( '/' );
+ return url.substring( 0, i+1 );
+ }
+
+
+ private String getNormalizedURL( String url ) {
+ int questionIndex = url.indexOf( '?' );
+ if (questionIndex < 0) return getNormalizedPath( url );
+ return getNormalizedPath( url.substring( 0, questionIndex ) ) + url.substring( questionIndex );
+ }
+
+
+ private String getNormalizedPath( String path ) {
+ if (path.lastIndexOf( "//" ) > path.lastIndexOf( "://" ) + 1) return getNormalizedPath( stripDoubleSlashes( path ) );
+ if (path.indexOf( "/.." ) > 0) return getNormalizedPath( stripUpNavigation( path ) );
+ if (path.indexOf( "/./" ) > 0) return getNormalizedPath( stripInPlaceNavigation( path ) );
+ return path;
+ }
+
+
+ private String stripInPlaceNavigation( String url ) {
+ int i = url.lastIndexOf( "/./" );
+ return url.substring( 0, i+1 ) + url.substring( i+2 );
+ }
+
+
+ private String stripUpNavigation( String url ) {
+ int i = url.indexOf( "/.." );
+ int j = url.lastIndexOf( "/", i-1 );
+ return url.substring( 0, j+1 ) + url.substring( i+ 3 );
+ }
+
+
+ private String stripDoubleSlashes( String url ) {
+ int i = url.lastIndexOf( "//" );
+ return url.substring( 0, i ) + url.substring( i+1 );
+ }
+
+
+ /**
+ * Returns the target for this web request.
+ */
+ public String getTarget() {
+ return _requestTarget;
+ }
+
+
+ /**
+ * Returns the frame from which this request originates.
+ */
+ FrameSelector getSourceFrame() {
+ return _sourceFrame;
+ }
+
+
+ /**
+ * the HTTP method defined for this request e.g. DELETE,OPTIONS,HEAD
+ */
+ protected String method;
+
+
+ /**
+ * @return the method
+ */
+ public String getMethod() {
+ return method;
+ }
+
+
+ /**
+ * Returns the query string defined for this request. The query string is sent to the HTTP server as part of
+ * the request header. This default implementation returns an empty string.
+ **/
+ public String getQueryString() {
+ return "";
+ }
+
+
+//------------------------------------- ParameterCollection methods ------------------------------------
+
+
+ /**
+ * Sets the value of a parameter in a web request.
+ **/
+ public void setParameter( String name, String value ) {
+ _parameterHolder.setParameter( name, value );
+ }
+
+
+ /**
+ * Sets the multiple values of a parameter in a web request.
+ **/
+ public void setParameter( String name, String[] values ) {
+ _parameterHolder.setParameter( name, values );
+ }
+
+
+ /**
+ * Sets the multiple values of a file upload parameter in a web request.
+ **/
+ public void setParameter( String parameterName, UploadFileSpec[] files ) {
+ if (!maySelectFile( parameterName )) throw new IllegalNonFileParameterException( parameterName );
+ if (!isMimeEncoded()) throw new MultipartFormRequiredException();
+ _parameterHolder.setParameter( parameterName, files );
+ }
+
+
+ /**
+ * Specifies the click position for the submit button. When a user clioks on an image button, not only the name
+ * and value of the button, but also the position of the mouse at the time of the click is submitted with the form.
+ * This method allows the caller to override the position selected when this request was created.
+ *
+ * @exception IllegalRequestParameterException thrown if the request was not created from a form with an image button.
+ **/
+ public void setImageButtonClickPosition( int x, int y ) throws IllegalRequestParameterException {
+ if (_button == null) throw new IllegalButtonPositionException();
+ _parameterHolder.selectImageButtonPosition( _button, x, y );
+ }
+
+
+ /**
+ * Returns true if the specified parameter is a file field.
+ **/
+ public boolean isFileParameter( String name ) {
+ return _parameterHolder.isFileParameter( name );
+ }
+
+
+ /**
+ * Sets the file for a parameter upload in a web request.
+ **/
+ public void selectFile( String parameterName, File file ) {
+ setParameter( parameterName, new UploadFileSpec[] { new UploadFileSpec( file ) } );
+ }
+
+
+ /**
+ * Sets the file for a parameter upload in a web request.
+ **/
+ public void selectFile( String parameterName, File file, String contentType ) {
+ setParameter( parameterName, new UploadFileSpec[] { new UploadFileSpec( file, contentType ) } );
+ }
+
+
+ /**
+ * Sets the file for a parameter upload in a web request.
+ **/
+ public void selectFile( String parameterName, String fileName, InputStream inputStream, String contentType ) {
+ setParameter( parameterName, new UploadFileSpec[] { new UploadFileSpec( fileName, inputStream, contentType ) } );
+ }
+
+
+ /**
+ * Returns an array of all parameter names defined as part of this web request.
+ * @since 1.3.1
+ **/
+ public String[] getRequestParameterNames() {
+ final HashSet names = new HashSet();
+ ParameterProcessor pp = new ParameterProcessor() {
+ public void addParameter( String name, String value, String characterSet ) throws IOException {
+ names.add( name );
+ }
+ public void addFile( String parameterName, UploadFileSpec fileSpec ) throws IOException {
+ names.add( parameterName );
+ }
+ };
+
+ try {
+ _parameterHolder.recordPredefinedParameters( pp );
+ _parameterHolder.recordParameters( pp );
+ } catch (IOException e) {}
+
+ return (String[]) names.toArray( new String[ names.size() ] );
+ }
+
+
+ /**
+ * Returns the value of a parameter in this web request.
+ * @return the value of the named parameter, or empty string
+ * if it is not set.
+ **/
+ public String getParameter( String name ) {
+ String[] values = getParameterValues( name );
+ return values.length == 0 ? "" : values[0];
+ }
+
+
+ /**
+ * Returns the multiple default values of the named parameter.
+ **/
+ public String[] getParameterValues( String name ) {
+ return _parameterHolder.getParameterValues( name );
+ }
+
+
+ /**
+ * Removes a parameter from this web request.
+ **/
+ public void removeParameter( String name ) {
+ _parameterHolder.removeParameter( name );
+ }
+
+
+//------------------------------------- Object methods ------------------------------------
+
+
+ public String toString() {
+ return getMethod() + " request for (" + getURLBase() + ") " + getURLString();
+ }
+
+
+
+//------------------------------------- protected members ------------------------------------
+
+
+ /**
+ * Constructs a web request using an absolute URL string.
+ **/
+ protected WebRequest( String urlString ) {
+ this( null, urlString );
+ }
+
+
+ /**
+ * Constructs a web request using a base URL and a relative URL string.
+ **/
+ protected WebRequest( URL urlBase, String urlString ) {
+ this( urlBase, urlString, TOP_FRAME );
+ }
+
+
+ /**
+ * Constructs a web request using a base request and a relative URL string.
+ **/
+ protected WebRequest( WebRequest baseRequest, String urlString, String target ) throws MalformedURLException {
+ this( baseRequest.getURL(), urlString, target );
+ }
+
+
+ /**
+ * Constructs a web request using a base URL, a relative URL string, and a target.
+ **/
+ protected WebRequest( URL urlBase, String urlString, String target ) {
+ this( urlBase, urlString, FrameSelector.TOP_FRAME, target );
+ }
+
+
+ /**
+ * Constructs a web request using a base URL, a relative URL string, and a target.
+ **/
+ protected WebRequest( WebResponse referer, Element sourceElement, URL urlBase, String urlString, String target ) {
+ this( urlBase, urlString, referer.getFrame(), target != null ? target : referer.getBaseTarget() );
+ _sourceElement = sourceElement;
+ _referringPage = referer;
+ setHeaderField( REFERER_HEADER_NAME, referer.getURL().toExternalForm() );
+ }
+
+
+ /**
+ * Constructs a web request using a base URL, a relative URL string, and a target.
+ **/
+ protected WebRequest( URL urlBase, String urlString, FrameSelector frame, String target ) {
+ this( urlBase, urlString, frame, target, new UncheckedParameterHolder() );
+ }
+
+
+ /**
+ * Constructs a web request from a form.
+ * @param sourceForm - the WebForm to startFrom
+ * @param parameterHolder - the parameter holder
+ * @param button - the submit button
+ * @param x - x position
+ * @param y - y position
+ **/
+ protected WebRequest( WebForm sourceForm, ParameterHolder parameterHolder, SubmitButton button, int x, int y ) {
+ this( sourceForm, parameterHolder );
+ // [ 1443333 ] Allow unnamed Image input elements to submit x,y values
+ if (button != null && button.isValidImageButton() ) {
+ _button = button;
+ _parameterHolder.selectImageButtonPosition( _button, x, y );
+ }
+ }
+
+
+ protected WebRequest( WebRequestSource requestSource, ParameterHolder parameterHolder ) {
+ this( requestSource.getBaseURL(), requestSource.getRelativePage(), requestSource.getFrame(), requestSource.getTarget(), parameterHolder );
+ _webRequestSource = requestSource;
+ _sourceElement = requestSource.getElement();
+ }
+
+
+ static ParameterHolder newParameterHolder( WebRequestSource requestSource ) {
+ if (HttpUnitOptions.getParameterValuesValidated()) {
+ return requestSource;
+ } else {
+ return new UncheckedParameterHolder( requestSource );
+ }
+ }
+
+
+ /**
+ * Constructs a web request using a base URL, a relative URL string, and a target.
+ **/
+ private WebRequest( URL urlBase, String urlString, FrameSelector sourceFrame, String requestTarget, ParameterHolder parameterHolder ) {
+ _urlBase = urlBase;
+ _sourceFrame = sourceFrame;
+ _requestTarget = requestTarget;
+ _urlString = urlString.toLowerCase().startsWith( "http" ) ? escape( urlString ) : urlString;
+ _parameterHolder = parameterHolder;
+ _characterSet = parameterHolder.getCharacterSet();
+ }
+
+
+ private static String escape( String urlString ) {
+ if (urlString.indexOf( ' ' ) < 0) return urlString;
+ StringBuffer sb = new StringBuffer();
+
+ int start = 0;
+ do {
+ int index = urlString.indexOf( ' ', start );
+ if (index < 0) {
+ sb.append( urlString.substring( start ) );
+ break;
+ } else {
+ sb.append( urlString.substring( start, index ) ).append( "%20" );
+ start = index+1;
+ }
+ } while (true);
+ return sb.toString();
+ }
+
+
+ /**
+ * Returns true if selectFile may be called with this parameter.
+ */
+ protected boolean maySelectFile( String parameterName )
+ {
+ return isFileParameter( parameterName );
+ }
+
+
+ /**
+ * Returns true if this request is to be MIME-encoded.
+ **/
+ protected boolean isMimeEncoded() {
+ return false;
+ }
+
+
+ /**
+ * Returns the content type of this request. If null, no content is specified.
+ */
+ protected String getContentType() {
+ return null;
+ }
+
+
+ /**
+ * Returns the character set required for this request.
+ **/
+ final
+ protected String getCharacterSet() {
+ return _characterSet;
+ }
+
+
+ /**
+ * Performs any additional processing necessary to complete the request.
+ **/
+ protected void completeRequest( URLConnection connection ) throws IOException {
+ if (connection instanceof HttpURLConnection) ((HttpURLConnection) connection).setRequestMethod( getMethod() );
+ }
+
+
+ /**
+ * Writes the contents of the message body to the specified stream.
+ */
+ protected void writeMessageBody( OutputStream stream ) throws IOException {
+ }
+
+
+ final
+ protected URL getURLBase() {
+ return _urlBase;
+ }
+
+
+//------------------------------------- protected members ---------------------------------------------
+
+
+ protected String getURLString() {
+ final String queryString = getQueryString();
+ if (queryString.length() == 0) {
+ return _urlString;
+ } else {
+ return _urlString + "?" + queryString;
+ }
+ }
+
+
+ final
+ protected ParameterHolder getParameterHolder() {
+ return _parameterHolder;
+ }
+
+
+//---------------------------------- package members --------------------------------
+
+ /** The target indicating the topmost frame of a window. **/
+ static final String TOP_FRAME = "_top";
+
+ /** The target indicating the parent of a frame. **/
+ static final String PARENT_FRAME = "_parent";
+
+ /** The target indicating a new, empty window. **/
+ static final String NEW_WINDOW = "_blank";
+
+ /** The target indicating the same frame. **/
+ static final String SAME_FRAME = "_self";
+
+
+ Hashtable getHeaderDictionary() {
+ if (_headers == null) {
+ _headers = new Hashtable();
+ if (getContentType() != null) _headers.put( "Content-Type", getContentType() );
+ }
+ return _headers;
+ }
+
+
+ String getReferer() {
+ return _headers == null ? null : (String) _headers.get( REFERER_HEADER_NAME );
+ }
+
+
+ ScriptingHandler getSourceScriptingHandler() {
+ WebRequestSource wrs = _webRequestSource;
+ if (wrs != null) {
+ return wrs.getScriptingHandler();
+ } else if (_referringPage != null && _sourceElement != null) {
+ try {
+ _referringPage.getReceivedPage().getElement( _sourceElement ).getScriptingHandler();
+ } catch (SAXException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+}
+
+//======================================== class JavaScriptURLStreamHandler ============================================
+
+
+class JavascriptURLStreamHandler extends URLStreamHandler {
+
+ protected URLConnection openConnection( URL u ) throws IOException {
+ return null;
+ }
+}
+
+
+//======================================== class HttpsURLStreamHandler ============================================
+
+
+class HttpsURLStreamHandler extends URLStreamHandler {
+
+ protected URLConnection openConnection( URL u ) throws IOException {
+ throw new RuntimeException( "https support requires the Java Secure Sockets Extension. See http://java.sun.com/products/jsse" );
+ }
+}
+
+
+//============================= exception class IllegalNonFileParameterException ======================================
+
+
+/**
+ * This exception is thrown on an attempt to set a non-file parameter to a file value.
+ **/
+class IllegalNonFileParameterException extends IllegalRequestParameterException {
+
+
+ IllegalNonFileParameterException( String parameterName ) {
+ _parameterName = parameterName;
+ }
+
+
+ public String getMessage() {
+ return "Parameter '" + _parameterName + "' is not a file parameter and may not be set to a file value.";
+ }
+
+
+ private String _parameterName;
+
+}
+
+
+//============================= exception class MultipartFormRequiredException ======================================
+
+
+/**
+ * This exception is thrown on an attempt to set a file parameter in a form that does not specify MIME encoding.
+ **/
+class MultipartFormRequiredException extends IllegalRequestParameterException {
+
+
+ MultipartFormRequiredException() {
+ }
+
+
+ public String getMessage() {
+ return "The request does not use multipart/form-data encoding, and cannot be used to upload files ";
+ }
+
+}
+
+
+//============================= exception class IllegalButtonPositionException ======================================
+
+
+/**
+ * This exception is thrown on an attempt to set a file parameter in a form that does not specify MIME encoding.
+ **/
+class IllegalButtonPositionException extends IllegalRequestParameterException {
+
+
+ IllegalButtonPositionException() {
+ }
+
+
+ public String getMessage() {
+ return "The request was not created with an image button, and cannot accept an image button click position";
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequestSource.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequestSource.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebRequestSource.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,468 @@
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2001-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+package com.meterware.httpunit;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.net.URL;
+import java.util.StringTokenizer;
+import java.io.IOException;
+
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+
+/**
+ * Base class for objects which can be clicked to generate new web requests.
+ *
+ * @author Russell Gold
+ */
+abstract
+public class WebRequestSource extends ParameterHolder implements HTMLElement {
+
+ private FrameSelector _frame;
+
+ /** The name of the destination attribute used to create for the request, including anchors and parameters. **/
+ private String _destinationAttribute;
+ private ScriptingHandler _scriptable;
+
+
+ /**
+ * Returns the ID associated with this request source.
+ **/
+ public String getID() {
+ return getAttribute( "id" );
+ }
+
+
+ /**
+ * Returns the class associated with this request source.
+ **/
+ public String getClassName() {
+ return getAttribute( "class" );
+ }
+
+
+ /**
+ * Returns the name associated with this request source.
+ **/
+ public String getName() {
+ return getAttribute( "name" );
+ }
+
+
+ /**
+ * Returns the title associated with this request source.
+ **/
+ public String getTitle() {
+ return getAttribute( "title" );
+ }
+
+
+ /**
+ * Returns the target for this request source.
+ */
+ public String getTarget() {
+ if (getSpecifiedTarget().length() == 0) {
+ return _defaultTarget;
+ } else {
+ return getSpecifiedTarget();
+ }
+ }
+
+
+ /**
+ * Returns the name of the frame containing this request source.
+ * @deprecated as of 1.6, use #getFrame
+ */
+ public String getPageFrame() {
+ return _frame.getName();
+ }
+
+
+ /**
+ * Returns the frame containing this request source.
+ */
+ public FrameSelector getFrame() {
+ return _frame;
+ }
+
+
+ /**
+ * Returns the fragment identifier for this request source, used to identifier an element within an HTML document.
+ */
+ public String getFragmentIdentifier() {
+ final int hashIndex = getDestination().indexOf( '#' );
+ if (hashIndex < 0) {
+ return "";
+ } else {
+ return getDestination().substring( hashIndex+1 );
+ }
+ }
+
+
+ /**
+ * Returns a copy of the domain object model subtree associated with this entity.
+ **/
+ public Node getDOMSubtree() {
+ return _node.cloneNode( /* deep */ true );
+ }
+
+
+ /**
+ * Creates and returns a web request from this request source.
+ **/
+ abstract
+ public WebRequest getRequest();
+
+
+ /**
+ * Returns an array containing the names of any parameters to be sent on a request based on this request source.
+ **/
+ abstract
+ public String[] getParameterNames();
+
+
+ /**
+ * Returns the values of the named parameter.
+ **/
+ abstract
+ public String[] getParameterValues( String name );
+
+
+ /**
+ * Returns the URL relative to the current page which will handle the request.
+ */
+ String getRelativePage() {
+ final String url = getRelativeURL();
+ if (HttpUnitUtils.isJavaScriptURL( url )) return url;
+ final int questionMarkIndex = url.indexOf("?");
+ if (questionMarkIndex >= 1 && questionMarkIndex < url.length() - 1) {
+ return url.substring(0, questionMarkIndex);
+ }
+ return url;
+ }
+
+
+ /**
+ * get the relative URL for a weblink
+ * change spaces to %20
+ * @return the relative URL as a string
+ */
+ protected String getRelativeURL() {
+ String result = HttpUnitUtils.encodeSpaces( HttpUnitUtils.trimFragment( getDestination() ) );
+ if (result.trim().length() == 0) result = getBaseURL().getFile();
+ return result;
+ }
+
+
+//----------------------------- protected members ---------------------------------------------
+
+ /**
+ * Contructs a web request source.
+ * @param response the response from which this request source was extracted
+ * @param node the DOM subtree defining this request source
+ * @param baseURL the URL on which to base all releative URL requests
+ * @param attribute the attribute which defines the relative URL to which requests will be directed
+ **/
+ WebRequestSource( WebResponse response, Node node, URL baseURL, String attribute, FrameSelector frame, String defaultTarget ) {
+ if (node == null) throw new IllegalArgumentException( "node must not be null" );
+ _baseResponse = response;
+ _node = node;
+ _baseURL = baseURL;
+ _destinationAttribute = attribute;
+ _frame = frame;
+ _defaultTarget = defaultTarget;
+ }
+
+
+ protected URL getBaseURL() {
+ return _baseURL;
+ }
+
+
+ protected String getDestination() {
+ return getElement().getAttribute( _destinationAttribute );
+ }
+
+
+ protected void setDestination( String destination ) {
+ getElement().setAttribute( _destinationAttribute, destination );
+ }
+
+
+ /**
+ * Returns the actual DOM for this request source, not a copy.
+ **/
+ protected Element getElement() {
+ return (Element) _node;
+ }
+
+
+ /**
+ * Returns the HTMLPage associated with this request source.
+ */
+ protected HTMLPage getHTMLPage() throws SAXException {
+ return _baseResponse.getReceivedPage();
+ }
+
+
+ /**
+ * Extracts any parameters specified as part of the destination URL, calling addPresetParameter for each one
+ * in the order in which they are found.
+ */
+ final
+ protected void loadDestinationParameters() {
+ StringTokenizer st = new StringTokenizer( getParametersString(), PARAM_DELIM );
+ while (st.hasMoreTokens())
+ stripOneParameter( st.nextToken() );
+ }
+
+
+ /**
+ * submit the given event for the given request
+ * @param event
+ * @param request
+ * @return the response for the submitted Request
+ * @throws IOException
+ * @throws SAXException
+ */
+ protected WebResponse submitRequest( String event, final WebRequest request ) throws IOException, SAXException {
+ WebResponse response = null;
+ if (doEventScript( event ))
+ response = submitRequest( request );
+ if (response == null) response = getCurrentFrameContents();
+ return response;
+ }
+
+ /**
+ * handle the event that has the given script attached
+ * by compiling the eventScript as a function and executing it
+ * @param eventScript - the script to use
+ * @deprecated since 1.7 - use doEventScript instead
+ */
+ public boolean doEvent( String eventScript ) {
+ return doEventScript(eventScript);
+ }
+
+ /**
+ * optional do the event if it's defined
+ * @param eventScript - the script to handle
+ * @return whether the script was handled
+ */
+ public boolean doEventScript(String eventScript) {
+ return this.getScriptingHandler().doEventScript(eventScript);
+ }
+
+
+ public boolean handleEvent(String eventName) {
+ return this.getScriptingHandler().handleEvent(eventName);
+ }
+
+ protected WebResponse getCurrentFrameContents() {
+ return getCurrentFrame( getBaseResponse().getWindow(), _frame );
+ }
+
+
+ private WebResponse getCurrentFrame( WebWindow window, FrameSelector pageFrame ) {
+ return window.hasFrame( pageFrame ) ? window.getFrameContents( pageFrame ) : window.getCurrentPage();
+ }
+
+
+ /**
+ * Submits a request to the web client from which this request source was originally obtained.
+ **/
+ final
+ protected WebResponse submitRequest( WebRequest request ) throws IOException, SAXException {
+ return getDestination().equals( "#" )
+ ? _baseResponse
+ : _baseResponse.getWindow().sendRequest( request );
+ }
+
+
+ /**
+ * Returns the web response containing this request source.
+ */
+ final
+ protected WebResponse getBaseResponse() {
+ return _baseResponse;
+ }
+
+
+ /**
+ * Records a parameter defined by including it in the destination URL.
+ * The value can be null, if the parameter name was not specified with an equals sign.
+ **/
+ abstract
+ protected void addPresetParameter( String name, String value );
+
+
+ /**
+ * get the attribute value for the given name
+ * @param name - the name of the attribute to get
+ */
+ public String getAttribute( final String name ) {
+ return NodeUtils.getNodeAttribute( _node, name );
+ }
+
+ /**
+ * set the attribute with the given name to the given value
+ * @param name - the name of the attribute
+ * @param value - the value to use
+ */
+ public void setAttribute( final String name, final Object value ) {
+ NodeUtils.setNodeAttribute( getNode(), name, (value == null) ? null : value.toString() );
+ }
+
+ /**
+ * remove the given attribute
+ * @param name - the name of the attribute to remove
+ */
+ public void removeAttribute( final String name ) {
+ NodeUtils.removeNodeAttribute( getNode(), name );
+ }
+
+
+ public boolean isSupportedAttribute( String name ) {
+ return false;
+ }
+
+
+ public Node getNode() {
+ return _node;
+ }
+
+
+ /**
+ * Returns the text value of this block.
+ **/
+ public String getText() {
+ if (_node.getNodeType() == Node.TEXT_NODE) {
+ return _node.getNodeValue().trim();
+ } else if (_node == null || !_node.hasChildNodes()) {
+ return "";
+ } else {
+ return NodeUtils.asText( _node.getChildNodes() ).trim();
+ }
+ }
+
+
+ public String getTagName() {
+ return _node.getNodeName();
+ }
+
+
+ String getAttribute( final String name, String defaultValue ) {
+ return NodeUtils.getNodeAttribute( _node, name, defaultValue );
+ }
+
+
+//----------------------------- private members -----------------------------------------------
+
+
+ /**
+ * parameter Delimiter for URL parameters
+ * bug report
+ * [ 1052037 ] Semicolon not supported as URL param delimiter
+ * asks for this to be extended to &;
+ * @see http://www.w3.org/TR/html4/appendix/notes.html#h-B.2 section B2.2
+ *
+ */
+ private static final String PARAM_DELIM = "&";
+
+ /** The web response containing this request source. **/
+ private WebResponse _baseResponse;
+
+ /** The name of the frame in which the response containing this request source is rendered. **/
+ private String _defaultTarget;
+
+ /** The URL of the page containing this entity. **/
+ private URL _baseURL;
+
+ /** The DOM node representing this entity. **/
+ private Node _node;
+
+
+ private String getSpecifiedTarget() {
+ return getAttribute( "target" );
+ }
+
+
+ protected void setTargetAttribute( String value ) {
+ ((Element) _node).setAttribute( "target", value );
+ }
+
+
+ /**
+ * Gets all parameters from a URL
+ **/
+ private String getParametersString() {
+ String url = HttpUnitUtils.trimFragment( getDestination() );
+ if (url.trim().length() == 0) url = getBaseURL().toExternalForm();
+ if (HttpUnitUtils.isJavaScriptURL( url )) return "";
+ final int questionMarkIndex = url.indexOf("?");
+ if (questionMarkIndex >= 1 && questionMarkIndex < url.length() - 1) {
+ return url.substring( questionMarkIndex + 1 );
+ }
+ return "";
+ }
+
+
+ /**
+ * Extracts a parameter of the form
+ *
+ *
+ *
+ *
+ * this can be used like this
+ *
+ * getMetaTagContent("name","robots") will return { "index","follow" }
+ * getMetaTagContent("http-equiv","Expires") will return { "now" }
+ *
+ * @exception SAXException thrown if there is an error parsing this response
+ **/
+ public String[] getMetaTagContent(String attribute, String attributeValue) throws SAXException {
+ return getReceivedPage().getMetaTagContent(attribute, attributeValue);
+ }
+
+
+ /**
+ * Returns the name of the frame containing this page.
+ **/
+ public String getFrameName() {
+ return _frame.getName();
+ }
+
+
+ void setFrame( FrameSelector frame ) {
+ if (!_frame.getName().equals( frame.getName())) throw new IllegalArgumentException( "May not modify the frame name" );
+ _frame = frame;
+ }
+
+
+ /**
+ * Returns the frame containing this page.
+ */
+ FrameSelector getFrame() {
+ return _frame;
+ }
+
+
+ /**
+ * Returns a request to refresh this page, if any. This request will be defined
+ * by a tag in the header. If no tag exists, will return null.
+ **/
+ public WebRequest getRefreshRequest() {
+ readRefreshRequest();
+ return _refreshRequest;
+ }
+
+
+ /**
+ * Returns the delay before normally following the request to refresh this page, if any.
+ * This request will be defined by a tag in the header. If no tag exists,
+ * will return zero.
+ **/
+ public int getRefreshDelay() {
+ readRefreshRequest();
+ return _refreshDelay;
+ }
+
+
+ /**
+ * Returns the response code associated with this response.
+ **/
+ abstract
+ public int getResponseCode();
+
+
+ /**
+ * Returns the response message associated with this response.
+ **/
+ abstract
+ public String getResponseMessage();
+
+
+ /**
+ * Returns the content length of this response.
+ * @return the content length, if known, or -1.
+ */
+ public int getContentLength() {
+ if (_contentLength == UNINITIALIZED_INT) {
+ String length = getHeaderField( "Content-Length" );
+ _contentLength = (length == null) ? -1 : Integer.parseInt( length );
+ }
+ return _contentLength;
+ }
+
+
+ /**
+ * Returns the content type of this response.
+ **/
+ public String getContentType() {
+ if (_contentType == null) readContentTypeHeader();
+ return _contentType;
+ }
+
+
+ /**
+ * Returns the character set used in this response.
+ **/
+ public String getCharacterSet() {
+ if (_characterSet == null) {
+ readContentTypeHeader();
+ if (_characterSet == null) setCharacterSet( getHeaderField( "Charset" ) );
+ if (_characterSet == null) setCharacterSet( HttpUnitOptions.getDefaultCharacterSet() );
+ }
+ return _characterSet;
+ }
+
+
+ /**
+ * Returns a list of new cookie names defined as part of this response.
+ **/
+ public String[] getNewCookieNames() {
+ return getCookieJar().getCookieNames();
+ }
+
+
+ /**
+ * Returns the new cookie value defined as part of this response.
+ **/
+ public String getNewCookieValue( String name ) {
+ return getCookieJar().getCookieValue( name );
+ }
+
+
+ /**
+ * Returns the names of the header fields found in the response.
+ **/
+ abstract
+ public String[] getHeaderFieldNames();
+
+
+ /**
+ * Returns the value for the specified header field. If no such field is defined, will return null.
+ * If more than one header is defined for the specified name, returns only the first found.
+ **/
+ abstract
+ public String getHeaderField( String fieldName );
+
+
+ /**
+ * Returns the text of the response (excluding headers) as a string. Use this method in preference to 'toString'
+ * which may be used to represent internal state of this object.
+ **/
+ public String getText() throws IOException {
+ if (_responseText == null) loadResponseText();
+ return _responseText;
+ }
+
+
+ /**
+ * Returns a buffered input stream for reading the contents of this reply.
+ **/
+ public InputStream getInputStream() throws IOException {
+ if (_inputStream == null) _inputStream = new ByteArrayInputStream( getText().getBytes() );
+ return _inputStream;
+ }
+
+
+ /**
+ * Returns the names of the frames found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing this response
+ **/
+ public String[] getFrameNames() throws SAXException {
+ WebFrame[] frames = getFrames();
+ String[] result = new String[ frames.length ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = frames[i].getFrameName();
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Returns the frames found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing this response
+ **/
+ FrameSelector[] getFrameSelectors() throws SAXException {
+ WebFrame[] frames = getFrames();
+ FrameSelector[] result = new FrameSelector[ frames.length ];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = frames[i].getSelector();
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Returns the contents of the specified subframe of this frameset response.
+ *
+ * @param subFrameName the name of the desired frame as defined in the frameset.
+ **/
+ public WebResponse getSubframeContents( String subFrameName ) {
+ if (_window == null) throw new NoSuchFrameException( subFrameName );
+ return _window.getSubframeContents( _frame, subFrameName );
+ }
+
+
+//---------------------- HTMLSegment methods -----------------------------
+
+
+ /**
+ * Returns the HTMLElement with the specified ID.
+ * @throws SAXException thrown if there is an error parsing the response.
+ */
+ public HTMLElement getElementWithID( String id ) throws SAXException {
+ return getReceivedPage().getElementWithID( id );
+ }
+
+ /**
+ * return the HTMLElements with the specified tag name
+ * @param tagName e.g. "div" or "table"
+ * @return a list of all HTMLElements with that tag name
+ * @throws SAXException
+ * @since 1.7
+ */
+ public HTMLElement[] getElementsByTagName(String tagName) throws SAXException {
+ return getReceivedPage().getElementsByTagName(getDOM(),tagName);
+ }
+
+
+ /**
+ * Returns a list of HTML element names contained in this HTML section.
+ */
+ public String[] getElementNames() throws SAXException {
+ return getReceivedPage().getElementNames();
+ }
+
+
+ /**
+ * Returns the HTMLElements found in this segment with the specified name.
+ */
+ public HTMLElement[] getElementsWithName( String name ) throws SAXException {
+ return getReceivedPage().getElementsWithName( name );
+ }
+
+
+ /**
+ * Returns the HTMLElements found with the specified attribute value.
+ * @since 1.6
+ */
+ public HTMLElement[] getElementsWithAttribute( String name, String value ) throws SAXException {
+ return getReceivedPage().getElementsWithAttribute( name, value );
+ }
+
+
+ /**
+ * Returns the forms found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm[] getForms() throws SAXException {
+ return getReceivedPage().getForms();
+ }
+
+
+ /**
+ * Returns the form found in the page with the specified name.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm getFormWithName( String name ) throws SAXException {
+ return getReceivedPage().getFormWithName( name );
+ }
+
+
+ /**
+ * Returns the form found in the page with the specified ID.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm getFormWithID( String ID ) throws SAXException {
+ return getReceivedPage().getFormWithID( ID );
+ }
+
+
+ /**
+ * Returns the first form found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm getFirstMatchingForm( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getFirstMatchingForm( predicate, criteria );
+ }
+
+
+ /**
+ * Returns all forms found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebForm[] getMatchingForms( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getMatchingForms( predicate, criteria );
+ }
+
+
+ /**
+ * Returns the links found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink[] getLinks() throws SAXException {
+ return getReceivedPage().getLinks();
+ }
+
+
+ /**
+ * Returns the first link which contains the specified text.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getLinkWith( String text ) throws SAXException {
+ return getReceivedPage().getLinkWith( text );
+ }
+
+
+ /**
+ * Returns the first link which contains an image with the specified text as its 'alt' attribute.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getLinkWithImageText( String text ) throws SAXException {
+ return getReceivedPage().getLinkWithImageText( text );
+ }
+
+
+ /**
+ * Returns the link found in the page with the specified name.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getLinkWithName( String name ) throws SAXException {
+ return getReceivedPage().getLinkWithName( name );
+ }
+
+
+ /**
+ * Returns the link found in the page with the specified ID.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getLinkWithID( String ID ) throws SAXException {
+ return getReceivedPage().getLinkWithID( ID );
+ }
+
+
+ /**
+ * Returns the first link found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink getFirstMatchingLink( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getFirstMatchingLink( predicate, criteria );
+ }
+
+
+ /**
+ * Returns all links found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebLink[] getMatchingLinks( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getMatchingLinks( predicate, criteria );
+ }
+
+
+ /**
+ * Returns the images found in the page in the order in which they appear.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebImage[] getImages() throws SAXException {
+ return getReceivedPage().getImages();
+ }
+
+
+ /**
+ * Returns the image found in the page with the specified name attribute.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebImage getImageWithName( String source ) throws SAXException {
+ return getReceivedPage().getImageWithName( source );
+ }
+
+
+ /**
+ * Returns the first image found in the page with the specified src attribute.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebImage getImageWithSource( String source ) throws SAXException {
+ return getReceivedPage().getImageWithSource( source );
+ }
+
+
+ /**
+ * Returns the first image found in the page with the specified alt attribute.
+ **/
+ public WebImage getImageWithAltText( String altText ) throws SAXException {
+ return getReceivedPage().getImageWithAltText( altText );
+ }
+
+
+ public WebApplet[] getApplets() throws SAXException {
+ return getReceivedPage().getApplets();
+ }
+
+
+ /**
+ * Returns an array of text blocks found in the page.
+ * @since 1.6
+ */
+ public TextBlock[] getTextBlocks() throws SAXException {
+ return getReceivedPage().getTextBlocks();
+ }
+
+
+ /**
+ * Returns the text block after the specified block, if any.
+ * @since 1.6
+ */
+ public TextBlock getNextTextBlock( TextBlock block ) throws SAXException {
+ return getReceivedPage().getNextTextBlock( block );
+ }
+
+
+ /**
+ * Returns the first link found in the page matching the specified criteria.
+ * @since 1.6
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public TextBlock getFirstMatchingTextBlock( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getFirstMatchingTextBlock( predicate, criteria );
+ }
+
+
+ /**
+ * Returns a copy of the domain object model tree associated with this response.
+ * If the response is HTML, it will use a special parser which can transform HTML into an XML DOM.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public Document getDOM() throws SAXException {
+ if (isHTML()) {
+ return (Document) getReceivedPage().getDOM();
+ } else {
+ try {
+ return HttpUnitUtils.parse( new InputSource( new StringReader( getText() ) ) );
+ } catch (IOException e) {
+ throw new SAXException( e );
+ }
+ }
+ }
+
+
+ /**
+ * Returns the top-level tables found in this page in the order in which
+ * they appear.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebTable[] getTables() throws SAXException {
+ return getReceivedPage().getTables();
+ }
+
+
+ /**
+ * Returns the first table in the response which matches the specified predicate and value.
+ * Will recurse into any nested tables, as needed.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getFirstMatchingTable( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getFirstMatchingTable( predicate, criteria );
+ }
+
+
+ /**
+ * Returns all tables found in the page matching the specified criteria.
+ * @exception SAXException thrown if there is an error parsing the response.
+ **/
+ public WebTable[] getMatchingTables( HTMLElementPredicate predicate, Object criteria ) throws SAXException {
+ return getReceivedPage().getMatchingTables( predicate, criteria );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as the full text of
+ * its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * Case is ignored.
+ * @exception SAXException thrown if there is an error parsing the response.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableStartingWith( String text ) throws SAXException {
+ return getReceivedPage().getTableStartingWith( text );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as a prefix of the text of
+ * its first non-blank row and non-blank column. Will recurse into any nested tables, as needed.
+ * Case is ignored.
+ * @exception SAXException thrown if there is an error parsing the response.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableStartingWithPrefix( String text ) throws SAXException {
+ return getReceivedPage().getTableStartingWithPrefix( text );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as its summary attribute.
+ * Will recurse into any nested tables, as needed.
+ * Case is ignored.
+ * @exception SAXException thrown if there is an error parsing the response.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableWithSummary( String text ) throws SAXException {
+ return getReceivedPage().getTableWithSummary( text );
+ }
+
+
+ /**
+ * Returns the first table in the response which has the specified text as its ID attribute.
+ * Will recurse into any nested tables, as needed.
+ * Case is ignored.
+ * @exception SAXException thrown if there is an error parsing the response.
+ * @return the selected table, or null if none is found
+ **/
+ public WebTable getTableWithID( String text ) throws SAXException {
+ return getReceivedPage().getTableWithID( text );
+ }
+
+
+//---------------------------------------- JavaScript methods ----------------------------------------
+
+
+ /**
+ * get the scriptable object for this WebResponse
+ */
+ public Scriptable getScriptableObject() {
+ ScriptingHandler result=this.getScriptingHandler();
+ if (!(result instanceof Scriptable)) {
+ throw new RuntimeException("getScriptableObject failed for "+result.getClass().getName()+" - not a Scriptable");
+ }
+ return (Scriptable) result;
+ }
+
+
+ public void setScriptingHandler( ScriptingHandler scriptingHandler ) {
+ _scriptingHandler = scriptingHandler;
+ }
+
+
+ public ScriptingHandler getScriptingHandler() {
+ if (_scriptingHandler == null) _scriptingHandler = HttpUnitOptions.getScriptingEngine().createHandler( this );
+ return _scriptingHandler;
+ }
+
+
+ public ScriptingHandler createJavascriptScriptingHandler() {
+ return new Scriptable();
+ }
+
+
+ /**
+ * create a DOMScriptingHandler
+ * @return the DOM scripting handler (the window)
+ */
+ public ScriptingHandler createDomScriptingHandler() {
+ if (!isHTML()) {
+ return new DomWindow( this );
+ } else {
+ try {
+ HTMLPage page=this.getReceivedPage();
+ Node rootNode=page.getRootNode();
+ HTMLDocumentImpl document=(HTMLDocumentImpl) rootNode;
+ DomWindow result=document.getWindow();
+ result.setProxy(this);
+ return result;
+ } catch (SAXException e) {
+ return new DomWindow( this );
+ }
+ }
+ }
+
+
+ public static ScriptableDelegate newDelegate( String delegateClassName ) {
+ if (delegateClassName.equalsIgnoreCase( "Option" )) {
+ return FormControl.newSelectionOption();
+ } else {
+ throw new IllegalArgumentException( "No such scripting class supported: " + delegateClassName );
+ }
+ }
+
+
+ HTMLPage.Scriptable getDocumentScriptable() {
+ return getScriptableObject().getDocument();
+ }
+
+
+ /**
+ * open a a new Window with the given name and relative URL
+ * @param name - the name of the window
+ * @param relativeUrl - the relative URL to be used
+ * @return the WebResponse as a DomWindowProxy
+ */
+ public DomWindowProxy openNewWindow( String name, String relativeUrl ) throws IOException, SAXException {
+ if (relativeUrl == null || relativeUrl.trim().length() == 0) relativeUrl = "about:";
+ GetMethodWebRequest request = new GetMethodWebRequest( getURL(), relativeUrl, _frame, name );
+ WebResponse response=_window.getResponse( request );
+ return response;
+ }
+
+
+ public DomWindowProxy submitRequest( HTMLElementImpl sourceElement, String method, String location, String target, MessageBody requestBody ) throws IOException, SAXException {
+ if (method.equalsIgnoreCase( "get" )) {
+ return getWindow().sendRequest( new GetMethodWebRequest( this, sourceElement, getURL(), location, target ) );
+ } else {
+ return null;
+ }
+ }
+
+
+ public void close() {
+ if (getFrameName().equals( WebRequest.TOP_FRAME )) _window.close();
+ }
+
+
+ public void alert( String message ) {
+ _client.postAlert( message );
+ }
+
+
+ public boolean confirm( String message ) {
+ return _client.getConfirmationResponse( message );
+ }
+
+
+ public String prompt( String prompt, String defaultResponse ) {
+ return _client.getUserResponse( prompt, defaultResponse );
+ }
+
+
+ String getBaseTarget() {
+ return _baseTarget;
+ }
+
+
+ public class Scriptable extends ScriptableDelegate implements NamedDelegate {
+
+ public void alertUser( String message ) {
+ alert( message );
+ }
+
+
+ public boolean getConfirmationResponse( String message ) {
+ return confirm( message );
+ }
+
+
+ public String getUserResponse( String prompt, String defaultResponse ) {
+ return prompt( prompt, defaultResponse );
+ }
+
+
+ public ClientProperties getClientProperties() {
+ return _client == null ? ClientProperties.getDefaultProperties() : _client.getClientProperties();
+ }
+
+
+ public HTMLPage.Scriptable getDocument() {
+ try {
+ if (!isHTML()) replaceText( BLANK_HTML, HTML_CONTENT );
+ return getReceivedPage().getScriptableObject();
+ } catch (SAXException e) {
+ throw new RuntimeException( e.toString() );
+ }
+ }
+
+
+ public Scriptable[] getFrames() throws SAXException {
+ String[] names = getFrameNames();
+ Scriptable[] frames = new Scriptable[ names.length ];
+ for (int i = 0; i < frames.length; i++) {
+ frames[i] = getSubframeContents( names[i] ).getScriptableObject();
+ }
+ return frames;
+ }
+
+
+ public void load() throws SAXException {
+ if (isHTML()) {
+ getReceivedPage().getForms(); // TODO be more explicit here - don't care about forms, after all
+ doEventScript( getReceivedPage().getOnLoadEvent() );
+ }
+ }
+
+
+ public Scriptable open( String urlString, String name, String features, boolean replace )
+ throws IOException, SAXException {
+ WebResponse response = (WebResponse) openNewWindow( name, urlString );
+ return response == null ? null : response.getScriptableObject();
+ }
+
+
+ public void closeWindow() {
+ close();
+ }
+
+
+ /**
+ * Returns the value of the named property. Will return null if the property does not exist.
+ **/
+ public Object get( String propertyName ) {
+ if (propertyName.equals( "name" )) {
+ return getName();
+ } else if (propertyName.equalsIgnoreCase( "top" )) {
+ return _window.getFrameContents( WebRequest.TOP_FRAME ).getScriptableObject();
+ } else if (propertyName.equalsIgnoreCase( "parent" )) {
+ return _window.getParentFrameContents( _frame ).getScriptableObject();
+ } else if (propertyName.equalsIgnoreCase( "opener" )) {
+ return getFrameName().equals( WebRequest.TOP_FRAME ) ? getScriptable( _window.getOpener() ) : null;
+ } else if (propertyName.equalsIgnoreCase( "closed" )) {
+ return (getFrameName().equals( WebRequest.TOP_FRAME ) && _window.isClosed()) ? Boolean.TRUE : Boolean.FALSE;
+ } else {
+ try {
+ return getSubframeContents( propertyName ).getScriptableObject();
+ } catch (NoSuchFrameException e) {
+ return super.get( propertyName );
+ }
+ }
+ }
+
+
+ public String getName() {
+ String windowName = getFrameName().equals( WebRequest.TOP_FRAME ) ? _window.getName() : getFrameName();
+ return windowName.startsWith( WebWindow.NO_NAME ) ? "" : windowName;
+ }
+
+
+ private Scriptable getScriptable( WebResponse opener ) {
+ return opener == null ? null : opener.getScriptableObject();
+ }
+
+
+ /**
+ * Sets the value of the named property. Will throw a runtime exception if the property does not exist or
+ * cannot accept the specified value.
+ **/
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equals( "name" )) {
+ if (value == null) value = "";
+ if (getFrameName().equals( WebRequest.TOP_FRAME )) {
+ _window.setName( value.toString() );
+ }
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+
+
+ public void setLocation( String relativeURL ) throws IOException, SAXException {
+ getWindow().getResponse( new GetMethodWebRequest( _pageURL, relativeURL, _frame.getName() ) );
+ }
+
+
+ public URL getURL() {
+ return WebResponse.this._pageURL;
+ }
+ }
+
+
+//---------------------------------------- Object methods --------------------------------------------
+
+ abstract
+ public String toString();
+
+
+//----------------------------------------- protected members -----------------------------------------------
+
+
+ /**
+ * Constructs a response object.
+ * see [ 1159858 ] patch for RFE 1159844 (parsing intercepted pages)
+ * @param frame the frame to hold the response
+ * @param url the url from which the response was received
+ *
+ **/
+ protected WebResponse( WebClient client, FrameSelector frame, URL url ) {
+ _client = client;
+ _baseURL = _pageURL = url;
+ _baseTarget = frame.getName();
+ _frame = frame;
+ // intialize window for interception as described in
+ // https://sourceforge.net/tracker/index.php?func=detail&aid=1159844&group_id=6550&atid=356550
+ if (client!=null) {
+ _window = client.getMainWindow();
+ }
+ }
+
+
+ /**
+ * Constructs a response object.
+ * @param frame the frame to hold the response
+ * @param url the url from which the response was received
+ **/
+ protected WebResponse( WebClient client, FrameSelector frame, URL url, String text ) {
+ this( client, frame, url );
+ _responseText = text;
+ }
+
+
+ final
+ protected void defineRawInputStream( InputStream inputStream ) throws IOException {
+ if (_inputStream != null || _responseText != null) {
+ throw new IllegalStateException( "Must be called before response text is defined." );
+ }
+
+ // please note bug report [ 1119205 ] EOFExceptions while using a Proxy
+ // and patch proposal below
+ // by Ralf Bust
+ /* original 1.6.2 code
+ if (encodedUsingGZIP()) {
+ byte[] compressedData = readFromStream( inputStream, getContentLength() );
+ _inputStream = new GZIPInputStream( new ByteArrayInputStream( compressedData ) );
+ } else {
+ _inputStream = inputStream;
+ }*/
+
+ if (encodedUsingGZIP()) {
+ try {
+ _inputStream = new GZIPInputStream( inputStream );
+ } catch (EOFException eof) {
+ _inputStream = inputStream;
+ }
+ } else {
+ _inputStream = inputStream;
+ }
+ }
+
+
+ private boolean encodedUsingGZIP() {
+ String encoding = getHeaderField( "Content-Encoding" );
+ return encoding != null && encoding.indexOf( "gzip" ) >= 0;
+ }
+
+
+ /**
+ * Overwrites the current value (if any) of the content type header.
+ **/
+ protected void setContentTypeHeader( String value ) {
+ _contentHeader = value;
+ }
+
+
+//------------------------------------------ package members ------------------------------------------------
+
+ final static String BLANK_HTML = "";
+
+ static WebResponse createBlankResponse() {
+ return new DefaultWebResponse(BLANK_HTML);
+ }
+
+ WebWindow getWindow() {
+ return _window;
+ }
+
+
+ void setWindow( WebWindow window ) {
+ _window = window;
+ }
+
+
+ public boolean replaceText( String text, String contentType ) {
+ if (_parsingPage) return false;
+ _responseText = text;
+ _inputStream = null;
+ _page = null;
+ _contentType = contentType;
+ _baseURL = null;
+ _baseTarget = _frame.getName();
+ _refreshHeader = null;
+
+ try {
+ readTags( text.getBytes() );
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException( "Failure while attempting to reparse text: " + e );
+ } catch (MalformedURLException e) {
+ throw new RuntimeException( "Failure while attempting to reparse text: " + e );
+ }
+ return true;
+ }
+
+
+ /**
+ * Returns the frames found in the page in the order in which they appear.
+ **/
+ WebRequest[] getFrameRequests() throws SAXException {
+ WebFrame[] frames = getFrames();
+ Vector requests = new Vector();
+ for (int i = 0; i < frames.length; i++) {
+ if (frames[i].hasInitialRequest()) {
+ requests.addElement( frames[i].getInitialRequest() );
+ }
+ }
+
+ WebRequest[] result = new WebRequest[ requests.size() ];
+ requests.copyInto( result );
+ return result;
+ }
+
+
+//--------------------------------- private members --------------------------------------
+
+
+ private WebWindow _window;
+
+ private HTMLPage _page;
+
+ private String _contentHeader;
+
+ private int _contentLength = UNINITIALIZED_INT;
+
+ private String _contentType;
+
+ private String _characterSet;
+
+ private WebRequest _refreshRequest;
+
+ private int _refreshDelay = -1; // initialized to invalid value
+
+ private String _responseText;
+
+ private InputStream _inputStream;
+
+ private final URL _pageURL;
+
+ private final WebClient _client;
+ /**
+ * getter for the WebClient
+ * @since 1.7
+ * @return the web client for this WebResponse (if any)
+ */
+ public WebClient getClient() {
+ return _client;
+ }
+
+ private ScriptingHandler _scriptingHandler;
+
+
+ protected void loadResponseText() throws IOException {
+ if (_responseText != null) throw new IllegalStateException( "May only invoke loadResponseText once" );
+ _responseText = "";
+
+ InputStream inputStream = getInputStream();
+ try {
+ final int contentLength = this.encodedUsingGZIP() ? -1 : getContentLength();
+ int bytesRemaining = contentLength < 0 ? Integer.MAX_VALUE : contentLength;
+ byte[] bytes = readFromStream( inputStream, bytesRemaining );
+
+ readTags( bytes );
+ _responseText = new String( bytes, getCharacterSet() );
+ _inputStream = new ByteArrayInputStream( bytes );
+
+ if (HttpUnitOptions.isCheckContentLength() && contentLength >= 0 && bytes.length != contentLength) {
+ throw new IOException("Truncated message. Expected length: " + contentLength +
+ ", Actual length: " + bytes.length);
+ }
+ } finally {
+ inputStream.close();
+ }
+ }
+
+
+ private byte[] readFromStream( InputStream inputStream, int maxBytes ) throws IOException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ if (maxBytes > 0) {
+ do {
+ outputStream.write( buffer, 0, count );
+ maxBytes -= count;
+ if (maxBytes <= 0) break;
+ count = inputStream.read( buffer, 0, Math.min( maxBytes, buffer.length ) );
+ } while (count != -1);
+ } else {
+ do {
+ outputStream.write( buffer, 0, count );
+ int available = getAvailableBytes( inputStream );
+ count = (available == 0) ? -1 : inputStream.read( buffer, 0, buffer.length );
+ } while (count != -1);
+ }
+
+ return outputStream.toByteArray();
+ }
+
+
+ private int getAvailableBytes( InputStream inputStream ) throws IOException {
+ int timeLeft = UNKNOWN_LENGTH_TIMEOUT;
+ int available;
+ do {
+ timeLeft -= UNKNOWN_LENGTH_RETRY_INTERVAL;
+ try { Thread.sleep( UNKNOWN_LENGTH_RETRY_INTERVAL ); } catch (InterruptedException e) { /* do nothing */ }
+ available = inputStream.available();
+ } while (available == 0 && timeLeft > 0);
+ return available;
+ }
+
+
+ private void readTags( byte[] rawMessage ) throws UnsupportedEncodingException, MalformedURLException {
+ ByteTagParser parser = new ByteTagParser( rawMessage );
+ ByteTag tag = parser.getNextTag();
+ while (tag != null ) {
+ if (tag.getName().equalsIgnoreCase( "meta" )) processMetaTag( tag );
+ if (tag.getName().equalsIgnoreCase( "base" )) processBaseTag( tag );
+ if (tag.getName().equalsIgnoreCase( "noscript") && HttpUnitOptions.isScriptingEnabled()) {
+ do {
+ tag = parser.getNextTag();
+ }
+ while (tag.getName().equalsIgnoreCase( "/noscript") );
+ }
+ tag = parser.getNextTag();
+ }
+ }
+
+
+ private void processBaseTag( ByteTag tag ) throws MalformedURLException {
+ if (tag.getAttribute( "href" ) != null) _baseURL = new URL( getURL(), tag.getAttribute( "href" ) );
+ if (tag.getAttribute( "target" ) != null) _baseTarget = tag.getAttribute( "target" );
+ }
+
+
+ /**
+ * process MetaTags based on the tag
+ * @param tag
+ */
+ private void processMetaTag( ByteTag tag ) {
+ if (isHttpEquivMetaTag( tag, "content-type" )) {
+ inferContentType( tag.getAttribute( "content" ) );
+ } else if (isHttpEquivMetaTag( tag, "refresh" )) {
+ inferRefreshHeader( tag.getAttribute( "content" ) );
+ }
+ }
+
+
+ /**
+ * check whether the given tag is a http equiv meta tag
+ * @param tag
+ * @param headerName
+ * @return
+ */
+ private boolean isHttpEquivMetaTag( ByteTag tag, String headerName )
+ {
+ String equiv1=tag.getAttribute( "http_equiv" );
+ String equiv2=tag.getAttribute( "http-equiv" );
+ boolean result=
+ headerName.equalsIgnoreCase( equiv1 ) ||
+ headerName.equalsIgnoreCase( equiv2 );
+ return result;
+ }
+
+
+ /**
+ * infer the refresh Header
+ * @param refreshHeader
+ */
+ private void inferRefreshHeader( String refreshHeader ) {
+ String originalHeader = getHeaderField( "Refresh" );
+ // System.err.println("original='"+originalHeader+"'\nrefreshHeader='"+refreshHeader+"'");
+ if (originalHeader == null) {
+ _refreshHeader = refreshHeader;
+ }
+ }
+
+
+ /**
+ * read the Refresh Request
+ *
+ */
+ private void readRefreshRequest() {
+ if (_refreshDelay >= 0)
+ return;
+ _refreshDelay = 0;
+ String refreshHeader = _refreshHeader != null ? _refreshHeader : getHeaderField( "Refresh" );
+ if (refreshHeader == null) return;
+
+ int semicolonIndex = refreshHeader.indexOf( ';' );
+ if (semicolonIndex < 0) {
+ interpretRefreshHeaderElement( refreshHeader, refreshHeader );
+ } else {
+ interpretRefreshHeaderElement( refreshHeader.substring( 0, semicolonIndex ), refreshHeader );
+ interpretRefreshHeaderElement( refreshHeader.substring( semicolonIndex+1 ), refreshHeader );
+ }
+ if (_refreshRequest == null) _refreshRequest = new GetMethodWebRequest( _pageURL, _pageURL.toString(), _frame.getName() );
+ }
+
+
+ private void interpretRefreshHeaderElement( String token, String refreshHeader ) {
+ if (token.length() == 0) return;
+ try {
+ if (Character.isDigit( token.charAt(0) )) {
+ _refreshDelay = Integer.parseInt( token );
+ } else {
+ _refreshRequest = new GetMethodWebRequest( _pageURL, getRefreshURL( token ), _frame.getName() );
+ }
+ } catch (NumberFormatException e) {
+ System.out.println( "Unable to interpret refresh tag: \"" + refreshHeader + '"' );
+ }
+ }
+
+
+ private String getRefreshURL( String text ) {
+ text = text.trim();
+ if (!text.toUpperCase().startsWith( "URL" )) {
+ return HttpUnitUtils.stripQuotes( text );
+ } else {
+ int splitIndex = text.indexOf( '=' );
+ String value = text.substring( splitIndex+1 ).trim();
+ return HttpUnitUtils.replaceEntities( HttpUnitUtils.stripQuotes( value ) );
+ }
+ }
+
+
+ private void inferContentType( String contentTypeHeader ) {
+ String originalHeader = getHeaderField( "Content-type" );
+ if (originalHeader == null || originalHeader.indexOf( "charset" ) < 0) {
+ setContentTypeHeader( contentTypeHeader );
+ }
+ }
+
+
+ CookieJar getCookieJar() {
+ if (_cookies == null) _cookies = new CookieJar( this );
+ return _cookies;
+ }
+
+
+ private CookieJar _cookies;
+
+ private void readContentTypeHeader() {
+ String contentHeader = (_contentHeader != null) ? _contentHeader
+ : getHeaderField( "Content-type" );
+ if (contentHeader == null) {
+ _contentType = HttpUnitOptions.getDefaultContentType();
+ setCharacterSet( HttpUnitOptions.getDefaultCharacterSet() );
+ _contentHeader = _contentType + ";charset=" + _characterSet;
+ } else {
+ String[] parts = HttpUnitUtils.parseContentTypeHeader( contentHeader );
+ if (null != _client && null != _client.getClientProperties().getOverrideContextType()) {
+ _contentType = _client.getClientProperties().getOverrideContextType();
+ } else {
+ _contentType = parts[0];
+ }
+ if (parts[1] != null) setCharacterSet( parts[1] );
+ }
+ }
+
+
+ private WebFrame[] getFrames() throws SAXException {
+ return getReceivedPage().getFrames();
+
+ }
+
+
+ /**
+ * get the received Page
+ * @return the received page
+ * @throws SAXException
+ */
+ HTMLPage getReceivedPage() throws SAXException {
+ if (_page == null) {
+ try {
+ _parsingPage = true;
+ if (!isHTML()) throw new NotHTMLException( getContentType() );
+ _page = new HTMLPage( this, _frame, _baseURL, _baseTarget, getCharacterSet() );
+ _page.parse( getText(), _pageURL );
+ if (_page == null) throw new IllegalStateException( "replaceText called in the middle of getReceivedPage()" );
+
+ ((HTMLDocumentImpl) _page.getRootNode()).getWindow().setProxy( this );
+ } catch (IOException e) {
+ HttpUnitUtils.handleException(e);
+ throw new RuntimeException( e.toString() );
+ } finally {
+ _parsingPage = false;
+ }
+ }
+ return _page;
+ }
+
+
+ private static String _defaultEncoding;
+
+ private final static String[] DEFAULT_ENCODING_CANDIDATES = { HttpUnitUtils.DEFAULT_CHARACTER_SET, "us-ascii", "utf-8", "utf8" };
+
+ static String getDefaultEncoding() {
+ if (_defaultEncoding == null) {
+ for (int i = 0; i < DEFAULT_ENCODING_CANDIDATES.length; i++) {
+ if (isSupportedCharacterSet( DEFAULT_ENCODING_CANDIDATES[i] )) {
+ return _defaultEncoding = DEFAULT_ENCODING_CANDIDATES[i];
+ }
+ }
+ }
+ return (_defaultEncoding = System.getProperty( "file.encoding" ));
+ }
+
+
+ private void setCharacterSet( String characterSet ) {
+ if (characterSet == null) return;
+
+ _characterSet = isSupportedCharacterSet( characterSet ) ? characterSet : getDefaultEncoding();
+ }
+
+
+ private static boolean isSupportedCharacterSet( String characterSet ) {
+ try {
+ return "abcd".getBytes( characterSet ).length > 0;
+ } catch (UnsupportedEncodingException e) {
+ return false;
+ }
+ }
+
+
+ void setCookie( String name, String value ) {
+ _client.putCookie( name, value );
+ }
+
+
+ String getCookieHeader() {
+ return _client.getCookieJar().getCookieHeaderField( getURL() );
+ }
+
+
+ String getReferer() {
+ return null;
+ }
+
+
+
+//=======================================================================================
+
+ static class ByteTag {
+
+ ByteTag( byte[] buffer, int start, int length ) throws UnsupportedEncodingException {
+ _buffer = new String( buffer, start, length, WebResponse.getDefaultEncoding() ).toCharArray();
+ _name = nextToken();
+
+ String attribute = "";
+ String token = nextToken();
+ while (token.length() != 0) {
+ if (token.equals( "=" ) && attribute.length() != 0) {
+ getAttributes().put( attribute.toLowerCase(), nextToken() );
+ attribute = "";
+ } else {
+ if (attribute.length() > 0) getAttributes().put( attribute.toLowerCase(), "" );
+ attribute = token;
+ }
+ token = nextToken();
+ }
+ }
+
+
+ public String getName() {
+ return _name;
+ }
+
+ public String getAttribute( String attributeName ) {
+ return (String) getAttributes().get( attributeName );
+ }
+
+ public String toString() {
+ return "ByteTag[ name=" + _name + ";attributes = " + _attributes + ']';
+ }
+
+
+ private Hashtable getAttributes() {
+ if (_attributes == null) _attributes = new Hashtable();
+ return _attributes;
+ }
+
+
+ private String _name = "";
+ private Hashtable _attributes;
+
+
+ private char[] _buffer;
+ private int _end = -1;
+
+
+ private String nextToken() {
+ int start = _end + 1;
+ while (start < _buffer.length && Character.isWhitespace( _buffer[ start ] )) start++;
+ if (start >= _buffer.length) {
+ return "";
+ } else if (_buffer[ start ] == '"') {
+ for (_end = start +1; _end < _buffer.length && _buffer[ _end ] != '"'; _end++);
+ return new String( _buffer, start +1, _end-start -1 );
+ } else if (_buffer[ start ] == '\'') {
+ for (_end = start +1; _end < _buffer.length && _buffer[ _end ] != '\''; _end++);
+ return new String( _buffer, start +1, _end-start -1 );
+ } else if (_buffer[ start ] == '=') {
+ _end = start;
+ return "=";
+ } else {
+ for (_end = start +1; _end < _buffer.length && _buffer[ _end ] != '=' && !Character.isWhitespace( _buffer[ _end ] ); _end++);
+ return new String( _buffer, start, (_end--)-start );
+ }
+ }
+ }
+
+
+//=======================================================================================
+
+
+ static class ByteTagParser {
+ ByteTagParser( byte[] buffer ) {
+ _buffer = buffer;
+ }
+
+
+ ByteTag getNextTag() throws UnsupportedEncodingException {
+ ByteTag byteTag=null;
+ do {
+ int _start = _end + 1;
+ while (_start < _buffer.length && _buffer[ _start ] != '<') _start++;
+ // proposed patch for bug report
+ // [ 1376739 ] iframe tag not recognized if Javascript code contains '<'
+ // by Nathan Jakubiak
+ // uncommented since it doesn't seem to fix the test in WebFrameTest.java
+ // if (_scriptDepth > 0 && _start+1 < _buffer.length &&
+ // _buffer[ _start+1 ] != '/') {
+ // _end = _start+1;
+ // continue;
+ //}
+ for (_end =_start +1; _end < _buffer.length && _buffer[ _end ] != '>'; _end++);
+ if (_end >= _buffer.length || _end < _start) return null;
+ byteTag = new ByteTag( _buffer, _start +1, _end-_start -1 );
+ if (byteTag.getName().equalsIgnoreCase("script")) {
+ _scriptDepth++;
+ return byteTag;
+ }
+ if (byteTag.getName().equalsIgnoreCase("/script")) _scriptDepth--;
+ } while (_scriptDepth > 0);
+ return byteTag;
+ }
+
+
+ private int _scriptDepth = 0;
+ private int _end = -1;
+
+ private byte[] _buffer;
+ }
+
+
+ /**
+ * allow access to the valid content Types
+ * @since 1.7
+ * @return the validContentTypes
+ */
+ public static String[] getValidContentTypes() {
+ return validContentTypes;
+ }
+
+
+ /**
+ * allow modification of the valid content Types
+ * use with care
+ * @since 1.7
+ * @param validContentTypes the validContentTypes to set
+ */
+ protected static void setValidContentTypes(String[] validContentTypes) {
+ WebResponse.validContentTypes = validContentTypes;
+ }
+
+
+}
+
+
+//=======================================================================================
+
+
+class DefaultWebResponse extends WebResponse {
+
+
+ DefaultWebResponse( String text ) {
+ this( null, null, text );
+ }
+
+
+ DefaultWebResponse( WebClient client, URL url, String text ) {
+ this( client, FrameSelector.TOP_FRAME, url, text );
+ }
+
+
+ DefaultWebResponse( WebClient client, FrameSelector frame, URL url, String text ) {
+ super( client, frame, url, text );
+ }
+
+
+ /**
+ * Returns the response code associated with this response.
+ **/
+ public int getResponseCode() {
+ return HttpURLConnection.HTTP_OK;
+ }
+
+
+ /**
+ * Returns the response message associated with this response.
+ **/
+ public String getResponseMessage() {
+ return "OK";
+ }
+
+
+ public String[] getHeaderFieldNames() {
+ return new String[] { "Content-type" };
+ }
+
+
+ /**
+ * Returns the value for the specified header field. If no such field is defined, will return null.
+ **/
+ public String getHeaderField( String fieldName ) {
+ if (fieldName.equalsIgnoreCase( "Content-type" )) {
+ return "text/html; charset=us-ascii";
+ } else {
+ return null;
+ }
+ }
+
+
+ public String[] getHeaderFields( String fieldName ) {
+ String value = getHeaderField( fieldName );
+ return value == null ? new String[0] : new String[]{ value };
+ }
+
+
+ public String toString() {
+ try {
+ return "DefaultWebResponse [" + getText() + "]";
+ } catch (IOException e) { // should never happen
+ return "DefaultWebResponse [???]";
+ }
+ }
+}
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebTable.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebTable.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebTable.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,383 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2000-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.html.HTMLTableCellElement;
+import org.w3c.dom.html.HTMLTableRowElement;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * This class represents a table in an HTML page.
+ *
+ * @author Russell Gold
+ * @author Benoit Xhenseval
+ **/
+public class WebTable extends HTMLElementBase {
+
+
+ /** Predicate to match the complete text of a table's first non-blank cell. **/
+ public final static HTMLElementPredicate MATCH_FIRST_NONBLANK_CELL;
+
+ /** Predicate to match a prefix of a table's first non-blank cell. **/
+ public final static HTMLElementPredicate MATCH_FIRST_NONBLANK_CELL_PREFIX;
+
+ /** Predicate to match a table's summary attribute. **/
+ public final static HTMLElementPredicate MATCH_SUMMARY;
+
+ /** Predicate to match a table's ID. **/
+ public final static HTMLElementPredicate MATCH_ID;
+
+
+ /**
+ * Returns the number of rows in the table.
+ **/
+ public int getRowCount() {
+ return getCells().length;
+ }
+
+
+ private TableCell[][] getCells() {
+ if (_cells == null) readTable();
+ return _cells;
+
+ }
+
+
+ /**
+ * Returns the number of columns in the table.
+ **/
+ public int getColumnCount() {
+ if (getCells().length == 0) return 0;
+ return getCells()[0].length;
+ }
+
+
+ /**
+ * Returns the contents of the specified table cell as text.
+ * The row and column numbers are zero-based.
+ * @throws IndexOutOfBoundsException if the specified cell numbers are not valid
+ **/
+ public String getCellAsText( int row, int column ) {
+ TableCell cell = getTableCell( row, column );
+ return (cell == null) ? "" : cell.getText();
+ }
+
+
+ /**
+ * Returns the contents of the specified table cell as text.
+ * The row and column numbers are zero-based.
+ * @throws IndexOutOfBoundsException if the specified cell numbers are not valid
+ **/
+ public TableCell getTableCell( int row, int column ) {
+ return getCells()[ row ][ column ];
+ }
+
+
+ /**
+ * Returns the contents of the specified table cell with a given ID
+ * @return TableCell with given ID or null if ID is not found.
+ **/
+ public TableCell getTableCellWithID( String id ) {
+ for (int i = 0; i < getRowCount(); i++) {
+ for (int j = 0; j < getColumnCount(); j++) {
+ final TableCell tableCell = getCells()[i][j];
+ if (tableCell!=null && tableCell.getID().equals( id )) return tableCell;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Removes all rows and all columns from this table which have no visible text in them.
+ * patch [ 1117822 ] Patch for purgeEmptyCells() problem
+ * by Glen Stampoultzis
+ **/
+ public void purgeEmptyCells() {
+ int numRowsWithText = 0;
+ int numColumnsWithText = 0;
+ boolean rowHasText[] = new boolean[ getRowCount() ];
+ boolean columnHasText[] = new boolean[ getColumnCount() ];
+ Hashtable spanningCells = new Hashtable();
+
+
+ // look for rows and columns with any text in a non-spanning cell
+ for (int row = 0; row < rowHasText.length; row++) {
+ for (int col = 0; col < columnHasText.length; col++) {
+ if (getCellAsText(row,col).trim().length() == 0) continue;
+ if (getTableCell(row,col).getColSpan() == 1 && getTableCell(row,col).getRowSpan() == 1) {
+ if (!rowHasText[row]) numRowsWithText++;
+ if (!columnHasText[col]) numColumnsWithText++;
+ rowHasText[row] = columnHasText[col] = true;
+ } else if (!spanningCells.containsKey( getTableCell(row,col) )) {
+ // gstamp: altered the original code to deal with two issues:
+ // Firstly only the coordinates of the first spanning cell
+ // are added to the Map. The old code was using the last
+ // set of coordinates.
+ // Secondly I mark the starting coordinates as containing
+ // text which keeps the next section of code from removing
+ // the starting row/column.
+ if (spanningCells.get( getTableCell(row,col) ) == null ) {
+ if (!rowHasText[row]) numRowsWithText++;
+ if (!columnHasText[col]) numColumnsWithText++;
+ rowHasText[row] = columnHasText[col] = true;
+ spanningCells.put( getTableCell(row,col), new int[] { row, col } );
+ } }
+ }
+ }
+
+ // look for requirements to keep spanning cells: special processing is needed if either:
+ // none of its rows already have text, or none of its columns already have text.
+ for (Enumeration e = spanningCells.keys(); e.hasMoreElements();) {
+ TableCell cell = (TableCell) e.nextElement();
+ int coords[] = (int[]) spanningCells.get( cell );
+ boolean neededInRow = true;
+ boolean neededInCol = true;
+ for (int i = coords[0]; neededInRow && (i < rowHasText.length) && (i < coords[0] + cell.getRowSpan()); i++) {
+ neededInRow = !rowHasText[i];
+ }
+ for (int j = coords[1]; neededInCol && (j < columnHasText.length) && (j < coords[1] + cell.getColSpan()); j++) {
+ neededInCol = !columnHasText[j];
+ }
+ if (neededInRow) {
+ rowHasText[ coords[0] ] = true;
+ numRowsWithText++;
+ }
+ if (neededInCol) {
+ columnHasText[ coords[1] ] = true;
+ numColumnsWithText++;
+ }
+ }
+
+ TableCell[][] remainingCells = new TableCell[ numRowsWithText ][ numColumnsWithText ];
+
+ int targetRow = 0;
+ for (int i = 0; i < rowHasText.length; i++) {
+ if (!rowHasText[i]) continue;
+ int targetColumn = 0;
+ for (int j = 0; j < columnHasText.length; j++) {
+ if (!columnHasText[j]) continue;
+ remainingCells[ targetRow ][ targetColumn++ ] = _cells[i][j];
+ }
+ targetRow++;
+ }
+
+ _cells = remainingCells;
+
+ }
+
+
+ /**
+ * Returns a rendering of this table with all cells converted to text.
+ **/
+ public String[][] asText() {
+ String[][] result = new String[ getRowCount() ][ getColumnCount() ];
+
+ for (int i = 0; i < result.length; i++) {
+ for (int j= 0; j < result[0].length; j++) {
+ result[i][j] = getCellAsText( i, j );
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the summary attribute associated with this table.
+ **/
+ public String getSummary() {
+ return NodeUtils.getNodeAttribute( _dom, "summary" );
+ }
+
+
+ public String toString() {
+ String eol = System.getProperty( "line.separator" );
+ StringBuffer sb = new StringBuffer( HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE).append("WebTable:" ).append( eol );
+ for (int i = 0; i < getCells().length; i++) {
+ sb.append( "[" ).append( i ).append( "]: " );
+ for (int j = 0; j < getCells()[i].length; j++) {
+ sb.append( " [" ).append( j ).append( "]=" );
+ if (getCells()[i][j] == null) {
+ sb.append( "null" );
+ } else {
+ sb.append( getCells()[i][j].getText() );
+ }
+ }
+ sb.append( eol );
+ }
+ return sb.toString();
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new HTMLElementScriptable( this );
+ }
+
+
+ public ScriptableDelegate getParentDelegate() {
+ return _response.getDocumentScriptable();
+ }
+
+
+//----------------------------------- private members -----------------------------------
+
+ private Element _dom;
+ private URL _url;
+ private FrameSelector _frameName;
+ private String _baseTarget;
+ private String _characterSet;
+ private WebResponse _response;
+
+
+ private TableCell[][] _cells;
+
+
+ WebTable( WebResponse response, FrameSelector frame, Node domTreeRoot, URL sourceURL, String baseTarget, String characterSet ) {
+ super( domTreeRoot );
+ _response = response;
+ _frameName = frame;
+ _dom = (Element) domTreeRoot;
+ _url = sourceURL;
+ _baseTarget = baseTarget;
+ _characterSet = characterSet;
+ }
+
+
+
+ private void readTable() {
+ TableRow[] rows = getRows();
+ int[] columnsRequired = new int[ rows.length ];
+
+ for (int i = 0; i < rows.length; i++) {
+ TableCell[] cells = rows[i].getCells();
+ for (int j = 0; j < cells.length; j++) {
+ int spannedRows = Math.min( columnsRequired.length-i, cells[j].getRowSpan() );
+ for (int k = 0; k < spannedRows; k++) {
+ columnsRequired[ i+k ]+= cells[j].getColSpan();
+ }
+ }
+ }
+ int numColumns = 0;
+ for (int i = 0; i < columnsRequired.length; i++) {
+ numColumns = Math.max( numColumns, columnsRequired[i] );
+ }
+
+ _cells = new TableCell[ columnsRequired.length ][ numColumns ];
+
+ for (int i = 0; i < rows.length; i++) {
+ TableCell[] cells = rows[i].getCells();
+ for (int j = 0; j < cells.length; j++) {
+ int spannedRows = Math.min( columnsRequired.length-i, cells[j].getRowSpan() );
+ for (int k = 0; k < spannedRows; k++) {
+ for (int l = 0; l < cells[j].getColSpan(); l++) {
+ placeCell( i+k, j+l, cells[j] );
+ }
+ }
+ }
+ }
+ }
+
+
+ private void placeCell( int row, int column, TableCell cell ) {
+ while (_cells[ row ][ column ] != null) column++;
+ _cells[ row ][ column ] = cell;
+ }
+
+
+ private ArrayList _rows = new ArrayList();
+
+
+ void addRow( TableRow tableRow ) {
+ _cells = null;
+ _rows.add( tableRow );
+ }
+
+
+ TableRow newTableRow( HTMLTableRowElement element ) {
+ return new TableRow( this, element );
+ }
+
+
+ /**
+ * Returns an array of rows for this table.
+ */
+ public TableRow[] getRows() {
+ return (TableRow[]) _rows.toArray( new TableRow[ _rows.size() ] );
+ }
+
+
+ TableCell newTableCell( HTMLTableCellElement element ) {
+ return new TableCell( _response, _frameName, element, _url, _baseTarget, _characterSet );
+ }
+
+
+ static {
+ MATCH_FIRST_NONBLANK_CELL = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ WebTable table = ((WebTable) htmlElement);
+ for (int row = 0; row < table.getRowCount(); row++) {
+ for (int col = 0; col < table.getColumnCount(); col++) {
+ if (HttpUnitUtils.matches( table.getCellAsText( row, col ).trim(), (String) criteria)) return true;
+ }
+ }
+ return false;
+ }
+ };
+
+
+ MATCH_FIRST_NONBLANK_CELL_PREFIX = new HTMLElementPredicate() { // XXX find a way to do this w/o purging the table cells
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ WebTable table = ((WebTable) htmlElement);
+ for (int row = 0; row < table.getRowCount(); row++) {
+ for (int col = 0; col < table.getColumnCount(); col++) {
+ if (HttpUnitUtils.hasPrefix( table.getCellAsText( row, col ).trim(), (String) criteria)) return true;
+ }
+ }
+ return false;
+ }
+ };
+
+
+ MATCH_ID = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ return HttpUnitUtils.matches( ((WebTable) htmlElement).getID(), (String) criteria );
+ };
+ };
+
+
+ MATCH_SUMMARY = new HTMLElementPredicate() {
+ public boolean matchesCriteria( Object htmlElement, Object criteria ) {
+ return HttpUnitUtils.matches( ((WebTable) htmlElement).getSummary(), (String) criteria );
+ };
+ };
+
+ }
+
+}
+
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindow.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindow.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindow.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,404 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.xml.sax.SAXException;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+/**
+ * A window managed by a {@link com.meterware.httpunit.WebClient WebClient}.
+ *
+ * @author Russell Gold
+ **/
+public class WebWindow {
+
+ /** The client which created this window. **/
+ private WebClient _client;
+
+ /** A map of frame names to current contents. **/
+ private FrameHolder _frameContents;
+
+ /** The name of the window, set via JavaScript. **/
+ private String _name = "";
+
+ /** The web response containing the reference that opened this window **/
+ private WebResponse _opener;
+
+ /** True if this window has been closed. **/
+ private boolean _closed;
+
+
+ static final String NO_NAME = "$$HttpUnit_Window$$_";
+
+ /**
+ * The urls that have been encountered as redirect locations in the course
+ * of a single client-initiated request
+ * @since patch [ 1155415 ] Handle redirect instructions which can lead to a loop
+ */
+ private final Set _redirects;
+
+ /** True if seen initial request
+ * @since patch [ 1155415 ] Handle redirect instructions which can lead to a loop
+ */
+ private boolean _isInitialRequest = true;
+
+ /**
+ * Cache the initial client request to ensure that the _redirects
+ * structure gets reset.
+ * @since patch [ 1155415 ] Handle redirect instructions which can lead to a loop
+ */
+ private WebRequest _initialRequest;
+
+
+ /**
+ * Returns the web client associated with this window.
+ */
+ public WebClient getClient() {
+ return _client;
+ }
+
+
+ /**
+ * Returns true if this window has been closed.
+ */
+ public boolean isClosed() {
+ return _closed;
+ }
+
+
+ /**
+ * Closes this window.
+ */
+ public void close() {
+ if (!_closed) _client.close( this );
+ _closed = true;
+ }
+
+
+ /**
+ * Returns the name of this window. Windows created through normal HTML or browser commands have empty names,
+ * but JavaScript can set the name. A name may be used as a target for a request.
+ */
+ public String getName() {
+ return _name;
+ }
+
+
+ /**
+ * Returns the web response that contained the script which opened this window.
+ */
+ public WebResponse getOpener() {
+ return _opener;
+ }
+
+
+ /**
+ * Submits a GET method request and returns a response.
+ * @exception SAXException thrown if there is an error parsing the retrieved page
+ **/
+ public WebResponse getResponse( String urlString ) throws IOException, SAXException {
+ return getResponse( new GetMethodWebRequest( urlString ) );
+ }
+
+
+ /**
+ * Submits a web request and returns a response. This is an alternate name for the getResponse method.
+ * @return the WebResponse or null
+ **/
+ public WebResponse sendRequest( WebRequest request ) throws IOException, SAXException {
+ return getResponse( request );
+ }
+
+
+ /**
+ * Submits a web request and returns a response, using all state developed so far as stored in
+ * cookies as requested by the server.
+ * see patch [ 1155415 ] Handle redirect instructions which can lead to a loop
+ * @exception SAXException thrown if there is an error parsing the retrieved page
+ * @return the WebResponse or null
+ **/
+ public WebResponse getResponse( WebRequest request ) throws IOException, SAXException {
+ // Need to have some sort of ExecuteAroundMethod to ensure that the
+ // redirects data structure gets cleared down upon exit - not
+ // straightforward, since this could be a recursive call
+ if (_isInitialRequest) {
+ _initialRequest = request;
+ _isInitialRequest = false;
+ }
+
+ WebResponse result = null;
+
+ try {
+ final RequestContext requestContext = new RequestContext();
+ final WebResponse response = getSubframeResponse( request, requestContext );
+ requestContext.runScripts();
+ result = response == null ? null : response.getWindow().getFrameContents( response.getFrame() ); // javascript might replace the response in its frame
+ } finally {
+ if (null != request && request.equals(_initialRequest)) {
+ _redirects.clear();
+ _initialRequest = null;
+ _isInitialRequest = true;
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * get a Response from a SubFrame
+ * @param request
+ * @param requestContext
+ * @return the WebResponse or null
+ * @throws IOException
+ * @throws SAXException
+ */
+ WebResponse getSubframeResponse( WebRequest request, RequestContext requestContext ) throws IOException, SAXException {
+ WebResponse response = getResource( request );
+
+ return response == null ? null : updateWindow( request.getTarget(), response, requestContext );
+ }
+
+
+ /**
+ * Updates this web client based on a received response. This includes updating
+ * cookies and frames.
+ **/
+ WebResponse updateWindow( String requestTarget, WebResponse response, RequestContext requestContext ) throws IOException, SAXException {
+ _client.updateClient( response );
+ if (getClient().getClientProperties().isAutoRefresh() && response.getRefreshRequest() != null) {
+ WebRequest request=response.getRefreshRequest();
+ WebResponse result=getResponse( request );
+ return result;
+ } else if (shouldFollowRedirect( response )) {
+ delay( HttpUnitOptions.getRedirectDelay() );
+ return getResponse( new RedirectWebRequest( response ) );
+ } else {
+ _client.updateFrameContents( this, requestTarget, response, requestContext );
+ return response;
+ }
+ }
+
+
+ /**
+ * Returns the resource specified by the request. Does not update the window or load included framesets.
+ * May return null if the resource is a JavaScript URL which would normally leave the client unchanged.
+ */
+ public WebResponse getResource( WebRequest request ) throws IOException {
+ _client.tellListeners( request );
+
+ WebResponse response = null;
+ String urlString = request.getURLString().trim();
+ FrameSelector targetFrame = _frameContents.getTargetFrame( request );
+ if (urlString.startsWith( "about:" )) {
+ response = new DefaultWebResponse( _client, targetFrame, null, "" );
+ } else if (!HttpUnitUtils.isJavaScriptURL( urlString )) {
+ response = _client.createResponse( request, targetFrame );
+ } else {
+ ScriptingHandler handler = request.getSourceScriptingHandler();
+ if (handler == null) handler = getCurrentPage().getScriptingHandler();
+ Object result = handler.evaluateExpression( urlString );
+ if (result != null) {
+ response = new DefaultWebResponse( _client, targetFrame, request.getURL(), result.toString() );
+ }
+ }
+
+ if (response != null) _client.tellListeners( response );
+ return response;
+ }
+
+
+ /**
+ * Returns the name of the currently active frames.
+ **/
+ public String[] getFrameNames() {
+ final List names = _frameContents.getActiveFrameNames();
+ return (String[]) names.toArray( new String[ names.size() ] );
+ }
+
+
+ /**
+ * Returns true if the specified frame name is defined in this window.
+ */
+ public boolean hasFrame( String frameName ) {
+ return _frameContents.get( frameName ) != null;
+ }
+
+
+ boolean hasFrame( FrameSelector frame ) {
+ return _frameContents.get( frame ) != null;
+ }
+
+
+ /**
+ * Returns the response associated with the specified frame name.
+ * Throws a runtime exception if no matching frame is defined.
+ **/
+ public WebResponse getFrameContents( String frameName ) {
+ WebResponse response = _frameContents.get( frameName );
+ if (response == null) throw new NoSuchFrameException( frameName );
+ return response;
+ }
+
+
+ /**
+ * Returns the response associated with the specified frame target.
+ * Throws a runtime exception if no matching frame is defined.
+ **/
+ WebResponse getFrameContents( FrameSelector targetFrame ) {
+ return _frameContents.getFrameContents( targetFrame );
+ }
+
+
+ WebResponse getSubframeContents( FrameSelector frame, String subFrameName ) {
+ return _frameContents.getSubframeContents( frame, subFrameName );
+ }
+
+
+ WebResponse getParentFrameContents( FrameSelector frame ) {
+ return _frameContents.getParentFrameContents( frame );
+ }
+
+
+ /**
+ * Returns the response representing the main page in this window.
+ */
+ public WebResponse getCurrentPage() {
+ return getFrameContents( WebRequest.TOP_FRAME );
+ }
+
+
+ /**
+ * construct a WebWindow from a given client
+ * @param client - the client to construct me from
+ */
+ WebWindow( WebClient client ) {
+ _client = client;
+ _frameContents = new FrameHolder( this );
+ _name = NO_NAME + _client.getOpenWindows().length;
+ _redirects = new HashSet();
+ }
+
+
+ WebWindow( WebClient client, WebResponse opener ) {
+ this( client );
+ _opener = opener;
+ }
+
+
+ void updateFrameContents( WebResponse response, RequestContext requestContext ) throws IOException, SAXException {
+ response.setWindow( this );
+ _frameContents.updateFrames( response, response.getFrame(), requestContext );
+ }
+
+
+ void setName( String name ) {
+ _name = name;
+ }
+
+
+ /**
+ * Delays the specified amount of time.
+ **/
+ private void delay( int numMilliseconds ) {
+ if (numMilliseconds == 0) return;
+ try {
+ Thread.sleep( numMilliseconds );
+ } catch (InterruptedException e) {
+ // ignore the exception
+ }
+ }
+
+ /**
+ * check whether redirect is configured
+ * @param response
+ * @return
+ */
+ private boolean redirectConfigured( WebResponse response ) {
+ boolean isAutoredirect=getClient().getClientProperties().isAutoRedirect();
+ boolean hasLocation=response.getHeaderField( "Location" ) != null;
+ int responseCode=response.getResponseCode();
+ boolean result=isAutoredirect
+ && responseCode >= HttpURLConnection.HTTP_MOVED_PERM
+ && responseCode <= HttpURLConnection.HTTP_MOVED_TEMP
+ && hasLocation;
+ return result;
+ }
+
+ /**
+ * check wether we should follow the redirect given in the response
+ * make sure we don't run into a recursion
+ * @param response
+ * @return
+ */
+ private boolean shouldFollowRedirect( WebResponse response ) {
+ // first check whether redirect is configured for this response
+ // this is the old pre [ 1155415 ] Handle redirect instructions which can lead to a loop
+ // shouldFollowRedirect method - just renamed
+ if (!redirectConfigured(response))
+ return false;
+ // now do the recursion check
+ String redirectLocation = response.getHeaderField("Location");
+
+ URL url = null;
+
+ try {
+ if (redirectLocation != null) {
+ url = new URL(response.getURL(), redirectLocation);
+ }
+ } catch (MalformedURLException e) {
+ // Fall through and allow existing exception handling code deal
+ // with any exception - we don't know at this stage whether it is
+ // a redirect instruction, although it is highly likely, given
+ // there is a location header present in the response!
+ }
+
+ switch (response.getResponseCode()) {
+ case HttpURLConnection.HTTP_MOVED_PERM:
+ case HttpURLConnection.HTTP_MOVED_TEMP: // Fall through
+ if (null != url && _redirects.contains(url)) {
+ // We have already been instructed to redirect to that location in
+ // the course of this attempt to resolve the resource
+ throw new RecursiveRedirectionException(url,
+ "Unable to process request due to redirection loop");
+ }
+ _redirects.add(url);
+ break;
+ }
+ return redirectLocation != null;
+ }
+
+ FrameSelector getTopFrame() {
+ return _frameContents.getTopFrame();
+ }
+
+
+ FrameSelector getFrame( String target ) {
+ return _frameContents.getFrame( target );
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindowListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindowListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebWindowListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,40 @@
+package com.meterware.httpunit;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * A listener for web window openings and closings.
+ *
+ * @author Russell Gold
+ **/
+public interface WebWindowListener {
+
+ /**
+ * Invoked when the web client opens a new window.
+ */
+ public void windowOpened( WebClient client, WebWindow window );
+
+
+ /**
+ * Invoked when the web client closes a window.
+ */
+ public void windowClosed( WebClient client, WebWindow window );
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/controls/IllegalParameterValueException.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/controls/IllegalParameterValueException.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/controls/IllegalParameterValueException.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,90 @@
+package com.meterware.httpunit.controls;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import java.util.List;
+
+import com.meterware.httpunit.HttpUnitUtils;
+import com.meterware.httpunit.IllegalRequestParameterException;
+
+//============================= exception class IllegalParameterValueException ======================================
+
+
+/**
+ * This exception is thrown on an attempt to set a parameter to a value not permitted to it by the form.
+ **/
+public class IllegalParameterValueException extends IllegalRequestParameterException {
+
+
+ /**
+ * construct an IllegalParameterValueException
+ * @param parameterName - the name of the parameter
+ * @param badValue - the bad value that is not allowed
+ * @param allowed - the list of allowed values
+ */
+ public IllegalParameterValueException( String parameterName, String badValue, String[] allowed ) {
+ _parameterName = parameterName;
+ _badValue = badValue;
+ _allowedValues = allowed;
+ }
+
+ /**
+ * get the bad value from a list of Values
+ * @param values
+ * @return
+ */
+ protected static String getBadValue(List values) {
+ String result="unknown bad value";
+ if (values.size()>0) {
+ Object badValue=values.get(0);
+ result=badValue.toString();
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param parameterName
+ * @param values
+ * @param allowed
+ */
+ public IllegalParameterValueException( String parameterName, List values, String[] allowed ) {
+ this(parameterName,getBadValue(values),allowed);
+ }
+
+
+ public String getMessage() {
+ StringBuffer sb = new StringBuffer(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
+ sb.append( "May not set parameter '" ).append( _parameterName ).append( "' to '" );
+ sb.append( _badValue ).append( "'. Value must be one of: { " );
+ for (int i = 0; i < _allowedValues.length; i++) {
+ if (i != 0) sb.append( ", " );
+ sb.append( "'"+ _allowedValues[i] +"'" );
+ }
+ sb.append( " }" );
+ return sb.toString();
+ }
+
+
+ private String _parameterName;
+ private String _badValue;
+ private String[] _allowedValues;
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/controls/SelectionFormControl.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/controls/SelectionFormControl.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/controls/SelectionFormControl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,552 @@
+package com.meterware.httpunit.controls;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2008, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.meterware.httpunit.FormControl;
+import com.meterware.httpunit.NodeUtils;
+import com.meterware.httpunit.WebForm;
+import com.meterware.httpunit.dom.HTMLSelectElementImpl;
+import com.meterware.httpunit.protocol.ParameterProcessor;
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.SelectionOption;
+import com.meterware.httpunit.scripting.SelectionOptions;
+
+/**
+ * FormControl for "Select"
+ * moved here by wf for testability and visibility
+ * see bugreport [ 1124057 ] Out of Bounds Exception should be avoided
+ *
+ */
+public class SelectionFormControl extends FormControl {
+
+ private final boolean _multiSelect;
+ private final boolean _listBox;
+
+ private Options _selectionOptions;
+
+
+ public String getType() {
+ return (isMultiValued()?MULTIPLE_TYPE:SINGLE_TYPE);
+ }
+
+ public SelectionFormControl( WebForm form, HTMLSelectElementImpl element ) {
+ super( form, element );
+ if (!element.getNodeName().equalsIgnoreCase( "select" )) throw new RuntimeException( "Not a select element" );
+
+ int size = NodeUtils.getAttributeValue( element, "size", 0);
+ _multiSelect = NodeUtils.isNodeAttributePresent( element, "multiple" );
+ _listBox = size > 1 || (_multiSelect && size != 1);
+
+ _selectionOptions = _listBox ? (Options) new MultiSelectOptions( element ) : (Options) new SingleSelectOptions( element );
+ }
+
+
+ public String[] getValues() {
+ return _selectionOptions.getSelectedValues();
+ }
+
+
+ public String[] getOptionValues() {
+ return _selectionOptions.getValues();
+ }
+
+
+ public String[] getDisplayedOptions() {
+ return _selectionOptions.getDisplayedText();
+ }
+
+
+ /**
+ * Returns true if a single control can have multiple values.
+ **/
+ public boolean isMultiValued() {
+ return _multiSelect;
+ }
+
+
+ class Scriptable extends FormControl.Scriptable {
+
+ /**
+ * get the Object with the given property name
+ * @param propertyName - the name of the property to get
+ * @return the Object for the property
+ */
+ public Object get( String propertyName ) {
+ if (propertyName.equalsIgnoreCase( "options" )) {
+ return _selectionOptions;
+ } else if (propertyName.equalsIgnoreCase( "length" )) {
+ return new Integer( getOptionValues().length );
+ } else if (propertyName.equalsIgnoreCase( "value" )) {
+ return getSelectedValue();
+ } else if (propertyName.equalsIgnoreCase( "selectedIndex" )) {
+ return new Integer( _selectionOptions.getFirstSelectedIndex() );
+ } else {
+ return super.get( propertyName );
+ }
+ }
+
+
+ /**
+ * get the Object at the given index
+ * @param index - the index of the object to get
+ * @return the object at the given index
+ */
+ public Object get(int index) {
+ return _selectionOptions.get( index );
+ }
+
+
+ private String getSelectedValue() {
+ String[] values = getValues();
+ return (values.length == 0 ? "" : values[0] );
+ }
+
+
+ /**
+ * set the property with the given name to the given value
+ * @param propertyName - the name of the property to set
+ * @param value - the value to assign to the property
+ */
+ public void set( String propertyName, Object value ) {
+ if (propertyName.equalsIgnoreCase( "value" )) {
+ ArrayList values = new ArrayList();
+ values.add( value );
+ _selectionOptions.claimUniqueValues( values );
+ } else if (propertyName.equalsIgnoreCase( "selectedIndex" )) {
+ if (!(value instanceof Number)) throw new RuntimeException( "selectedIndex must be set to an integer" );
+ _selectionOptions.setSelectedIndex( ((Number) value).intValue() );
+ } else if (propertyName.equalsIgnoreCase( "length" )) {
+ _selectionOptions.setLength( ((Number) value).intValue() );
+ } else {
+ super.set( propertyName, value );
+ }
+ }
+ }
+
+
+ public ScriptableDelegate newScriptable() {
+ return new Scriptable();
+ }
+
+
+ void updateRequiredParameters( Hashtable required ) {
+ if (isReadOnly()) required.put( getName(), getValues() );
+ }
+
+
+ protected void addValues( ParameterProcessor processor, String characterSet ) throws IOException {
+ if (isDisabled()) return;
+ for (int i = 0; i < getValues().length; i++) {
+ processor.addParameter( getName(), getValues()[i], characterSet );
+ }
+ }
+
+
+ protected void claimUniqueValue( List values ) {
+ boolean changed = _selectionOptions.claimUniqueValues( values );
+ if (changed) sendOnChangeEvent();
+ }
+
+
+ protected void reset() {
+ _selectionOptions.reset();
+ }
+
+
+ public static class Option extends ScriptableDelegate implements SelectionOption {
+
+ private String _text ="";
+ private String _value;
+ private boolean _defaultSelected;
+ private boolean _selected;
+ private int _index;
+ private Options _container;
+
+
+ public Option() {
+ }
+
+
+ Option( String text, String value, boolean selected ) {
+ _text = text;
+ _value = value;
+ _defaultSelected = _selected = selected;
+ }
+
+
+ void reset() {
+ _selected = _defaultSelected;
+ }
+
+
+ void addValueIfSelected( List list ) {
+ if (_selected) list.add( _value );
+ }
+
+
+ void setIndex( Options container, int index ) {
+ _container = container;
+ _index = index;
+ }
+
+
+ //------------------------- SelectionOption methods ------------------------------
+
+
+ public void initialize( String text, String value, boolean defaultSelected, boolean selected ) {
+ _text = text;
+ _value = value;
+ _defaultSelected = defaultSelected;
+ _selected = selected;
+ }
+
+
+ public int getIndex() {
+ return _index;
+ }
+
+
+ public String getText() {
+ return _text;
+ }
+
+
+ public void setText( String text ) {
+ _text = text;
+ }
+
+
+ public String getValue() {
+ return _value;
+ }
+
+
+ public void setValue( String value ) {
+ _value = value;
+ }
+
+
+ public boolean isDefaultSelected() {
+ return _defaultSelected;
+ }
+
+
+ public void setSelected( boolean selected ) {
+ _selected = selected;
+ if (selected) _container.optionSet( _index );
+ }
+
+
+ public boolean isSelected() {
+ return _selected;
+ }
+ }
+
+
+ public abstract class Options extends ScriptableDelegate implements SelectionOptions {
+
+ private Option[] _options;
+
+ Options( Node selectionNode ) {
+ // BR [ 1843978 ] Accessing Options in a form is in lower case
+ // calls for uppercase "option" here ... pending as of 2007-12-30
+ NodeList nl = ((Element) selectionNode).getElementsByTagName( "OPTION" );
+
+ _options = new Option[ nl.getLength() ];
+ for (int i = 0; i < _options.length; i++) {
+ final String displayedText = getValue( nl.item(i).getFirstChild() ).trim();
+ _options[i] = new Option( displayedText,
+ getOptionValue( nl.item(i), displayedText ),
+ nl.item(i).getAttributes().getNamedItem( "selected" ) != null );
+ _options[i].setIndex( this, i );
+ }
+ }
+
+
+ /**
+ * claim unique values from the given list of values
+ * @param values - the list of values
+ * @return
+ */
+ boolean claimUniqueValues( List values ) {
+ return claimUniqueValues( values, _options );
+ }
+
+
+ protected abstract boolean claimUniqueValues( List values, Option[] options );
+
+
+ /**
+ * report if there are no matches
+ * be aware of [ 1100437 ] Patch for ClassCastException in FormControl
+ * TODO implement patch if test get's available
+ * @param values
+ */
+ final protected void reportNoMatches( List values ) {
+ if (!_listBox) {
+ throw new IllegalParameterValueException( getName(), values, getOptionValues() );
+ }
+ }
+
+
+ String[] getSelectedValues() {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < _options.length; i++) {
+ _options[i].addValueIfSelected( list );
+ }
+ if (!_listBox && list.isEmpty() && _options.length > 0) list.add( _options[0].getValue() );
+ return (String[]) list.toArray( new String[ list.size() ] );
+ }
+
+
+ void reset() {
+ for (int i = 0; i < _options.length; i++) {
+ _options[i].reset();
+ }
+ }
+
+
+ String[] getDisplayedText() {
+ String[] displayedText = new String[ _options.length ];
+ for (int i = 0; i < displayedText.length; i++) displayedText[i] = _options[i].getText();
+ return displayedText;
+ }
+
+
+ String[] getValues() {
+ String[] values = new String[ _options.length ];
+ for (int i = 0; i < values.length; i++) values[i] = _options[i].getValue();
+ return values;
+ }
+
+
+ /**
+ * Selects the matching item and deselects the others.
+ **/
+ void setSelectedIndex( int index ) {
+ for (int i = 0; i < _options.length; i++) {
+ _options[ i ]._selected = (i == index);
+ }
+ }
+
+
+ /**
+ * Returns the index of the first item selected, or -1 if none is selected.
+ */
+ int getFirstSelectedIndex() {
+ for (int i = 0; i < _options.length; i++) {
+ if (_options[i].isSelected()) return i;
+ }
+ return noOptionSelectedIndex();
+ }
+
+
+ protected abstract int noOptionSelectedIndex();
+
+
+ public int getLength() {
+ return _options.length;
+ }
+
+
+ /**
+ * Modified by gklopp - 12/19/2005
+ * [ 1396835 ] Javascript : length of a select element cannot be increased
+ * Bug corrected : The length can be greater than the original length
+ */
+ public void setLength( int length ) {
+ if (length < 0) return;
+ Option[] newArray = new Option[ length ];
+ System.arraycopy( _options, 0, newArray, 0, Math.min( length, _options.length ) );
+ for (int i = _options.length; i < length; i++) {
+ newArray[i] = new Option();
+ }
+ _options = newArray;
+ }
+
+
+ public void put( int i, SelectionOption option ) {
+ if (i < 0) return;
+
+ if (option == null) {
+ if (i >= _options.length) return;
+ deleteOptionsEntry( i );
+ } else {
+ if (i >= _options.length) {
+ i = _options.length;
+ expandOptionsArray();
+ }
+ _options[i] = (Option) option;
+ _options[i].setIndex( this, i );
+ if (option.isSelected()) ensureUniqueOption( _options, i);
+ }
+ }
+
+
+ protected abstract void ensureUniqueOption( Option[] options, int i );
+
+
+ private void deleteOptionsEntry( int i ) {
+ Option[] newArray = new Option[ _options.length-1 ];
+ System.arraycopy( _options, 0, newArray, 0, i );
+ System.arraycopy( _options, i+1, newArray, i, newArray.length - i );
+ _options = newArray;
+ }
+
+
+ private void expandOptionsArray() {
+ Option[] newArray = new Option[ _options.length+1 ];
+ System.arraycopy( _options, 0, newArray, 0, _options.length );
+ _options = newArray;
+ }
+
+ /**
+ * get the Object at the given index
+ * check that the index is not out of bounds
+ * @param index - the index of the object to get
+ * @throw RuntimeException if index is out of bounds
+ * @since [ 1124057 ] Out of Bounds Exception should be avoided
+ *
+ */
+ public Object get( int index ) {
+ // if the index is out of bounds
+ if (index < 0 || index >= _options.length) {
+ // create a user friendly error message
+ String msg="invalid index "+index+" for Options ";
+ // by listing all possible options
+ for (int i = 0; i < _options.length; i++) {
+ msg=msg+(_options[i]._text);
+ if (i<_options.length-1)
+ msg=msg+",";
+ } // for
+ // now throw a RunTimeException that would
+ // have happened anyways with a less friendly message
+ throw new RuntimeException(msg);
+ } // if
+ return _options[ index ];
+ } // get
+
+
+ /** Invoked when an option is set true. **/
+ void optionSet( int i ) {
+ ensureUniqueOption( _options, i);
+ }
+
+
+ private String getOptionValue( Node optionNode, String displayedText ) {
+ NamedNodeMap nnm = optionNode.getAttributes();
+ if (nnm.getNamedItem( "value" ) != null) {
+ return getValue( nnm.getNamedItem( "value" ) );
+ } else {
+ return displayedText;
+ }
+ }
+
+ private String getValue( Node node ) {
+ return (node == null) ? "" : emptyIfNull( node.getNodeValue() );
+ }
+ }
+
+
+ class SingleSelectOptions extends Options {
+
+ public SingleSelectOptions( Node selectionNode ) {
+ super( selectionNode );
+ }
+
+
+ protected void ensureUniqueOption( Option[] options, int i ) {
+ for (int j = 0; j < options.length; j++) {
+ options[j]._selected = (i == j);
+ }
+ }
+
+
+ protected int noOptionSelectedIndex() {
+ return 0;
+ }
+
+
+ /**
+ * claim the values
+ * be aware of [ 1100437 ] Patch for ClassCastException in FormControl
+ * TODO implement patch if test get's available - the (String) cast might fail
+ */
+ protected boolean claimUniqueValues( List values, Option[] options ) {
+ boolean changed = false;
+ for (int i = 0; i < values.size(); i++) {
+ String value = (String) values.get( i );
+ for (int j = 0; j < options.length; j++) {
+ boolean selected = value.equals( options[j].getValue() );
+ if (selected != options[j].isSelected()) changed = true;
+ options[j].setSelected( selected );
+ if (selected) {
+ values.remove( value );
+ for (++j; j < options.length; j++) options[j].setSelected( false );
+ return changed;
+ }
+ }
+ }
+ reportNoMatches( values );
+ return changed;
+ }
+ }
+
+
+ class MultiSelectOptions extends Options {
+
+ public MultiSelectOptions( Node selectionNode ) {
+ super( selectionNode );
+ }
+
+
+ protected void ensureUniqueOption( Option[] options, int i ) {}
+
+
+ protected int noOptionSelectedIndex() {
+ return -1;
+ }
+
+
+ protected boolean claimUniqueValues( List values, Option[] options ) {
+ boolean changed = false;
+ for (int i = 0; i < options.length; i++) {
+ final boolean newValue = values.contains( options[i].getValue() );
+ if (newValue != options[i].isSelected()) changed = true;
+ options[i].setSelected( newValue );
+ if (newValue) values.remove( options[i].getValue() );
+ }
+ return changed;
+ }
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/Cookie.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/Cookie.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/Cookie.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,255 @@
+package com.meterware.httpunit.cookies;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.TimeZone;
+import java.net.URL;
+
+
+/**
+ * An HTTP client-side cookie.
+ * @author Russell Gold
+ **/
+public class Cookie {
+
+ private String _name;
+
+ private String _value;
+
+ private String _path;
+
+ private String _domain;
+
+ private long _expiredTime;
+
+
+ /**
+ * @return the _expiredTime in milliseconds
+ */
+ public long getExpiredTime() {
+ return _expiredTime;
+ }
+
+
+ /**
+ * DateFormat to be used to format original Netscape cookies
+ */
+ private final static DateFormat originalCookieFormat =
+ new SimpleDateFormat("EEE,dd-MMM-yyyy HH:mm:ss z", Locale.US);
+
+ static {
+ originalCookieFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ /**
+ * Constructs a cookie w/o any domain or path restrictions.
+ * @param name - the name of the cookie
+ * @param value - the value of the cookie
+ */
+ Cookie( String name, String value ) {
+ _name = name;
+ _value = value;
+ }
+
+ /**
+ * construct a cookie with domain and path restrictions
+ * @param name
+ * @param value
+ * @param domain
+ * @param path
+ */
+ Cookie( String name, String value, String domain, String path) {
+ this(name, value);
+ _path = path;
+ _domain = domain;
+ }
+
+ /**
+ * Constructs a cookie w/o any domain or path restrictions.
+ * @param name - the name of the cookie
+ * @param value - the value of the cookie
+ * @param attributes - a map of attributes for the cookie
+ */
+ Cookie( String name, String value, Map attributes ) {
+ this( name, value );
+ for (Iterator iterator = attributes.keySet().iterator(); iterator.hasNext();) {
+ String key = (String) iterator.next();
+ String attributeValue = (String) attributes.get( key );
+ if (key.equalsIgnoreCase( "path" )) {
+ _path = attributeValue;
+ } else if (key.equalsIgnoreCase( "domain" )) {
+ _domain = attributeValue;
+ } else if (key.equalsIgnoreCase( "max-age" )) {
+ _expiredTime = System.currentTimeMillis() + getAgeInMsec( attributeValue );
+ } else if (key.equalsIgnoreCase( "expires" )) {
+ _expiredTime = getAgeInMsecFromDate( attributeValue );
+ }
+ }
+ }
+
+
+ /**
+ * get the age of the cookie in Milliseconds from a string representaiton in seconds
+ * @param maxAgeValue - the string with the age in seconds
+ * @return - the integer millisecond value or 0 if conversion fails
+ */
+ private int getAgeInMsec( String maxAgeValue ) {
+ try {
+ return 1000 * Integer.parseInt( maxAgeValue );
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * return the age of a cookie in milliesconds from a string formatted date value
+ * @param dateValue - the string to parse
+ * @return - milliseconds as integer or 0 if parsing fails
+ */
+ private long getAgeInMsecFromDate( String dateValue ) {
+ try {
+ // SimpleDateFormat isn't thread-safe
+ synchronized(originalCookieFormat) {
+ long age=originalCookieFormat.parse( dateValue ).getTime();
+ return age;
+ }
+ } catch (ParseException e) {
+ return 0;
+ }
+ }
+
+
+ /**
+ * Returns the name of this cookie.
+ */
+ public String getName() {
+ return _name;
+ }
+
+
+ /**
+ * Returns the value associated with this cookie.
+ */
+ public String getValue() {
+ return _value;
+ }
+
+ /**
+ * Sets the value associated with this cookie.
+ */
+ public void setValue(String value) {
+ _value = value;
+ }
+
+ /**
+ * Returns the path to which this cookie is restricted.
+ */
+ public String getPath() {
+ return _path;
+ }
+
+
+ /**
+ * Returns the domain to which this cookie may be sent.
+ */
+ public String getDomain() {
+ return _domain;
+ }
+
+
+ void setPath( String path ) {
+ _path = path;
+ }
+
+
+ void setDomain( String domain ) {
+ _domain = domain;
+ }
+
+
+ public int hashCode() {
+ int hashCode = _name.hashCode();
+ if (_domain != null) hashCode ^= _domain.hashCode();
+ if (_path != null) hashCode ^= _path.hashCode();
+ return hashCode;
+ }
+
+
+ public boolean equals( Object obj ) {
+ return obj.getClass() == getClass() && equals( (Cookie) obj );
+ }
+
+
+ private boolean equals( Cookie other ) {
+ return _name.equalsIgnoreCase( other._name ) &&
+ equalProperties( getDomain(), other.getDomain() ) &&
+ equalProperties( getPath(), other.getPath() );
+ }
+
+
+ private boolean equalProperties( String first, String second ) {
+ return first == second || (first != null && first.equals( second ));
+ }
+
+ /**
+ * check whether the cookie is expired
+ * @return true if the _expiredTime is higher than the current System time
+ */
+ public boolean isExpired() {
+ boolean expired=_expiredTime != 0 && _expiredTime <= System.currentTimeMillis();
+ return expired;
+ }
+
+ /**
+ * may this cookie be sent to the given url?
+ * @param url - the unform resource locator to check
+ * @return true if the cookie is not expired and the path is accepted if a domain is set
+ */
+ public boolean mayBeSentTo( URL url ) {
+ if (getDomain() == null) return true;
+ if (isExpired()) return false;
+
+ return acceptHost( getDomain(), url.getHost() ) && acceptPath( getPath(), url.getPath() );
+ }
+
+
+ private boolean acceptPath( String pathPattern, String hostPath ) {
+ return !CookieProperties.isPathMatchingStrict() || hostPath.startsWith( pathPattern );
+ }
+
+ /**
+ * accept host if the given hostName fits to the given hostPattern
+ * @param hostPattern
+ * @param hostName
+ * @return true if there is a fit
+ */
+ private static boolean acceptHost( String hostPattern, String hostName ) {
+ return hostPattern.equalsIgnoreCase( hostName ) ||
+ (hostPattern.startsWith( "." ) && hostName.endsWith( hostPattern ));
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieJar.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieJar.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieJar.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,572 @@
+package com.meterware.httpunit.cookies;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2004,2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.*;
+
+
+/**
+ * A collection of HTTP cookies, which can interact with cookie and set-cookie header values.
+ *
+ * @author Russell Gold
+ * @author Drew Varner
+ **/
+public class CookieJar {
+
+ private static final int DEFAULT_HEADER_SIZE = 80;
+
+ private ArrayList _cookies = new ArrayList();
+ private ArrayList _globalCookies = new ArrayList();
+ private CookiePress _press;
+
+
+ /**
+ * Creates an empty cookie jar.
+ */
+ public CookieJar() {
+ _press = new CookiePress( null );
+ }
+
+
+ /**
+ * Creates a cookie jar which is initially populated with cookies parsed from the Set-Cookie
and
+ * Set-Cookie2
header fields.
+ * Vector
.
+ * handles the broken syntax for expires= fields ...
+ * @param cookieHeader - the header to read
+ * @return a Vector of cookieTokens as name=value pairs
+ **/
+ private Vector getCookieTokens(String cookieHeader) {
+ StringReader sr = new StringReader(cookieHeader);
+ StreamTokenizer st = new StreamTokenizer(sr);
+ Vector tokens = new Vector();
+
+ // clear syntax tables of the StreamTokenizer
+ st.resetSyntax();
+
+ // set all characters as word characters
+ st.wordChars(0,Character.MAX_VALUE);
+
+ // set up characters for quoting
+ st.quoteChar( '"' ); //double quotes
+ st.quoteChar( '\'' ); //single quotes
+
+ // set up characters to separate tokens
+ st.whitespaceChars(59,59); //semicolon
+ // and here we run into trouble ...
+ // see http://www.mnot.net/blog/2006/10/27/cookie_fun
+ // ... Notice something about the above? It uses a comma inside of the date,
+ // without quoting the value. This makes it difficult for generic processors to handle the Set-Cookie header.
+ st.whitespaceChars(44,44); //comma
+
+ try {
+ while (st.nextToken() != StreamTokenizer.TT_EOF) {
+ String tokenContent=st.sval;
+ // fix expires comma delimiter token problem
+ if (tokenContent.toLowerCase().startsWith("expires=")) {
+ if (st.nextToken() != StreamTokenizer.TT_EOF) {
+ tokenContent+=","+st.sval;
+ } // if
+ } // if
+ tokenContent=tokenContent.trim();
+ tokens.addElement( tokenContent );
+ }
+ }
+ catch (IOException ioe) {
+ // this will never happen with a StringReader
+ }
+ sr.close();
+ return tokens;
+ }
+
+
+ abstract protected boolean isCookieAttribute( String stringLowercase );
+
+
+ abstract protected boolean isCookieReservedWord( String token );
+
+ }
+
+
+ /**
+ * cookie Factory - creates cookies for URL s
+ *
+ */
+ class CookiePress {
+
+ private StringBuffer _value = new StringBuffer();
+ private HashMap _attributes = new HashMap();
+ private URL _sourceURL;
+
+
+ /**
+ * create a cookie press for the given URL
+ * @param sourceURL
+ */
+ public CookiePress( URL sourceURL ) {
+ _sourceURL = sourceURL;
+ }
+
+
+ void clear() {
+ _value.setLength(0);
+ _attributes.clear();
+ }
+
+
+ void addToken( String token, char lastChar ) {
+ _value.insert( 0, token );
+ if (lastChar != '=') _value.insert( 0, ',' );
+ }
+
+
+ /**
+ * add from a token
+ * @param recipe - the recipe to use
+ * @param token - the token to use
+ * @param equalsIndex - the position of the equal sign
+ */
+ void addTokenWithEqualsSign( CookieRecipe recipe, String token, int equalsIndex ) {
+ String name = token.substring( 0, equalsIndex ).trim();
+ String value= token.substring( equalsIndex + 1 ).trim();
+ _value.insert( 0, value );
+ if (recipe.isCookieAttribute( name.toLowerCase() )) {
+ _attributes.put( name.toLowerCase(), _value.toString() );
+ } else {
+ addCookieIfValid( new Cookie( name, _value.toString(), _attributes ) );
+ _attributes.clear();
+ }
+ _value.setLength(0);
+ }
+
+
+ /**
+ * add the given cookie if it is valid
+ * @param cookie
+ */
+ private void addCookieIfValid( Cookie cookie ) {
+ if (acceptCookie( cookie )) addUniqueCookie( cookie );
+ }
+
+
+ /**
+ * accept the given cookie
+ * @param cookie
+ * @return
+ */
+ private boolean acceptCookie( Cookie cookie ) {
+ if (cookie.getPath() == null) {
+ cookie.setPath( getParentPath( _sourceURL.getPath() ) );
+ } else {
+ int status = getPathAttributeStatus( cookie.getPath(), _sourceURL.getPath() );
+ if (status != CookieListener.ACCEPTED) {
+ reportCookieRejected( status, cookie.getPath(), cookie.getName() );
+ return false;
+ }
+ }
+
+ if (cookie.getDomain() == null) {
+ cookie.setDomain( _sourceURL.getHost() );
+ } else if (!CookieProperties.isDomainMatchingStrict() && cookie.getDomain().equalsIgnoreCase( _sourceURL.getHost() )) {
+ cookie.setDomain( _sourceURL.getHost() );
+ } else {
+ int status = getDomainAttributeStatus( cookie.getDomain(), _sourceURL.getHost() );
+ if (status != CookieListener.ACCEPTED) {
+ reportCookieRejected( status, cookie.getDomain(), cookie.getName() );
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private String getParentPath( String path ) {
+ int rightmostSlashIndex = path.lastIndexOf( '/' );
+ return rightmostSlashIndex < 0 ? "/" : path.substring( 0, rightmostSlashIndex );
+ }
+
+
+ private int getPathAttributeStatus( String pathAttribute, String sourcePath ) {
+ if (!CookieProperties.isPathMatchingStrict() || sourcePath.length() == 0 || sourcePath.startsWith( pathAttribute )) {
+ return CookieListener.ACCEPTED;
+ } else {
+ return CookieListener.PATH_NOT_PREFIX;
+ }
+ }
+
+
+ /**
+ * get the domainAttribute Status for the given domainAttribute with the given sourceHost
+ * @see http://wp.netscape.com/newsref/std/cookie_spec.html
+ * @param domainAttribute
+ * @param sourceHost
+ * @return
+ */
+ private int getDomainAttributeStatus( String domainAttribute, String sourceHost ) {
+ // patch according to [ 1476380 ] Cookies incorrectly rejected despite valid domain
+ if (domainAttribute.equals(sourceHost)) {
+ return CookieListener.ACCEPTED;
+ }
+ if (!domainAttribute.startsWith("."))
+ domainAttribute = '.' + domainAttribute;
+
+ if (domainAttribute.lastIndexOf('.') == 0) {
+ return CookieListener.DOMAIN_ONE_DOT;
+ } else if (!sourceHost.endsWith( domainAttribute )) {
+ return CookieListener.DOMAIN_NOT_SOURCE_SUFFIX;
+ } else if (CookieProperties.isDomainMatchingStrict() &&
+ sourceHost.lastIndexOf( domainAttribute ) > sourceHost.indexOf( '.' )) {
+ return CookieListener.DOMAIN_TOO_MANY_LEVELS;
+ } else {
+ return CookieListener.ACCEPTED;
+ }
+ }
+
+ private boolean reportCookieRejected( int reason, String attribute, String source ) {
+ CookieProperties.reportCookieRejected( reason, attribute, source );
+ return false;
+ }
+
+ }
+
+
+ /**
+ * Parses cookies according to
+ * RFC 2109
+ *
+ *
+ * These cookies come from the Set-Cookie:
header
+ **/
+ class RFC2109CookieRecipe extends CookieRecipe {
+
+ /**
+ * check whether the given lower case String is a cookie attribute
+ * @param stringLowercase - the string to check
+ * @return true - if the string is the name of a valid cookie attribute
+ */
+ protected boolean isCookieAttribute( String stringLowercase ) {
+ return stringLowercase.equals("path") ||
+ stringLowercase.equals("domain") ||
+ stringLowercase.equals("expires") ||
+ stringLowercase.equals("comment") ||
+ stringLowercase.equals("max-age") ||
+ stringLowercase.equals("version");
+ }
+
+
+ protected boolean isCookieReservedWord( String token ) {
+ return token.equalsIgnoreCase( "secure" );
+ }
+ }
+
+
+ /**
+ * Parses cookies according to
+ * RFC 2965
+ *
+ *
+ * These cookies come from the Set-Cookie2:
header
+ **/
+ class RFC2965CookieRecipe extends CookieRecipe {
+
+ protected boolean isCookieAttribute( String stringLowercase ) {
+ return stringLowercase.equals("path") ||
+ stringLowercase.equals("domain") ||
+ stringLowercase.equals("comment") ||
+ stringLowercase.equals("commenturl") ||
+ stringLowercase.equals("max-age") ||
+ stringLowercase.equals("version") ||
+ stringLowercase.equals("$version") ||
+ stringLowercase.equals("port");
+ }
+
+
+ protected boolean isCookieReservedWord( String token ) {
+ return token.equalsIgnoreCase( "discard" ) || token.equalsIgnoreCase( "secure" );
+ }
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,53 @@
+package com.meterware.httpunit.cookies;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2003-2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * An interface for classes which can listen for cookies being rejected and the reason.
+ *
+ * @author Russell Gold
+ */
+public interface CookieListener {
+
+
+ /** Indicates that the cookie was accepted. **/
+ public final static int ACCEPTED = 0;
+
+ /** Indicates that the domain attribute has only one dot. **/
+ public final static int DOMAIN_ONE_DOT = 2;
+
+ /** Indicates that the domain attribute is not a suffix of the source domain issuing the cookie. **/
+ public final static int DOMAIN_NOT_SOURCE_SUFFIX = 3;
+
+ /** Indicates that the source domain has an extra dot beyond those defined in the domain attribute. **/
+ public final static int DOMAIN_TOO_MANY_LEVELS = 4;
+
+ /** Indicates that the source path does not begin with the path attribute. **/
+ public final static int PATH_NOT_PREFIX = 5;
+
+
+ /**
+ * Invoked when a cookie is rejected by HttpUnit.
+ **/
+ void cookieRejected( String cookieName, int reason, String attribute );
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieProperties.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieProperties.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieProperties.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,107 @@
+package com.meterware.httpunit.cookies;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2003-2004, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+
+/**
+ * Controls behavior for cookies.
+ */
+public class CookieProperties {
+
+ /** If true, domain matching follows the spec. If false, permits any domain which is a prefix of the host. **/
+ private static boolean _domainMatchingStrict = true;
+
+ /** If true, path matching follows the spec. If false, permits any path. **/
+ private static boolean _pathMatchingStrict = true;
+
+ /** A collection of listeners for cookie events. **/
+ private static ArrayList _listeners;
+
+
+ public static void reset() {
+ _domainMatchingStrict = true;
+ _pathMatchingStrict = true;
+ _listeners = null;
+ }
+
+
+ /**
+ * Returns true (the default) if cookies should be rejected if they specify a domain which is not a suffix
+ * of the host domain or does not contain all of the dots in that host domain name
+ * (see RFC2965).
+ */
+ public static boolean isDomainMatchingStrict() {
+ return _domainMatchingStrict;
+ }
+
+
+ /**
+ * Specifies whether strict domain name matching must be followed.
+ */
+ public static void setDomainMatchingStrict( boolean domainMatchingStrict ) {
+ _domainMatchingStrict = domainMatchingStrict;
+ }
+
+
+ /**
+ * Returns true (the default) if cookies should be rejected if they specify a path which is not a prefix
+ * of the request path (see RFC2965).
+ */
+ public static boolean isPathMatchingStrict() {
+ return _pathMatchingStrict;
+ }
+
+
+ /**
+ * Specifies whether strict path name matching must be followed.
+ */
+ public static void setPathMatchingStrict( boolean pathMatchingStrict ) {
+ _pathMatchingStrict = pathMatchingStrict;
+ }
+
+
+ /**
+ * Adds a listener for cookie events.
+ */
+ public static void addCookieListener( CookieListener listener ) {
+ if (_listeners == null) _listeners = new ArrayList();
+ synchronized( _listeners ) {
+ _listeners.add( listener );
+ }
+ }
+
+
+ public static void reportCookieRejected( int reason, String attribute, String source ) {
+ if (_listeners == null) return;
+
+ List listeners;
+ synchronized( _listeners ) {
+ listeners = (List) _listeners.clone();
+ }
+
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ ((CookieListener) i.next()).cookieRejected( source, reason, attribute );
+ }
+ }
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieSource.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieSource.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/CookieSource.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,43 @@
+package com.meterware.httpunit.cookies;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.net.URL;
+
+
+/**
+ * This interface represents a source from which to parse out cookies.
+ *
+ * @author Russell Gold
+ **/
+public interface CookieSource {
+
+ /**
+ * Returns the URL which invoked this response.
+ **/
+ URL getURL();
+
+
+ /**
+ * Returns the values for the specified header field. If no such field is defined, will return an empty array.
+ **/
+ String[] getHeaderFields( String fieldName );
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/package.html
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/package.html (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/cookies/package.html (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,12 @@
+
+Installation
+The package depends on a number of external jar files, provided in the jar
directory:
+
+
+
+document.write()
will only work with NekoHTML.Example
+In the following code, a web conversation is started and an initial request sent. The program
+then prints out the response and extracts the first form (the login form) from it. After
+setting the name parameter to the desired value, it submits the form and prints the response.
+
+import com.meterware.httpunit.*;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.xml.sax.*;
+
+public class Example {
+
+
+ public static void main( String[] params ) {
+ try {
+ WebConversation conversation = new WebConversation();
+
+ WebResponse response = conversation.getResponse( "http://www.meterware.com/servlet/TopSecret" );
+ System.out.println( response );
+
+ WebForm loginForm = response.getForms()[0];
+
+ loginForm.setParameter( "name", "master" );
+ response = loginForm.submit();
+ System.out.println( response );
+
+ } catch (Exception e) {
+ System.err.println( "Exception: " + e );
+ }
+ }
+}
+
+
+Please direct any questions to Russell Gold.
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/DocumentAdapter.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/DocumentAdapter.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/DocumentAdapter.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,57 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2007, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptableDelegate;
+import com.meterware.httpunit.scripting.ScriptingHandler;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.html.HTMLDocument;
+
+import java.io.IOException;
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+public interface DocumentAdapter {
+
+
+ /**
+ * Records the root (Document) node.
+ */
+ public void setDocument( HTMLDocument document );
+
+
+ /**
+ * Returns the contents of an included script, given its src attribute.
+ * @param srcAttribute the relative URL for the included script
+ * @return the contents of the script.
+ * @throws java.io.IOException if there is a problem retrieving the script
+ */
+ public String getIncludedScript( String srcAttribute ) throws IOException;
+
+
+ /**
+ * Returns the Scriptable object associated with the document
+ */
+ public ScriptingHandler getScriptingHandler();
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParser.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParser.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParser.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,70 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.xml.sax.SAXException;
+
+import java.net.URL;
+import java.io.IOException;
+
+/**
+ * A front end to a DOM parser that can handle HTML.
+ *
+ * @since 1.5.2
+ * @author Russell Gold
+ * @author Bernhard Wagner
+ **/
+public interface HTMLParser {
+
+ /**
+ * Parses the specified text string as a Document, registering it in the HTMLPage.
+ * Any error reporting will be annotated with the specified URL.
+ */
+ public void parse( URL baseURL, String pageText, DocumentAdapter adapter ) throws IOException, SAXException;
+
+
+ /**
+ * Removes any string artifacts placed in the text by the parser. For example, a parser may choose to encode
+ * an HTML entity as a special character. This method should convert that character to normal text.
+ */
+ public String getCleanedText( String string );
+
+
+ /**
+ * Returns true if this parser supports preservation of the case of tag and attribute names.
+ */
+ public boolean supportsPreserveTagCase();
+
+ /**
+ * Returns true if this parser supports forcing the upper/lower case of tag and attribute names.
+ */
+ public boolean supportsForceTagCase();
+
+ /**
+ * Returns true if this parser can return an HTMLDocument object.
+ */
+ public boolean supportsReturnHTMLDocument();
+
+
+ /**
+ * Returns true if this parser can display parser warnings.
+ */
+ public boolean supportsParserWarnings();
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserFactory.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserFactory.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserFactory.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,274 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.util.Vector;
+
+
+/**
+ * Factory for creating HTML parsers. Parser customization properties can be specified but do not necessarily work
+ * for every parser type.
+ *
+ * @since 1.5.2
+ * @author Russell Gold
+ * @author Bernhard Wagner
+ **/
+abstract public class HTMLParserFactory {
+
+ private static Vector _listeners = new Vector();
+ private static HTMLParser _jtidyParser;
+ private static HTMLParser _nekoParser;
+
+ private static HTMLParser _htmlParser;
+ private static boolean _preserveTagCase;
+ private static boolean _returnHTMLDocument;
+ private static boolean _parserWarningsEnabled;
+ // for parsers that support forcing Case
+ private static boolean _forceUpper;
+ private static boolean _forceLower;
+
+
+ /**
+ * Resets all settings to their default values. This includes the parser selection.
+ */
+ public static void reset() {
+ _preserveTagCase = false;
+ _returnHTMLDocument = true;
+ _parserWarningsEnabled = false;
+ _htmlParser = null;
+ _forceUpper = false;
+ _forceLower = false;
+ }
+
+
+ /**
+ * Selects the JTidy parser, if present.
+ */
+ public static void useJTidyParser() {
+ if (_jtidyParser == null) throw new RuntimeException( "JTidy parser not available" );
+ _htmlParser = _jtidyParser;
+ }
+
+
+ /**
+ * Selects the NekoHTML parser, if present.
+ */
+ public static void useNekoHTMLParser() {
+ if (_nekoParser == null) throw new RuntimeException( "NekoHTML parser not available" );
+ _htmlParser = _nekoParser;
+ }
+
+
+ /**
+ * Specifies the parser to use.
+ */
+ public static void setHTMLParser( HTMLParser htmlParser ) {
+ _htmlParser = htmlParser;
+ }
+
+
+ /**
+ * Returns the current selected parser.
+ */
+ public static HTMLParser getHTMLParser() {
+ if (_htmlParser == null) {
+ if (_nekoParser != null) {
+ _htmlParser = _nekoParser;
+ } else if (_jtidyParser != null) {
+ _htmlParser = _jtidyParser;
+ } else {
+ throw new RuntimeException( "No HTML parser found. Make sure that either nekoHTML.jar or Tidy.jar is in the in classpath" );
+ }
+ }
+ return _htmlParser;
+ }
+
+
+ /**
+ * Returns true if the current parser will preserve the case of HTML tags and attributes.
+ */
+ public static boolean isPreserveTagCase() {
+ return _preserveTagCase && getHTMLParser().supportsPreserveTagCase();
+ }
+
+
+ /**
+ * Specifies whether the parser should preserve the case of HTML tags and attributes. Not every parser can
+ * support this capability. Note that enabling this will disable support for the HTMLDocument class.
+ * override any previous behaviour configured by calling {@link #setForceUpperCase(boolean)} or
+ * {@link #setForceLowerCase(boolean)}
+ * @see #setReturnHTMLDocument
+ * @see #setForceUpperCase(boolean)
+ * @see #setForceLowerCase(boolean)
+ */
+ public static void setPreserveTagCase( boolean preserveTagCase ) {
+ _preserveTagCase = preserveTagCase;
+ if (preserveTagCase) {
+ _forceLower = false;
+ _forceUpper = false;
+ }
+ }
+
+
+ /**
+ * Returns true if the current parser will return an HTMLDocument object rather than a Document object.
+ */
+ public static boolean isReturnHTMLDocument() {
+ return _returnHTMLDocument && !isPreserveTagCase() && getHTMLParser().supportsReturnHTMLDocument();
+ }
+
+
+ /**
+ * Specifies whether the parser should return an HTMLDocument object rather than a Document object.
+ * Not every parser can support this capability. Note that enabling this will disable preservation of tag case.
+ * and/or the forcing of the tag case to upper or lower case.
+ * @see #setPreserveTagCase
+ * @see #setForceUpperCase(boolean)
+ * @see #setForceLowerCase(boolean)
+ */
+ public static void setReturnHTMLDocument( boolean returnHTMLDocument ) {
+ _returnHTMLDocument = returnHTMLDocument;
+ if (returnHTMLDocument) {
+ _preserveTagCase = false;
+ _forceLower = false;
+ _forceUpper = false;
+ }
+ }
+
+ /**
+ * Specifies whether the parser should force the case of HTML tags and attributes to be upper case. Not
+ * every parser can support this capability. Note that enabling this will disable support for the
+ * HTMLDocument class and override any previous behaviour configured by enabling
+ * {@link #setPreserveTagCase(boolean)} or {@link #setForceLowerCase(boolean)}
+ * @see #setReturnHTMLDocument
+ * @see #setPreserveTagCase(boolean)
+ * @see #setForceLowerCase(boolean)
+ * @param forceUpper
+ * boolean indicating whether to enable this functionality
+ */
+ public static void setForceUpperCase(boolean forceUpper) {
+ _forceUpper = forceUpper;
+ if (_forceUpper) {
+ _forceLower = false;
+ _preserveTagCase = false;
+ // _returnHTMLDocument = false;
+ }
+ }
+
+ /**
+ * Return true if the current parser will support forcing the tags and attributes to upper case
+ * @return boolean flag
+ */
+ public static boolean getForceUpperCase() {
+ return _forceUpper && getHTMLParser().supportsPreserveTagCase();
+ }
+
+
+ /**
+ * Specifies whether the parser should force the case of HTML tags and attributes to lower case. Not
+ * every parser can support this capability. Note that enabling this will disable support for the
+ * HTMLDocument class and override any previous behaviour configured by enabling
+ * {@link #setPreserveTagCase(boolean)} or {@link #setForceUpperCase(boolean)}
+ * @see #setReturnHTMLDocument
+ * @see #setPreserveTagCase(boolean)
+ * @see #setForceUpperCase(boolean)
+ * @param forceLower
+ * boolean indicating whether to enable this functionality
+ */
+ public static void setForceLowerCase(boolean forceLower) {
+ _forceLower = forceLower;
+ if (_forceLower) {
+ _forceUpper = false;
+ _preserveTagCase = false;
+ // _returnHTMLDocument = false;
+ }
+ }
+
+ /**
+ * Return true if the current parser will support forcing the tags and attributes to lower case
+ * @return boolean flag
+ */
+ public static boolean getForceLowerCase() {
+ return _forceLower && getHTMLParser().supportsPreserveTagCase();
+ }
+
+ /**
+ * Returns true if parser warnings are enabled.
+ **/
+ public static boolean isParserWarningsEnabled() {
+ return _parserWarningsEnabled && getHTMLParser().supportsParserWarnings();
+ }
+
+
+ /**
+ * If true, tells the parser to display warning messages. The default is false (warnings are not shown).
+ **/
+ public static void setParserWarningsEnabled( boolean enabled ) {
+ _parserWarningsEnabled = enabled;
+ }
+
+
+ /**
+ * Remove an HTML Parser listener.
+ **/
+ public static void removeHTMLParserListener( HTMLParserListener el ) {
+ _listeners.removeElement( el );
+ }
+
+
+ /**
+ * Add an HTML Parser listener.
+ **/
+ public static void addHTMLParserListener( HTMLParserListener el ) {
+ _listeners.addElement( el );
+ }
+
+
+//------------------------------------- package protected members ------------------------------------------------------
+
+
+ /**
+ * Get the list of Html Error Listeners
+ **/
+ static Vector getHTMLParserListeners() {
+ return _listeners;
+ }
+
+
+ private static HTMLParser loadParserIfSupported( final String testClassName, final String parserClassName ) {
+ try {
+ Class.forName( testClassName );
+ return (HTMLParser) Class.forName( parserClassName ).newInstance();
+ } catch (InstantiationException e) {
+ } catch (IllegalAccessException e) {
+ } catch (ClassNotFoundException e) {
+ }
+ return null;
+ }
+
+
+ static {
+ _jtidyParser = loadParserIfSupported( "org.w3c.tidy.Parser", "com.meterware.httpunit.parsing.JTidyHTMLParser" );
+ _nekoParser = loadParserIfSupported( "org.cyberneko.html.HTMLConfiguration", "com.meterware.httpunit.parsing.NekoHTMLParser" );
+ reset();
+ }
+
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserListener.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserListener.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/HTMLParserListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,51 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.net.URL;
+
+/**
+ * A listener for messages from the HTMLParser. This provides a mechanism to watch for errors and warnings generated
+ * during parsing.
+ *
+ * @author Russell Gold
+ * @author Benoit Xhenseval
+ **/
+public interface HTMLParserListener {
+
+ /**
+ * Invoked when the parser wishes to report a warning.
+ * @param url the location of the document to which the warning applies.
+ * @param msg the warning message
+ * @param line the line in the document on which the problematic HTML was found
+ * @param column the column in the document on which the problematic HTML was found
+ */
+ void warning( URL url, String msg, int line, int column );
+
+
+ /**
+ * Invoked when the parser wishes to report an error.
+ * @param url the location of the document to which the error applies.
+ * @param msg the warning message
+ * @param line the line in the document on which the problematic HTML was found
+ * @param column the column in the document on which the problematic HTML was found
+ */
+ void error( URL url, String msg, int line, int column );
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyHTMLParser.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyHTMLParser.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyHTMLParser.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,99 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002,2004,2008 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.w3c.tidy.Tidy;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.html.HTMLDocument;
+import org.xml.sax.SAXException;
+
+import java.net.URL;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.meterware.httpunit.dom.HTMLDocumentImpl;
+
+
+/**
+ *
+ * @author Russell Gold
+ **/
+class JTidyHTMLParser implements HTMLParser {
+
+
+ public void parse( URL pageURL, String pageText, DocumentAdapter adapter ) throws IOException, SAXException {
+ try {
+ Document jtidyDocument = getParser( pageURL ).parseDOM( new ByteArrayInputStream( pageText.getBytes( UTF_ENCODING ) ), null );
+ HTMLDocument htmlDocument = new HTMLDocumentImpl();
+ NodeList nl = jtidyDocument.getChildNodes();
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node importedNode = nl.item(i);
+ if (importedNode.getNodeType() != Node.DOCUMENT_TYPE_NODE) htmlDocument.appendChild( htmlDocument.importNode( importedNode, true ) );
+ }
+ adapter.setDocument( htmlDocument );
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException( "UTF-8 encoding failed" );
+ }
+ }
+
+
+ public String getCleanedText( String string ) {
+ return (string == null) ? "" : string.replace( NBSP, ' ' );
+ }
+
+
+ public boolean supportsPreserveTagCase() {
+ return false;
+ }
+
+ public boolean supportsForceTagCase() {
+ return false;
+ }
+
+ public boolean supportsReturnHTMLDocument() {
+ return true;
+ }
+
+
+ public boolean supportsParserWarnings() {
+ return true;
+ }
+
+
+ final private static char NBSP = (char) 160; // non-breaking space, defined by JTidy
+
+ final private static String UTF_ENCODING = "UTF-8";
+
+
+ private static Tidy getParser( URL url ) {
+ Tidy tidy = new Tidy();
+ tidy.setCharEncoding( org.w3c.tidy.Configuration.UTF8 );
+ tidy.setQuiet( true );
+ tidy.setShowWarnings( HTMLParserFactory.isParserWarningsEnabled() );
+ if (!HTMLParserFactory.getHTMLParserListeners().isEmpty()) {
+ tidy.setErrout( new JTidyPrintWriter( url ) );
+ }
+ return tidy;
+ }
+
+}
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyPrintWriter.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyPrintWriter.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/JTidyPrintWriter.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,214 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+* $Id$
+*
+* Copyright (c) 2001-2002, Russell Gold
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions
+* of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*******************************************************************************************************************/
+import java.util.StringTokenizer;
+import java.util.Enumeration;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+/**
+ * Basic "parser" for the JTidy error output. Will get the line and column number as well
+ * as the message. It assumes that an error or warning is to be logged once println() has been
+ * called or if a string starts with "line"
+ *
+ * @author Benoit Xhenseval
+ * @author Peter Royal
+ **/
+class JTidyPrintWriter extends PrintWriter {
+ /**
+ * DecimalFormat.getNumberInstance() should provide us with a proper formatter for the default locale. The
+ * integers returned from JTidy contain the appropriate decimal separator for the current locale.
+ */
+ private static final NumberFormat INTEGER_FORMAT = DecimalFormat.getNumberInstance();
+
+
+ JTidyPrintWriter( URL pageURL ) {
+ super(System.out);
+ _url = pageURL;
+ }
+
+ public void print(boolean b) {
+ print(String.valueOf(b));
+ }
+
+ public void print(char c) {
+ print(String.valueOf(c));
+ }
+
+ public void print(char[] s) {
+ print(String.valueOf(s));
+ }
+
+ public void print(double d) {
+ print(String.valueOf(d));
+ }
+
+ public void print(float f) {
+ print(String.valueOf(f));
+ }
+
+ public void print(int i) {
+ print(String.valueOf(i));
+ }
+
+ public void print(long l) {
+ print(String.valueOf(l));
+ }
+
+ public void print(Object obj) {
+ print(obj.toString());
+ }
+
+ /**
+ * Detects a new log if starting with "line", a warning if message starts with "Warning"
+ * and an error if it starts with "Error"
+ **/
+ public void print(String s) {
+ if (s.startsWith("line")) {
+ if (!_logged && _line > 0 && _msg!=null && _msg.length()>0) {
+ log(); // log previous!!!
+ }
+ _logged = false; // new error....
+ StringTokenizer tok = new StringTokenizer(s);
+ // skip first "line"
+ tok.nextToken();
+ // get line
+ _line = parseInteger(tok.nextToken());
+ // skip second "column"
+ tok.nextToken();
+ // get column
+ _column = parseInteger(tok.nextToken());
+ } else if (s.startsWith("Warning")) {
+ _error = false;
+ _msg = s;
+ } else if (s.startsWith("Error")) {
+ _error = true;
+ _msg = s;
+ } else {
+ // non structured msg
+ _msg += s;
+ }
+ }
+
+
+ private int parseInteger( String integer ) {
+ try {
+ return INTEGER_FORMAT.parse( integer ).intValue();
+ } catch (ParseException e) {
+ throw new NumberFormatException( "Unable to parse integer [int: " + integer + ", error: " + e.getMessage() );
+ }
+ }
+
+
+ public void println() {
+ if (!_logged) {
+ log();
+ }
+ }
+
+ public void println(boolean x) {
+ print(String.valueOf(x));
+ println();
+ }
+
+ public void println(char c) {
+ print(String.valueOf(c));
+ println();
+ }
+
+ public void println(char[] c) {
+ print(String.valueOf(c));
+ println();
+ }
+
+ public void println(double d) {
+ print(String.valueOf(d));
+ println();
+ }
+
+ public void println(float f) {
+ print(String.valueOf(f));
+ println();
+ }
+
+ public void println(int i) {
+ print(String.valueOf(i));
+ println();
+ }
+
+ public void println(long l) {
+ print(String.valueOf(l));
+ println();
+ }
+
+ public void println(Object o) {
+ print(o.toString());
+ println();
+ }
+
+ public void println(String s) {
+ print(s);
+ println();
+ }
+
+//----------------------------------------------- private members ------------------------------------------------------
+
+ private int _line = -1;
+ private int _column = -1;
+ private String _msg = "";
+ private boolean _error = false;
+ private boolean _logged = false;
+ private URL _url;
+
+ /**
+ * reports the warning or error and then resets the current error/warning.
+ **/
+ private void log() {
+ //System.out.println("Logging.........................");
+ if (_error) {
+ reportError(_msg,_line,_column);
+ } else {
+ reportWarning(_msg,_line,_column);
+ }
+ _logged = true;
+ _line = -1;
+ _column=-1;
+ _msg="";
+ }
+
+ private void reportError( String msg, int line, int column ) {
+ Enumeration listeners = HTMLParserFactory.getHTMLParserListeners().elements();
+ while (listeners.hasMoreElements()) {
+ ((HTMLParserListener) listeners.nextElement()).error( _url, msg, line, column );
+ }
+ }
+
+
+ private void reportWarning( String msg, int line, int column ) {
+ Enumeration listeners = HTMLParserFactory.getHTMLParserListeners().elements();
+ while (listeners.hasMoreElements()) {
+ ((HTMLParserListener) listeners.nextElement()).warning( _url, msg, line, column );
+ }
+ }
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoDOMParser.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoDOMParser.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoDOMParser.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,207 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2008, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import com.meterware.httpunit.scripting.ScriptingHandler;
+import com.meterware.httpunit.dom.HTMLDocumentImpl;
+
+import java.net.URL;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.cyberneko.html.HTMLConfiguration;
+import org.apache.xerces.xni.parser.XMLDocumentFilter;
+import org.apache.xerces.xni.parser.XMLErrorHandler;
+import org.apache.xerces.xni.parser.XMLParseException;
+import org.apache.xerces.xni.XNIException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.w3c.dom.Element;
+import org.w3c.dom.html.HTMLDocument;
+
+/**
+ *
+ *
+ * @author Russell Gold
+ * @author Artashes Aghajanyan
+ **/
+class NekoDOMParser extends org.apache.xerces.parsers.DOMParser implements ScriptHandler {
+
+ // private static final String HTML_DOCUMENT_CLASS_NAME = "org.apache.html.dom.HTMLDocumentImpl";
+
+ /** Error reporting feature identifier. */
+ private static final String REPORT_ERRORS = "http://cyberneko.org/html/features/report-errors";
+
+ /** Augmentations feature identifier. */
+ private static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";
+
+ /** Filters property identifier. */
+ private static final String FILTERS = "http://cyberneko.org/html/properties/filters";
+
+ /** Element case settings. possible values: "upper", "lower", "match" */
+ private static final String TAG_NAME_CASE = "http://cyberneko.org/html/properties/names/elems";
+
+ /** Attribute case settings. possible values: "upper", "lower", "no-change" */
+ private static final String ATTRIBUTE_NAME_CASE = "http://cyberneko.org/html/properties/names/attrs";
+
+ private DocumentAdapter _documentAdapter;
+
+
+ /**
+ * construct a new NekoDomParser with the given adapter and url
+ * @param adapter
+ * @param url
+ * @return - the new parser
+ * patch [ 1211154 ] NekoDOMParser default to lowercase by Dan Allen
+ * patch [ 1176688 ] Allow configuration of neko parser properties by James Abley
+ */
+ static NekoDOMParser newParser( DocumentAdapter adapter, URL url ) {
+ final HTMLConfiguration configuration = new HTMLConfiguration();
+ if (!HTMLParserFactory.getHTMLParserListeners().isEmpty() || HTMLParserFactory.isParserWarningsEnabled()) {
+ configuration.setErrorHandler( new ErrorHandler( url ) );
+ configuration.setFeature( REPORT_ERRORS, true);
+ }
+ configuration.setFeature( AUGMENTATIONS, true );
+ final ScriptFilter javaScriptFilter = new ScriptFilter( configuration );
+ configuration.setProperty( FILTERS, new XMLDocumentFilter[] { javaScriptFilter } );
+ if (HTMLParserFactory.isPreserveTagCase()) {
+ configuration.setProperty( TAG_NAME_CASE, "match" );
+ configuration.setProperty( ATTRIBUTE_NAME_CASE, "no-change" );
+ } else {
+ configuration.setProperty( TAG_NAME_CASE, "lower" );
+ configuration.setProperty( ATTRIBUTE_NAME_CASE, "lower" );
+
+ if (HTMLParserFactory.getForceUpperCase()) {
+ configuration.setProperty(TAG_NAME_CASE, "upper");
+ configuration.setProperty(ATTRIBUTE_NAME_CASE, "upper");
+ }
+ // this is the default as of patch [ 1211154 ] ... just for people who rely on patch [ 1176688 ]
+ if (HTMLParserFactory.getForceLowerCase()) {
+ configuration.setProperty(TAG_NAME_CASE, "lower");
+ configuration.setProperty(ATTRIBUTE_NAME_CASE, "lower");
+ }
+ }
+
+ try {
+ final NekoDOMParser domParser = new NekoDOMParser( configuration, adapter );
+ domParser.setFeature( DEFER_NODE_EXPANSION, false );
+ if (HTMLParserFactory.isReturnHTMLDocument()) domParser.setProperty( DOCUMENT_CLASS_NAME, HTMLDocumentImpl.class.getName() );
+ javaScriptFilter.setScriptHandler( domParser );
+ return domParser;
+ } catch (SAXNotRecognizedException e) {
+ throw new RuntimeException( e.toString() );
+ } catch (SAXNotSupportedException e) {
+ throw new RuntimeException( e.toString() );
+ }
+
+ }
+
+
+ private Element getCurrentElement() {
+ try {
+ return (Element) getProperty( CURRENT_ELEMENT_NODE );
+ } catch (SAXNotRecognizedException e) {
+ throw new RuntimeException( CURRENT_ELEMENT_NODE + " property not recognized" );
+ } catch (SAXNotSupportedException e) {
+ e.printStackTrace();
+ throw new RuntimeException( CURRENT_ELEMENT_NODE + " property not supported" );
+ }
+ }
+
+
+ NekoDOMParser( HTMLConfiguration configuration, DocumentAdapter adapter ) {
+ super( configuration );
+ _documentAdapter = adapter;
+ }
+
+
+ public String getIncludedScript( String srcAttribute ) {
+ try {
+ return _documentAdapter.getIncludedScript( srcAttribute );
+ } catch (IOException e) {
+ throw new ScriptException( e );
+ }
+ }
+
+
+ public boolean supportsScriptLanguage( String language ) {
+ return getScriptingHandler().supportsScriptLanguage( language );
+ }
+
+
+ public String runScript( final String language, final String scriptText ) {
+ getScriptingHandler().clearCaches();
+ return getScriptingHandler().runScript( language, scriptText );
+ }
+
+
+ private ScriptingHandler getScriptingHandler() {
+ _documentAdapter.setDocument( (HTMLDocument) getCurrentElement().getOwnerDocument() );
+ return _documentAdapter.getScriptingHandler();
+ }
+
+
+ static class ScriptException extends RuntimeException {
+ private IOException _cause;
+
+ public ScriptException( IOException cause ) {
+ _cause = cause;
+ }
+
+ public IOException getException() {
+ return _cause;
+ }
+ }
+}
+
+
+class ErrorHandler implements XMLErrorHandler {
+
+ private URL _url = null;
+
+ ErrorHandler( URL url ) {
+ _url = url;
+ }
+
+ public void warning( String domain, String key, XMLParseException warningException ) throws XNIException {
+ if (HTMLParserFactory.isParserWarningsEnabled()) {
+ System.out.println( "At line " + warningException.getLineNumber() + ", column " + warningException.getColumnNumber() + ": " + warningException.getMessage() );
+ }
+
+ Enumeration listeners = HTMLParserFactory.getHTMLParserListeners().elements();
+ while (listeners.hasMoreElements()) {
+ ((HTMLParserListener) listeners.nextElement()).warning( _url, warningException.getMessage(), warningException.getLineNumber(), warningException.getColumnNumber() );
+ }
+ }
+
+
+ public void error( String domain, String key, XMLParseException errorException ) throws XNIException {
+ Enumeration listeners = HTMLParserFactory.getHTMLParserListeners().elements();
+ while (listeners.hasMoreElements()) {
+ ((HTMLParserListener) listeners.nextElement()).error( _url, errorException.getMessage(), errorException.getLineNumber(), errorException.getColumnNumber() );
+ }
+ }
+
+
+ public void fatalError( String domain, String key, XMLParseException fatalError ) throws XNIException {
+ error( domain, key, fatalError );
+ throw fatalError;
+ }
+}
\ No newline at end of file
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoHTMLParser.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoHTMLParser.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/NekoHTMLParser.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,84 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002-2004,2008 Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
+import org.w3c.dom.Document;
+import org.w3c.dom.html.HTMLDocument;
+
+import java.net.URL;
+import java.io.IOException;
+import java.io.StringReader;
+
+/**
+ *
+ * @author Russell Gold
+ * @author Bernhard Wagner
+ * @author Artashes Aghajanyan
+ **/
+class NekoHTMLParser implements HTMLParser {
+
+ /**
+ * parse the given URL with the given pageText using the given document adapter
+ * @param pageURL
+ * @param pageText
+ * @param adapter
+ */
+ public void parse( URL pageURL, String pageText, DocumentAdapter adapter ) throws IOException, SAXException {
+ try {
+ NekoDOMParser parser = NekoDOMParser.newParser( adapter, pageURL );
+ parser.parse( new InputSource( new StringReader( pageText ) ) );
+ Document doc=parser.getDocument();
+ adapter.setDocument( (HTMLDocument)doc );
+ } catch (NekoDOMParser.ScriptException e) {
+ throw e.getException();
+ }
+ }
+
+
+ public String getCleanedText( String string ) {
+ return (string == null) ? "" : string.replace( NBSP, ' ' );
+ }
+
+
+ public boolean supportsPreserveTagCase() {
+ return false;
+ }
+
+ public boolean supportsForceTagCase() {
+ return false;
+ }
+
+ public boolean supportsReturnHTMLDocument() {
+ return true;
+ }
+
+
+ public boolean supportsParserWarnings() {
+ return true;
+ }
+
+
+ final private static char NBSP = (char) 160; // non-breaking space, defined by nekoHTML
+}
+
+
+
Index: 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/ScriptFilter.java
===================================================================
diff -u
--- 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/ScriptFilter.java (revision 0)
+++ 3rdParty_sources/httpunit/com/meterware/httpunit/parsing/ScriptFilter.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7)
@@ -0,0 +1,156 @@
+package com.meterware.httpunit.parsing;
+/********************************************************************************************************************
+ * $Id$
+ *
+ * Copyright (c) 2002, Russell Gold
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *******************************************************************************************************************/
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.apache.xerces.xni.Augmentations;
+import org.apache.xerces.xni.QName;
+import org.apache.xerces.xni.XMLAttributes;
+import org.apache.xerces.xni.XMLLocator;
+import org.apache.xerces.xni.XMLString;
+import org.apache.xerces.xni.XNIException;
+import org.apache.xerces.xni.parser.XMLInputSource;
+
+import org.cyberneko.html.HTMLConfiguration;
+import org.cyberneko.html.filters.DefaultFilter;
+
+/**
+ * A filter to interpret JavaScript script blocks, based on the sample Scripts program provided by NekoHTML.
+ *
+ * @author Russell Gold
+ **/
+class ScriptFilter extends DefaultFilter {
+
+ /** The NekoHTML configuration. */
+ private HTMLConfiguration _configuration;
+
+ /** A string buffer to collect the script. */
+ private StringBuffer _activeScriptBlock;
+
+ /** The name of the current script language. **/
+ private String _scriptLanguage;
+
+ /** The system identifier of the source document. */
+ private String _systemID = "";
+
+ /** The number of the current script. */
+ private int _scriptIndex;
+
+ /** The parser in which this filter is running. **/
+ private ScriptHandler _scriptHandler;
+
+
+ /** Constructs a script object with the specified configuration. */
+ ScriptFilter( HTMLConfiguration config ) {
+ _configuration = config;
+ }
+
+
+ public void setScriptHandler( ScriptHandler scriptHandler ) {
+ _scriptHandler = scriptHandler;
+ }
+
+
+ public void startDocument( XMLLocator locator, String encoding, Augmentations augs ) throws XNIException {
+ _activeScriptBlock = null;
+ _systemID = (locator == null) ? "" : (locator.getLiteralSystemId() + "_");
+ _scriptIndex = 0;
+ super.startDocument( locator, encoding, augs );
+ }
+
+
+ /**
+ * Invoked for a start element. If the element is a