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.
nameShow 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 null, the specified key is removed + * in this applet context. + * @throws 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: + *

+     *    http://java.sun.com/products/jdk/1.2/index.html
+     * 
+ * The document base is: + *
+     *    http://java.sun.com/products/jdk/1.2/
+     * 
+ * + * @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 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>
+     * 
+ *

+ * then a call to 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 [=[]]. + **/ + private void stripOneParameter( String param ) { + final int index = param.indexOf( "=" ); + String value = ((index < 0) + ? null + : ((index == param.length() - 1) + ? getEmptyParameterValue() + : decode( param.substring( index + 1 ) ) )); + String name = (index < 0) ? decode( param ) : decode( param.substring( 0, index ) ); + addPresetParameter( name, value ); + } + + + private String decode( String string ) { + return HttpUnitUtils.decode( string, _baseResponse.getCharacterSet() ).trim(); + } + + + abstract protected String getEmptyParameterValue(); + + /** + * Returns the scriptable delegate. + */ + public ScriptingHandler getScriptingHandler() { + if (_scriptable == null) { + _scriptable = HttpUnitOptions.getScriptingEngine().createHandler( this ); + } + return _scriptable; + } + + public ScriptableDelegate getParentDelegate() { + return getBaseResponse().getDocumentScriptable(); + } + + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/WebResponse.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/WebResponse.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/WebResponse.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,1571 @@ +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.NamedDelegate; +import com.meterware.httpunit.scripting.ScriptingHandler; +import com.meterware.httpunit.cookies.CookieJar; +import com.meterware.httpunit.cookies.CookieSource; +import com.meterware.httpunit.dom.HTMLDocumentImpl; +import com.meterware.httpunit.dom.DomWindow; +import com.meterware.httpunit.dom.DomWindowProxy; +import com.meterware.httpunit.dom.HTMLElementImpl; +import com.meterware.httpunit.protocol.MessageBody; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.MalformedURLException; +import java.util.Hashtable; +import java.util.Vector; +import java.util.zip.GZIPInputStream; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.mozilla.javascript.Scriptable; + +/** + * A response to a web request from a web server. + * + * @author Russell Gold + * @author Drew Varner + * @author Dave Glowacki + * @author Benoit Xhenseval + * @author Wolfgang Fahl + **/ +abstract +public class WebResponse implements HTMLSegment, CookieSource, DomWindowProxy { + + private static final String HTML_CONTENT = "text/html"; + private static final String XHTML_CONTENT = "application/xhtml+xml"; + private static final String FAUX_XHTML_CONTENT = "text/xhtml"; + // [ 1281655 ] [patch] allow text/xml to be parsed as html + // testTraversal test changed after positive reply by Russell + private static final String XML_CONTENT = "text/xml"; + // the list of valid content Types + private static String[] validContentTypes={ + HTML_CONTENT, XHTML_CONTENT, FAUX_XHTML_CONTENT, XML_CONTENT + }; + + + private static final int UNINITIALIZED_INT = -2; + private static final int UNKNOWN_LENGTH_TIMEOUT = 500; + private static final int UNKNOWN_LENGTH_RETRY_INTERVAL = 10; + + private FrameSelector _frame; + + private String _baseTarget; + private String _refreshHeader; + private URL _baseURL; + private boolean _parsingPage; + + + /** + * Returns a web response built from a URL connection. Provided to allow + * access to WebResponse parsing without using a WebClient. + **/ + public static WebResponse newResponse( URLConnection connection ) throws IOException { + return new HttpWebResponse( null, FrameSelector.TOP_FRAME, connection.getURL(), connection, HttpUnitOptions.getExceptionsThrownOnErrorStatus() ); + } + + + /** + * Returns true if the response is HTML. + * @return true if the contenType fits + **/ + public boolean isHTML() { + boolean result=false; + // check the different content types + for (int i=0;i + * + *
+ * 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. + * + * + * + * + * + * 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. + *

+ * 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. + *

+ */ + public CookieJar( CookieSource source ) { + _press = new CookiePress( source.getURL() ); + findCookies( source.getHeaderFields( "Set-Cookie" ), new RFC2109CookieRecipe() ); + findCookies( source.getHeaderFields( "Set-Cookie2" ), new RFC2965CookieRecipe() ); + } + + + /** + * find the cookies in the given Header String array + * @param cookieHeader - the strings to look for cookies + * @param recipe - the recipe to use + */ + private void findCookies( String cookieHeader[], CookieRecipe recipe ) { + for (int i = 0; i < cookieHeader.length; i++) { + recipe.findCookies( cookieHeader[i] ); + } + } + + + /** + * Empties this cookie jar of all contents. + */ + public void clear() { + _cookies.clear(); + _globalCookies.clear(); + } + + + /** + * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only + * certain cookies are sent based on their host and path. + * @deprecated as of 1.6, use #putCookie + **/ + public void addCookie( String name, String value ) { + _globalCookies.add( new Cookie( name, value ) ); + } + + + /** + * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only + * certain cookies are sent based on their host and path. + * + * Values of null will result in the cookie being removed. Any other value will leave the + * cookie unchanged expect for the value. + * + * @since 1.6 + **/ + public void putCookie( String name, String value ) { + boolean foundCookie = false; + for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) { + foundCookie = true; + if (value != null) { + cookie.setValue(value); + } else { + iterator.remove(); + } + } + } + + for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) { + foundCookie = true; + if (value != null) { + cookie.setValue(value); + } else { + iterator.remove(); + } + } + } + + // only add it if it does not already exist + if (foundCookie == false) { + _globalCookies.add( new Cookie( name, value ) ); + } + } + + /** + * Define a non-global cookie. This cookie can be overwritten by subsequent cookie definitions + * in http headers. This cookie definition requires a domain and path. If a global cookie is + * defined with the same name, this cookie is not added. + */ + public void putSingleUseCookie(String name, String value, String domain, String path) { + for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) return; + } + + for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) iterator.remove(); + } + + _cookies.add( new Cookie( name, value, domain, path) ); + } + + /** + * Returns the name of all the active cookies in this cookie jar. + **/ + public String[] getCookieNames() { + final int numGlobalCookies = _globalCookies.size(); + String[] names = new String[ _cookies.size() + numGlobalCookies ]; + for (int i = 0; i < numGlobalCookies; i++) { + names[i] = ((Cookie) _globalCookies.get(i)).getName(); + } + for (int i = numGlobalCookies; i < names.length; i++) { + names[i] = ((Cookie) _cookies.get( i-numGlobalCookies )).getName(); + } + return names; + } + + + /** + * Returns a collection containing all of the cookies in this jar. + */ + public Collection getCookies() { + final Collection collection = (Collection) _cookies.clone(); + collection.addAll( _globalCookies ); + return collection; + } + + + /** + * Returns the value of the specified cookie. + * @param name - the name of the cookie to get the value for + * @return the value of the cookie + **/ + public String getCookieValue( String name ) { + Cookie cookie = getCookie( name ); + return cookie == null ? null : cookie.getValue(); + } + + + /** + * Returns the value of the specified cookie. + **/ + public Cookie getCookie( String name ) { + if (name == null) throw new IllegalArgumentException( "getCookieValue: no name specified" ); + for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) return cookie; + } + for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) { + Cookie cookie = (Cookie) iterator.next(); + if (name.equals( cookie.getName() )) return cookie; + } + return null; + } + + + /** + * Returns the value of the cookie header to be sent to the specified URL. + * Will return null if no compatible cookie is defined. + **/ + public String getCookieHeaderField( URL targetURL ) { + if (_cookies.isEmpty() && _globalCookies.isEmpty()) return null; + StringBuffer sb = new StringBuffer( DEFAULT_HEADER_SIZE ); + HashSet restrictedCookies = new HashSet(); + for (Iterator i = _cookies.iterator(); i.hasNext();) { + Cookie cookie = (Cookie) i.next(); + if (!cookie.mayBeSentTo( targetURL )) continue; + restrictedCookies.add( cookie.getName() ); + if (sb.length() != 0) sb.append( "; " ); + sb.append( cookie.getName() ).append( '=' ).append( cookie.getValue() ); + } + for (Iterator i = _globalCookies.iterator(); i.hasNext();) { + Cookie cookie = (Cookie) i.next(); + if (restrictedCookies.contains( cookie.getName() )) continue; + if (sb.length() != 0) sb.append( "; " ); + sb.append( cookie.getName() ).append( '=' ).append( cookie.getValue() ); + } + return sb.length() == 0 ? null : sb.toString(); + } + + + /** + * Updates the cookies maintained in this cookie jar with those in another cookie jar. Any duplicate cookies in + * the new jar will replace those in this jar. + **/ + public void updateCookies( CookieJar newJar ) { + for (Iterator i = newJar._cookies.iterator(); i.hasNext();) { + addUniqueCookie( (Cookie) i.next() ); + } + } + + + /** + * Add the cookie to this jar, replacing any previous matching cookie. + */ + void addUniqueCookie( Cookie cookie ) { + _cookies.remove( cookie ); + _cookies.add( cookie ); + } + + + /** + * base class for the cookie recipies - there are two different implementations + * of this + */ + abstract class CookieRecipe { + + /** + * Extracts cookies from a cookie header. Works in conjunction with a cookie press class, which actually creates + * the cookies and adds them to the jar as appropriate. + * + * 1. Parse the header into tokens, separated by ',' and ';' (respecting single and double quotes) + * 2. Process tokens from the end: + * a. if the token contains an '=' we have a name/value pair. Add them to the cookie press, which + * will decide if it is a cookie name or an attribute name. + * b. if the token is a reserved word, flush the cookie press and continue. + * c. otherwise, add the token to the cookie press, passing along the last character of the previous token. + */ + void findCookies( String cookieHeader ) { + Vector tokens = getCookieTokens( cookieHeader ); + + for (int i = tokens.size() - 1; i >= 0; i--) { + String token = (String) tokens.elementAt( i ); + + int equalsIndex = getEqualsIndex( token ); + if (equalsIndex != -1) { + _press.addTokenWithEqualsSign( this, token, equalsIndex ); + } else if (isCookieReservedWord( token )) { + _press.clear(); + } else { + _press.addToken( token, lastCharOf( (i == 0) ? "" : (String) tokens.elementAt( i - 1 ) ) ); + } + } + } + + + private char lastCharOf( String string ) { + return (string.length() == 0) ? ' ' : string.charAt( string.length()-1 ); + } + + + /** + * Returns the index (if any) of the equals sign separating a cookie name from the its value. + * Equals signs at the end of the token are ignored in this calculation, since they may be + * part of a Base64-encoded value. + */ + private int getEqualsIndex( String token ) { + if (!token.endsWith( "==" )) { + return token.indexOf( '=' ); + } else { + return getEqualsIndex( token.substring( 0, token.length()-2 ) ); + } + } + + + /** + * Tokenizes a cookie header and returns the tokens in a + * 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 @@ + +

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.

+ Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AbstractDomComponent.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AbstractDomComponent.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AbstractDomComponent.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,75 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Header$ + * + * Copyright (c) 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.javascript.ScriptingEngineImpl; +import com.meterware.httpunit.scripting.ScriptingEngine; +import com.meterware.httpunit.scripting.ScriptableDelegate; + +import org.mozilla.javascript.Scriptable; + +/** + * @author Russell Gold + */ +public abstract class AbstractDomComponent extends ScriptingEngineImpl implements Scriptable { + + private static int _anonymousFunctionNum; + + public String getClassName() { + return getClass().getName(); + } + + + public ScriptingEngine newScriptingEngine( ScriptableDelegate child ) { + throw new UnsupportedOperationException( ); + } + + + public void clearCaches() {} + + + public boolean has( String name, Scriptable start ) { + return super.has( name, start ) || ScriptingSupport.hasNamedProperty( this, getJavaPropertyName( name ), start ); + } + + + public Object get( String propertyName, Scriptable scriptable ) { + Object result = super.get( propertyName, scriptable ); + if (result != NOT_FOUND) return result; + + return ScriptingSupport.getNamedProperty( this, getJavaPropertyName( propertyName ), scriptable ); + } + + + protected String getJavaPropertyName( String propertyName ) { + return propertyName; + } + + + public void put( String propertyName, Scriptable initialObject, Object value ) { + super.put( propertyName, initialObject, value ); + ScriptingSupport.setNamedProperty( this, getJavaPropertyName( propertyName ), value ); + } + + + protected static String createAnonymousFunctionName() { + return "anon_" + (++_anonymousFunctionNum); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttrImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttrImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttrImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,123 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.*; + +/** + * + * @author Russell Gold + **/ +public class AttrImpl extends NodeImpl implements Attr { + + private String _name; + private String _value = ""; + private boolean _specified = false; + private Element _ownerElement; + + + static AttrImpl createAttribute( DocumentImpl owner, String name ) { + AttrImpl attribute = new AttrImpl(); + attribute.initialize( owner, name ); + return attribute; + } + + + public static Attr createAttribute( DocumentImpl owner, String namespaceURI, String qualifiedName ) { + AttrImpl attribute = new AttrImpl(); + attribute.initialize( owner, qualifiedName ); + return attribute; + } + + + protected void initialize( DocumentImpl owner, String name ) { + super.initialize( owner ); + _name = name; + } + + + public String getNodeName() { + return getName(); + } + + + public String getNodeValue() throws DOMException { + return getValue(); + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + setValue( nodeValue ); + } + + + public short getNodeType() { + return ATTRIBUTE_NODE; + } + + + public String getName() { + return _name; + } + + + public boolean getSpecified() { + return _specified; + } + + + public String getValue() { + return _value; + } + + + public void setValue( String value ) throws DOMException { + _value = value; + _specified = true; + } + + + public Element getOwnerElement() { + return _ownerElement; + } + + + void setOwnerElement( Element ownerElement ) { + _ownerElement = ownerElement; + } + + + public static Node importNode( Document document, Attr attr ) { + Attr attribute = document.createAttributeNS( attr.getNamespaceURI(), attr.getName() ); + attribute.setValue( attr.getValue() ); + return attribute; + } + +//------------------------------------- DOM level 3 methods ------------------------------------------------------------ + + public TypeInfo getSchemaTypeInfo() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public boolean isId() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttributeNameAdjusted.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttributeNameAdjusted.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/AttributeNameAdjusted.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,15 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 2005, Russell Gold + * + *******************************************************************************************************************/ + +/** + * @author Russell Gold + */ +public interface AttributeNameAdjusted { + + String getJavaAttributeName( String attributeName ); +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CDATASectionImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CDATASectionImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CDATASectionImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,52 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.CDATASection; +import org.w3c.dom.Node; + +/** + * + * @author Russell Gold + **/ +public class CDATASectionImpl extends TextImpl implements CDATASection { + + public static CDATASection createCDATASection( DocumentImpl ownerDocument, String data ) { + CDATASectionImpl cdataSection = new CDATASectionImpl(); + cdataSection.initialize( ownerDocument, data ); + return cdataSection; + } + + + public static Node importNode( DocumentImpl document, CDATASection cdataSection ) { + return document.createCDATASection( cdataSection.getData() ); + } + + + public String getNodeName() { + return "#cdata-section"; + } + + + public short getNodeType() { + return CDATA_SECTION_NODE; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CharacterDataImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CharacterDataImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CharacterDataImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,80 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +import java.util.ArrayList; + +/** + * + * @author Russell Gold + **/ +abstract public class CharacterDataImpl extends NodeImpl implements CharacterData { + + private String _data; + + + protected void initialize( DocumentImpl ownerDocument, String data ) { + super.initialize( ownerDocument ); + _data = data; + } + + + public String getData() throws DOMException { + return _data; + } + + + public void setData( String data ) throws DOMException { + if (data == null) data = ""; + _data = data; + } + + + public int getLength() { + return _data.length(); + } + + + public String substringData( int offset, int count ) throws DOMException { + return null; + } + + + public void appendData( String arg ) throws DOMException { + } + + + public void insertData( int offset, String arg ) throws DOMException { + } + + + public void deleteData( int offset, int count ) throws DOMException { + } + + + public void replaceData( int offset, int count, String arg ) throws DOMException { + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CommentImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CommentImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/CommentImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,74 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Comment; + +/** + * + * @author Russell Gold + **/ +public class CommentImpl extends CharacterDataImpl implements Comment { + + + static CommentImpl createComment( DocumentImpl ownerDocument, String data ) { + CommentImpl comment = new CommentImpl(); + comment.initialize( ownerDocument, data ); + return comment; + } + + + public static Node importNode( DocumentImpl document, Comment comment ) { + return document.createComment( comment.getData() ); + } + + + public String getNodeName() { + return "#comment"; + } + + + public String getNodeValue() throws DOMException { + return getData(); + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + setData( nodeValue ); + } + + + public short getNodeType() { + return COMMENT_NODE; + } + + + protected NodeImpl getChildIfPermitted( Node proposedChild ) { + throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Comment nodes may not have children" ); + } + + + void appendContents( StringBuffer sb ) { + sb.append( getData() ); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,241 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.*; +import org.w3c.dom.html.HTMLElement; + +import java.util.Iterator; + +/** + * + * @author Russell Gold + **/ +public class DocumentImpl extends NodeImpl implements Document { + + private Element _documentElement; + + + static DocumentImpl createDocument() { + DocumentImpl document = new DocumentImpl(); + document.initialize(); + return document; + } + + + protected void initialize() {} + + + public String getNodeName() { + return "#document"; + } + + + public String getNodeValue() throws DOMException { + return null; + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + } + + + public short getNodeType() { + return DOCUMENT_NODE; + } + + + public Document getOwnerDocument() { + return this; + } + + + public DocumentType getDoctype() { + return null; + } + + + public DOMImplementation getImplementation() { + return null; + } + + + public Element getDocumentElement() { + return _documentElement; + } + + + void setDocumentElement( Element documentElement ) { + if (_documentElement != null) throw new IllegalStateException( "A document may have only one root" ); + _documentElement = documentElement; + appendChild( documentElement ); + } + + + public Element createElement( String tagName ) throws DOMException { + return ElementImpl.createElement( this, tagName ); + } + + + public DocumentFragment createDocumentFragment() { + throw new UnsupportedOperationException( "DocumentFragment creation not supported "); + } + + + public Text createTextNode( String data ) { + return TextImpl.createText( this, data ); + } + + + public Comment createComment( String data ) { + return CommentImpl.createComment( this, data ); + } + + + public CDATASection createCDATASection( String data ) throws DOMException { + return CDATASectionImpl.createCDATASection( this, data ); + } + + + public ProcessingInstruction createProcessingInstruction( String target, String data ) throws DOMException { + return ProcessingInstructionImpl.createProcessingImpl( this, target, data ); + } + + + public Attr createAttribute( String name ) throws DOMException { + return AttrImpl.createAttribute( this, name ); + } + + + public EntityReference createEntityReference( String name ) throws DOMException { + throw new UnsupportedOperationException( "EntityReference creation not supported "); + } + + + public Node importNode( Node importedNode, boolean deep ) throws DOMException { + switch (importedNode.getNodeType()) { + case Node.ATTRIBUTE_NODE: + return AttrImpl.importNode( this, (Attr) importedNode ); + case Node.CDATA_SECTION_NODE: + return CDATASectionImpl.importNode( this, (CDATASection) importedNode ); + case Node.COMMENT_NODE: + return CommentImpl.importNode( this, (Comment) importedNode ); + case Node.ELEMENT_NODE: + return ElementImpl.importNode( this, (Element) importedNode, deep ); + case Node.PROCESSING_INSTRUCTION_NODE: + return ProcessingInstructionImpl.importNode( this, (ProcessingInstruction) importedNode ); + case Node.TEXT_NODE: + return TextImpl.importNode( this, (Text) importedNode ); + default: + throw new DOMException( DOMException.NOT_SUPPORTED_ERR, "Cannot import node type " + importedNode.getNodeType() ); + } + } + + + public Element getElementById( String elementId ) { + for (Iterator each = preOrderIterator(); each.hasNext();) { + Node node = (Node) each.next(); + if (!(node instanceof HTMLElement)) continue; + HTMLElement element = (HTMLElement) node; + if (elementId.equals( element.getId() )) return element; + } + return null; + } + + + public Element createElementNS( String namespaceURI, String qualifiedName ) throws DOMException { + return ElementImpl.createElement( this, namespaceURI, qualifiedName ); + } + + + public Attr createAttributeNS( String namespaceURI, String qualifiedName ) throws DOMException { + return AttrImpl.createAttribute( this, namespaceURI, qualifiedName ); + } + + + public NodeList getElementsByTagNameNS( String namespaceURI, String localName ) { + if (namespaceURI != null) throw new UnsupportedOperationException( "Namespaces are not supported" ); + return getElementsByTagName( localName ); + } + + + void importChildren( Node original, Node copy ) { + NodeList children = original.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node childCopy = importNode( children.item(i), /* deep */ true ); + copy.appendChild( childCopy ); + } + } + + +//------------------------------------- DOM level 3 methods ------------------------------------------------------------ + + public String getInputEncoding() { + return null; + } + + public String getXmlEncoding() { + return null; + } + + public Node renameNode( Node n, String namespaceURI, String qualifiedName ) throws DOMException { + return null; + } + + public boolean getXmlStandalone() { + return false; + } + + public void setXmlStandalone( boolean xmlStandalone ) throws DOMException { + } + + public String getXmlVersion() { + return null; + } + + public void setXmlVersion( String xmlVersion ) throws DOMException { + } + + public boolean getStrictErrorChecking() { + return false; + } + + public void setStrictErrorChecking( boolean strictErrorChecking ) { + } + + public String getDocumentURI() { + return null; + } + + public void setDocumentURI( String documentURI ) { + } + + public Node adoptNode( Node source ) throws DOMException { + return null; + } + + public DOMConfiguration getDomConfig() { + return null; + } + + public void normalizeDocument() { + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentTypeImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentTypeImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DocumentTypeImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,86 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.DOMException; + +import java.util.ArrayList; + +/** + * + * @author Russell Gold + **/ +public class DocumentTypeImpl extends NodeImpl implements DocumentType { + +//---------------------------------------------- DocumentType methods -------------------------------------------------- + + public NamedNodeMap getEntities() { + return null; + } + + + public String getInternalSubset() { + return null; + } + + + public String getName() { + return null; + } + + + public NamedNodeMap getNotations() { + return null; + } + + + public String getPublicId() { + return null; + } + + + public String getSystemId() { + return null; + } + +//------------------------------------------------ NodeImpl methods ---------------------------------------------------- + + + public String getNodeName() { + return null; + } + + + public short getNodeType() { + return 0; + } + + + public String getNodeValue() throws DOMException { + return null; + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomBasedScriptingEngineFactory.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomBasedScriptingEngineFactory.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomBasedScriptingEngineFactory.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,146 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** +* $Id$ +* +* Copyright (c) 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.javascript.JavaScript; +import com.meterware.httpunit.javascript.ScriptingEngineImpl; +import com.meterware.httpunit.javascript.JavaScript.Window; +import com.meterware.httpunit.scripting.ScriptingEngineFactory; +import com.meterware.httpunit.scripting.ScriptingHandler; +import com.meterware.httpunit.scripting.ScriptingEngine; +import com.meterware.httpunit.HttpUnitUtils; +import com.meterware.httpunit.WebResponse; +import com.meterware.httpunit.HTMLElement; + +import java.util.ArrayList; +import java.util.logging.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.html.HTMLDocument; +import org.w3c.dom.html.HTMLBodyElement; +import org.xml.sax.SAXException; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.EcmaError; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.JavaScriptException; +import org.mozilla.javascript.Scriptable; + +/** + * The scripting engine factory which relies directly on the DOM. + */ +public class DomBasedScriptingEngineFactory implements ScriptingEngineFactory { + + + /** + * check whether this ScriptingEngineFactory is enabled + */ + public boolean isEnabled() { + try { + Class.forName( "org.mozilla.javascript.Context" ); + return true; + } catch (Exception e) { + Logger.getLogger( "httpunit.org" ).warning( "Rhino classes (js.jar) not found - Javascript disabled" ); + return false; + } + } + + + /** + * associate me with a webresponse + * @param response - the WebResponse to use + */ + public void associate( WebResponse response ) { + try { + // JavaScript.run( response ); // can't do this (yet?) + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + HttpUnitUtils.handleException(e); + throw new RuntimeException( e.toString() ); + } + } + + + /** + * load + * @param response + */ + public void load( WebResponse response ) { + Function onLoadEvent=null; + try { + Context context = Context.enter(); + context.initStandardObjects( null ); + + HTMLDocument htmlDocument = ((DomWindow) response.getScriptingHandler()).getDocument(); + if (!(htmlDocument instanceof HTMLDocumentImpl)) return; + + HTMLBodyElementImpl body = (HTMLBodyElementImpl) htmlDocument.getBody(); + if (body == null) return; + onLoadEvent = body.getOnloadEvent(); + if (onLoadEvent == null) return; + onLoadEvent.call( context, body, body, new Object[0] ); + } catch (JavaScriptException e) { + ScriptingEngineImpl.handleScriptException(e, onLoadEvent.toString()); + // HttpUnitUtils.handleException(e); + } catch (EcmaError ee) { + //throw ee; + ScriptingEngineImpl.handleScriptException(ee, onLoadEvent.toString()); + } finally { + Context.exit(); + } + } + + /** + * setter for the throwExceptions flag + * @param throwExceptions - true if Exceptions should be thrown + */ + public void setThrowExceptionsOnError( boolean throwExceptions ) { + JavaScript.setThrowExceptionsOnError( throwExceptions ); + } + + + /** + * getter for the throwExceptions flag + * @return - true if Exceptions should be thrown + */ + public boolean isThrowExceptionsOnError() { + return JavaScript.isThrowExceptionsOnError(); + } + + + public String[] getErrorMessages() { + return ScriptingEngineImpl.getErrorMessages(); + } + + + public void clearErrorMessages() { + ScriptingEngineImpl.clearErrorMessages(); + } + + + public ScriptingHandler createHandler( HTMLElement elementBase ) { + return (ScriptingHandler) elementBase.getNode(); + } + + + public ScriptingHandler createHandler( WebResponse response ) { + return response.createDomScriptingHandler(); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomListener.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomListener.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomListener.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,31 @@ +package com.meterware.httpunit.dom; +import org.w3c.dom.Node; +import org.w3c.dom.Element; +/******************************************************************************************************************** + * $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. + * + *******************************************************************************************************************/ + +/** + * @author Russell Gold + */ +public interface DomListener { + + void propertyChanged( Element changedElement, String propertyName ); +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindow.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindow.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindow.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,183 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** +* $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 java.io.IOException; +import java.net.URL; + +import org.xml.sax.SAXException; +import org.mozilla.javascript.Scriptable; +import org.w3c.dom.html.HTMLDocument; + +import com.meterware.httpunit.scripting.ScriptingHandler; + +/** + * @author Russell Gold + */ +public class DomWindow extends AbstractDomComponent implements Scriptable { + + private DomWindowProxy _proxy; + private HTMLDocumentImpl _document; + + /** + * construct me from a document + * @param document + */ + public DomWindow( HTMLDocumentImpl document ) { + _document = document; + } + + + public DomWindow( DomWindowProxy implementation ) { + _proxy = implementation; + } + + + public void setProxy( DomWindowProxy proxy ) { + _proxy = proxy; + } + + + public DomWindow getWindow() { + return this; + } + + + public DomWindow getSelf() { + return this; + } + + + public HTMLDocument getDocument() { + return _document; + } + + + /** + * Returns the document associated with this window. Uses the same name as that used by elements in the DOM. + */ + public HTMLDocument getOwnerDocument() { + return _document; + } + + + /** + * Opens a named window. + * @param urlString the location (relative to the current page) from which to populate the window. + * @param name the name of the window. + * @param features special features for the window. + * @param replace if true, replaces the contents of an existing window. + * @return a new populated window object + */ + public DomWindow open( String urlString, String name, String features, boolean replace ) { + try { + if (_proxy==null) { + throw new RuntimeException("DomWindow.open failed for '"+name+"' _proxy is null"); + } + + DomWindowProxy newWindow=_proxy.openNewWindow( name, urlString ); + if (newWindow==null) { + // throw new RuntimeException("DomWindow.open failed for '"+name+"','"+urlString+"' openNewWindow returned null"); + return null; + } + ScriptingHandler result=newWindow.getScriptingHandler(); + return (DomWindow) result; + } catch (IOException e) { + return null; + } catch (SAXException e) { + return null; + } + } + + + /** + * Closes the current window. Has no effect if this "window" is actually a nested frame. + */ + public void close() { + _proxy.close(); + } + + + /** + * Displays an alert box with the specified message. + * @param message the message to display + */ + public void alert( String message ) { + _proxy.alert( message ); + } + + + /** + * Displays a prompt, asking for a yes or no answer and returns the answer. + * @param prompt the prompt text to display + * @return true if the user answered 'yes' + */ + public boolean confirm( String prompt ) { + return _proxy.confirm( prompt ); + } + + + /** + * Displays a promptand returns the user's textual reply, which could be the default reply. + * @param message the prompt text to display + * @param defaultResponse the response to return if the user doesn't enter anything + * @return the reply selected by the user. + */ + public String prompt( String message, String defaultResponse ) { + return _proxy.prompt( message, defaultResponse ); + } + + + public void setTimeout( int timeout ) { + } + + + public void focus() { + } + + + public void moveTo( int x, int y ) { + } + + + protected String getDocumentWriteBuffer() { + return _document.getWriteBuffer().toString(); + } + + + protected void discardDocumentWriteBuffer() { + _document.clearWriteBuffer(); + } + + + boolean replaceText( String string, String mimeType ) { + return _proxy.replaceText( string, mimeType ); + } + + + URL getUrl() { + return _proxy.getURL(); + } + + + void submitRequest( HTMLElementImpl sourceElement, String method, String location, String target, byte[] requestBody ) throws IOException, SAXException { + _proxy.submitRequest( sourceElement, method, location, target, null ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindowProxy.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindowProxy.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/DomWindowProxy.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,68 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** +* $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 com.meterware.httpunit.scripting.ScriptingHandler; +import com.meterware.httpunit.protocol.MessageBody; + +import java.io.IOException; +import java.net.URL; + +import org.xml.sax.SAXException; + +/** + * @author Russell Gold + */ +public interface DomWindowProxy { + + DomWindowProxy openNewWindow( String name, String relativeUrl ) throws IOException, SAXException; + + + ScriptingHandler getScriptingHandler(); + + + void close(); + + + void alert( String message ); + + + boolean confirm( String message ); + + + String prompt( String prompt, String defaultResponse ); + + + /** + * Returns the URL associated with the window. + * @return the URL associated with the window. + */ + URL getURL(); + + + /** + * Replaces the text in the window with the specified text and content type. Returns false if unable + * to do the replacement. + */ + boolean replaceText( String text, String contentType ); + + + DomWindowProxy submitRequest( HTMLElementImpl sourceElement, String method, String location, String target, MessageBody requestBody ) throws IOException, SAXException; +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,241 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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.dom.*; + +import java.util.Hashtable; +import java.util.ArrayList; +import java.util.Iterator; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeEvent; + +/** + * + * @author Russell Gold + **/ +public class ElementImpl extends NamespaceAwareNodeImpl implements Element { + + private Hashtable _attributes = new Hashtable(); + private ArrayList _listeners = new ArrayList( ); + + static ElementImpl createElement( DocumentImpl owner, String tagName ) { + ElementImpl element = new ElementImpl(); + element.initialize( owner, tagName ); + return element; + } + + + public static Element createElement( DocumentImpl owner, String namespaceURI, String qualifiedName ) { + ElementImpl element = new ElementImpl(); + element.initialize( owner, namespaceURI, qualifiedName ); + return element; + } + + + public void addDomListener( DomListener listener ) { + synchronized (_listeners) { + _listeners.add( listener ); + } + } + + + protected void reportPropertyChanged( String propertyName ) { + ArrayList listeners; + synchronized( _listeners ) { + listeners = (ArrayList) _listeners.clone(); + } + + for (Iterator each = listeners.iterator(); each.hasNext();) { + ((DomListener) each.next()).propertyChanged( this, propertyName ); + } + } + +//---------------------------------------- Element methods ------------------------------------------------------------- + + public short getNodeType() { + return ELEMENT_NODE; + } + + + public String getNodeValue() throws DOMException { + return null; + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + } + + + public boolean hasAttributes() { + return !_attributes.isEmpty(); + } + + + public NamedNodeMap getAttributes() { + return new NamedNodeMapImpl( _attributes ); + } + + + /** + * get the attribute with the given name + * @param name - the name of the attribute to get + */ + public String getAttribute( String name ) { + Attr attr = getAttributeNode( name ); + return attr == null ? "" : attr.getValue(); + } + + + public void setAttribute( String name, String value ) throws DOMException { + if (value.equals( getAttribute( name ))) return; + + Attr attribute = getOwnerDocument().createAttribute( name ); + attribute.setValue( value ); + setAttributeNode( attribute ); + reportPropertyChanged( name ); + } + + /** + * get the event Handler script for the event e.g. onchange, onmousedown, onclick, onmouseup + * execute the script if it's assigned by calling doEvent for the script + * @param eventName + * @return + */ + 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; + } + + public void setAttributeNS( String namespaceURI, String qualifiedName, String value ) throws DOMException { + Attr attribute = getOwnerDocument().createAttributeNS( namespaceURI, qualifiedName ); + attribute.setValue( value ); + setAttributeNodeNS( attribute ); + } + + + public void removeAttribute( String name ) throws DOMException { + _attributes.remove( name ); + } + + + public Attr getAttributeNode( String name ) { + return (Attr) _attributes.get( name ); + } + + + public Attr setAttributeNode( Attr newAttr ) throws DOMException { + if (newAttr.getOwnerDocument() != getOwnerDocument()) throw new DOMException( DOMException.WRONG_DOCUMENT_ERR, "attribute must be from the same document as the element" ); + + ((AttrImpl) newAttr).setOwnerElement( this ); + AttrImpl oldAttr = (AttrImpl) _attributes.put( newAttr.getName(), newAttr ); + if (oldAttr != null) oldAttr.setOwnerElement( null ); + return oldAttr; + } + + + public Attr setAttributeNodeNS( Attr newAttr ) throws DOMException { + if (newAttr.getOwnerDocument() != getOwnerDocument()) throw new DOMException( DOMException.WRONG_DOCUMENT_ERR, "attribute must be from the same document as the element" ); + + ((AttrImpl) newAttr).setOwnerElement( this ); + AttrImpl oldAttr = (AttrImpl) _attributes.put( newAttr.getName(), newAttr ); + if (oldAttr != null) oldAttr.setOwnerElement( null ); + return oldAttr; + } + + + public Attr removeAttributeNode( Attr oldAttr ) throws DOMException { + if (!_attributes.containsValue( oldAttr)) throw new DOMException( DOMException.NOT_FOUND_ERR, "Specified attribute is not defined for this element" ); + + AttrImpl removedAttr = (AttrImpl) _attributes.remove( oldAttr.getName() ); + if (removedAttr != null) removedAttr.setOwnerElement( null ); + return removedAttr; + } + + + public boolean hasAttribute( String name ) { + return _attributes.containsKey( name ); + } + + + // ----------------------- namespaces are not supported at present -------------------------------- + + + public String getAttributeNS( String namespaceURI, String localName ) { + return null; + } + + + public void removeAttributeNS( String namespaceURI, String localName ) throws DOMException { + } + + + public Attr getAttributeNodeNS( String namespaceURI, String localName ) { + return null; + } + + + public NodeList getElementsByTagNameNS( String namespaceURI, String localName ) { + return null; + } + + + public boolean hasAttributeNS( String namespaceURI, String localName ) { + return false; + } + + + public static Element importNode( DocumentImpl document, Element original, boolean deep ) { + Element copy = document.createElementNS( original.getNamespaceURI(), original.getTagName() ); + NamedNodeMap attributes = original.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + copy.setAttributeNode( (Attr) document.importNode( attributes.item(i), false ) ); + } + if (deep) document.importChildren( original, copy ); + return copy; + } + + +//------------------------------------- DOM level 3 methods ------------------------------------------------------------ + + public TypeInfo getSchemaTypeInfo() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setIdAttribute( String name, boolean isId ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setIdAttributeNS( String namespaceURI, String localName, boolean isId ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setIdAttributeNode( Attr idAttr, boolean isId ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAnchorElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAnchorElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAnchorElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,188 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLAnchorElement; + +import java.net.URL; +import java.net.MalformedURLException; + +/** + * + * @author Russell Gold + **/ +public class HTMLAnchorElementImpl extends HTMLElementImpl implements HTMLAnchorElement { + + ElementImpl create() { + return new HTMLAnchorElementImpl(); + } + + + public String getCharset() { + return getAttributeWithNoDefault( "charset" ); + } + + + public String getHref() { + String relativeLocation = getAttributeWithNoDefault( "href" ); + if (relativeLocation.indexOf( ':' ) > 0 || relativeLocation.equals( "#" )) { + return relativeLocation; + } else { + try { + return new URL( ((HTMLDocumentImpl) getOwnerDocument()).getBaseUrl(), relativeLocation ).toExternalForm(); + } catch (MalformedURLException e) { + return e.toString(); + } + } + } + + + public String getHreflang() { + return getAttributeWithNoDefault( "hreflang" ); + } + + + public String getRel() { + return getAttributeWithNoDefault( "rel" ); + } + + + public String getRev() { + return getAttributeWithNoDefault( "rev" ); + } + + + public String getTarget() { + return getAttributeWithNoDefault( "target" ); + } + + + public String getType() { + return getAttributeWithNoDefault( "type" ); + } + + + public void setCharset( String charset ) { + setAttribute( "charset", charset ); + } + + + public void setHref( String href ) { + setAttribute( "href", href ); + } + + + public void setHreflang( String hreflang ) { + setAttribute( "hreflang", hreflang ); + } + + + public void setRel( String rel ) { + setAttribute( "rel", rel ); + } + + + public void setRev( String rev ) { + setAttribute( "rev", rev ); + } + + + public void setTarget( String target ) { + setAttribute( "target", target ); + } + + + public void setType( String type ) { + setAttribute( "type", type ); + } + + /** + * simulate blur + */ + public void blur() { + handleEvent("onblur"); + } + + /** + * simulate focus; + */ + public void focus() { + handleEvent("onfocus"); + } + + public String getAccessKey() { + return getAttributeWithNoDefault( "accesskey" ); + } + + + public String getCoords() { + return getAttributeWithNoDefault( "coords" ); + } + + + public String getName() { + return getAttributeWithNoDefault( "name" ); + } + + + public String getShape() { + return getAttributeWithNoDefault( "shape" ); + } + + + public int getTabIndex() { + return getIntegerAttribute( "tabindex" ); + } + + + public void setAccessKey( String accessKey ) { + setAttribute( "accesskey", accessKey ); + } + + + public void setCoords( String coords ) { + setAttribute( "coords", coords ); + } + + + public void setName( String name ) { + setAttribute( "name", name ); + } + + + public void setShape( String shape ) { + setAttribute( "shape", shape ); + } + + + public void setTabIndex( int tabIndex ) { + setAttribute( "tabindex", tabIndex ); + } + + + public void doClickAction() { + if (null == getHref() || getHref().startsWith( "#" )) return; + try { + ((HTMLDocumentImpl) getOwnerDocument()).getWindow().submitRequest( this, "GET", getHref(), getTarget(), new byte[0] ); + } catch (Exception e) { + throw new RuntimeException( "Error clicking link: " + e ); + } + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAppletElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAppletElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAppletElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,146 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLAppletElement; + +/** + * @author Russell Gold + */ +public class HTMLAppletElementImpl extends HTMLElementImpl implements HTMLAppletElement { + + ElementImpl create() { + return new HTMLAppletElementImpl(); + } + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public String getAlt() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setAlt( String alt ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getArchive() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setArchive( String archive ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getCode() { + return getAttributeWithNoDefault( "code" ); + } + + + public void setCode( String code ) { + setAttribute( "code", code ); + } + + + /** + * get the codebase of this applet + * modified for bug report [ 1895501 ] Handling no codebase attribute in APPLET tag + */ + public String getCodeBase() { + return getAttributeWithDefault( "codebase", "." ); + } + + + public void setCodeBase( String codeBase ) { + setAttribute( "codebase", codeBase ); + } + + + public String getHeight() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setHeight( String height ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getHspace() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setHspace( String hspace ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setName( String name ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getObject() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setObject( String object ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getVspace() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setVspace( String vspace ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getWidth() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setWidth( String width ) { + //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAreaElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAreaElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLAreaElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,120 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLAreaElement; + +import java.net.URL; +import java.net.MalformedURLException; + +/** + * + * @author Russell Gold + **/ +public class HTMLAreaElementImpl extends HTMLElementImpl implements HTMLAreaElement { + + ElementImpl create() { + return new HTMLAreaElementImpl(); + } + + + public String getHref() { + try { + return new URL( ((HTMLDocumentImpl) getOwnerDocument()).getWindow().getUrl(), getAttributeWithNoDefault( "href" ) ).toExternalForm(); + } catch (MalformedURLException e) { + return e.toString(); + } + } + + + public String getTarget() { + return getAttributeWithNoDefault( "target" ); + } + + + public void setHref( String href ) { + setAttribute( "href", href ); + } + + + public void setTarget( String target ) { + setAttribute( "target", target ); + } + + + public String getAccessKey() { + return getAttributeWithNoDefault( "accesskey" ); + } + + + public String getCoords() { + return getAttributeWithNoDefault( "coords" ); + } + + + public String getShape() { + return getAttributeWithNoDefault( "shape" ); + } + + + public int getTabIndex() { + return getIntegerAttribute( "tabindex" ); + } + + + public void setAccessKey( String accessKey ) { + setAttribute( "accesskey", accessKey ); + } + + + public void setCoords( String coords ) { + setAttribute( "coords", coords ); + } + + + public void setShape( String shape ) { + setAttribute( "shape", shape ); + } + + + public void setTabIndex( int tabIndex ) { + setAttribute( "tabindex", tabIndex ); + } + + + public String getAlt() { + return getAttributeWithNoDefault( "alt" ); + } + + + public boolean getNoHref() { + return getBooleanAttribute( "nohref" ); + } + + + public void setAlt( String alt ) { + setAttribute( "alt", alt ); + } + + + public void setNoHref( boolean noHref ) { + setAttribute( "nohref", noHref ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBaseElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBaseElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBaseElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,53 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLBaseElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLBaseElementImpl extends HTMLElementImpl implements HTMLBaseElement { + + ElementImpl create() { + return new HTMLBaseElementImpl(); + } + + + public String getHref() { + return getAttributeWithNoDefault( "href" ); + } + + + public String getTarget() { + return getAttributeWithNoDefault( "target" ); + } + + + public void setHref( String href ) { + setAttribute( "href", href ); + } + + + public void setTarget( String target ) { + setAttribute( "target", target ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBodyElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBodyElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLBodyElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,108 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLBodyElement; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.Scriptable; + +/** + * + * @author Russell Gold + **/ +public class HTMLBodyElementImpl extends HTMLElementImpl implements HTMLBodyElement { + + private HTMLEventHandler _onLoad = new HTMLEventHandler( this, "onload" ); + + ElementImpl create() { + return new HTMLBodyElementImpl(); + } + + /** + * + * @return the onload event + */ + public Function getOnloadEvent() { + if (getParentScope() == null && getOwnerDocument() instanceof Scriptable) + setParentScope( (Scriptable) getOwnerDocument() ); + return _onLoad.getHandler(); + } + +//----------------------------------------- HTMLBodyElement methods ---------------------------------------------------- + + public String getALink() { + return getAttributeWithNoDefault( "aLink" ); + } + + + public String getBackground() { + return getAttributeWithNoDefault( "background" ); + } + + + public String getBgColor() { + return getAttributeWithNoDefault( "bgColor" ); + } + + + public String getLink() { + return getAttributeWithNoDefault( "link" ); + } + + + public String getText() { + return getAttributeWithNoDefault( "text" ); + } + + + public String getVLink() { + return getAttributeWithNoDefault( "vLink" ); + } + + + public void setALink( String aLink ) { + setAttribute( "aLink", aLink ); + } + + + public void setBackground( String background ) { + setAttribute( "background", background ); + } + + + public void setBgColor( String bgColor ) { + setAttribute( "bgColor", bgColor ); + } + + + public void setLink( String link ) { + setAttribute( "link", link ); + } + + + public void setText( String text ) { + setAttribute( "text", text ); + } + + + public void setVLink( String vLink ) { + setAttribute( "vLink", vLink ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLButtonElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLButtonElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLButtonElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,58 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLButtonElement; + +/** + * @author Russell Gold + */ +public class HTMLButtonElementImpl extends HTMLControl implements HTMLButtonElement { + + + ElementImpl create() { + return new HTMLButtonElementImpl(); + } + + + public String getAccessKey() { + return getAttributeWithNoDefault( "accesskey" ); + } + + + public void setAccessKey( String accessKey ) { + setAttribute( "accesskey", accessKey ); + } + + + public String getValue() { + return getAttributeWithNoDefault( "value" ); + } + + + public void setValue( String value ) { + setAttribute( "value", value ); + } + + + public String getType() { + return getAttributeWithDefault( "type", "submit" ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLCollectionImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLCollectionImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLCollectionImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,96 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLFormElement; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.Scriptable; + +/** + * + * @author Russell Gold + **/ +public class HTMLCollectionImpl extends ScriptableObject implements HTMLCollection { + + private NodeList _list; + + public static HTMLCollectionImpl createHTMLCollectionImpl( NodeList list ) { + HTMLCollectionImpl htmlCollection = new HTMLCollectionImpl(); + htmlCollection.initialize( list ); + return htmlCollection; + } + + private void initialize( NodeList list ) { + _list = list; + } + +//------------------------------------------ HTMLCollection methods -------------------------------------------------- + + public int getLength() { + return _list.getLength(); + } + + + public Node item( int index ) { + return _list.item( index ); + } + + + public Node namedItem( String name ) { + if (name == null) return null; + + Node nodeByName = null; + for (int i = 0; null == nodeByName && i < getLength(); i++) { + Node node = item(i); + if (!(node instanceof HTMLElementImpl)) continue; + if (name.equalsIgnoreCase( ((HTMLElement) node).getId() )) return node; + if (name.equalsIgnoreCase( ((HTMLElementImpl) node).getAttributeWithNoDefault( "name" )) ) nodeByName = node; + } + return nodeByName; + } + +//------------------------------------------ ScriptableObject methods -------------------------------------------------- + + public String getClassName() { + return getClass().getName(); + } + + + public Object get( String propertyName, Scriptable scriptable ) { + Object result = super.get( propertyName, scriptable ); + if (result != NOT_FOUND) return result; + + Object namedProperty = ScriptingSupport.getNamedProperty( this, propertyName, scriptable ); + if (namedProperty != NOT_FOUND) return namedProperty; + + Node namedItem = namedItem( propertyName ); + return namedItem == null ? NOT_FOUND : namedItem; + } + + + public Object get( int index, Scriptable start ) { + if (index < 0 || index >= _list.getLength()) return NOT_FOUND; + return item( index ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerDelegate.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerDelegate.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerDelegate.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,103 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLCollection; +import org.w3c.dom.Node; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.meterware.httpunit.ParsedHTML; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * @author Russell Gold + */ +class HTMLContainerDelegate { + + private NodeImpl.IteratorMask _iteratorMask = NodeImpl.SKIP_IFRAMES; + + + HTMLContainerDelegate( NodeImpl.IteratorMask iteratorMask ) { + _iteratorMask = iteratorMask; + } + + + /** + * get Links for a given Node + * @param rootNode + * @return + */ + HTMLCollection getLinks( NodeImpl rootNode ) { + ArrayList elements = new ArrayList(); + for (Iterator each = rootNode.preOrderIteratorAfterNode( _iteratorMask ); each.hasNext();) { + Node node = (Node) each.next(); + if (node.getNodeType() != Node.ELEMENT_NODE) continue; + + if (ParsedHTML.isWebLink(node)) { + elements.add( node ); + } + } + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } + + + HTMLCollection getForms( NodeImpl rootNode ) { + ArrayList elements = new ArrayList(); + for (Iterator each = rootNode.preOrderIteratorAfterNode( _iteratorMask ); each.hasNext();) { + Node node = (Node) each.next(); + if (node.getNodeType() != Node.ELEMENT_NODE) continue; + + if ("form".equalsIgnoreCase( ((Element) node).getTagName() )) { + elements.add( node ); + } + } + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } + + + HTMLCollection getAnchors( NodeImpl rootNode ) { + NodeList nodeList = rootNode.getElementsByTagName( "A" ); + ArrayList elements = new ArrayList(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item( i ); + if (node.getAttributes().getNamedItem( "name" ) != null) { + elements.add( node ); + } + } + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } + + + HTMLCollection getImages( NodeImpl rootNode ) { + ArrayList elements = new ArrayList(); + rootNode.appendElementsWithTags( new String[] {"img"}, elements ); + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } + + + HTMLCollection getApplets( NodeImpl rootNode ) { + ArrayList elements = new ArrayList(); + rootNode.appendElementsWithTags( new String[] {"applet"}, elements ); + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerElement.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerElement.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLContainerElement.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,42 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLCollection; + +/** + * @author Russell Gold + */ +public interface HTMLContainerElement { + + HTMLCollection getLinks(); + + + HTMLCollection getImages(); + + + HTMLCollection getApplets(); + + + HTMLCollection getForms(); + + + HTMLCollection getAnchors(); +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLControl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLControl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLControl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,117 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.Node; +import org.w3c.dom.html.HTMLFormElement; +import org.w3c.dom.html.HTMLCollection; + +import java.util.Iterator; +import java.io.IOException; + +import com.meterware.httpunit.protocol.ParameterProcessor; + +/** + * + * @author Russell Gold + **/ +public class HTMLControl extends HTMLElementImpl { + + public boolean getDisabled() { + return getBooleanAttribute( "disabled" ); + } + + + public HTMLFormElement getForm() { + Node parent = getParentNode(); + while (parent != null && !("form".equalsIgnoreCase( parent.getNodeName() ))) parent = parent.getParentNode(); + if (parent != null) return (HTMLFormElement) parent; + + for (Iterator here = preOrderIterator(); here.hasNext();) { + Object o = here.next(); + if (o instanceof HTMLFormElement) return getPreviousForm( (HTMLFormElement) o ); + } + return getLastFormInDocument(); + } + + + private HTMLFormElement getPreviousForm( HTMLFormElement nextForm ) { + HTMLCollection forms = getHtmlDocument().getForms(); + for (int i = 0; i < forms.getLength(); i++) { + if (nextForm == forms.item( i )) return i == 0 ? null : (HTMLFormElement) forms.item( i-1 ); + } + return null; + } + + + private HTMLFormElement getLastFormInDocument() { + HTMLCollection forms = getHtmlDocument().getForms(); + return forms.getLength() == 0 ? null : (HTMLFormElement) forms.item( forms.getLength()-1 ); + } + + + public String getName() { + return getAttributeWithNoDefault( "name" ); + } + + + public boolean getReadOnly() { + return getBooleanAttribute( "readonly" ); + } + + + public int getTabIndex() { + return getIntegerAttribute( "tabindex" ); + } + + + public String getType() { + return getAttributeWithDefault( "type", "text" ); + } + + + public void setDisabled( boolean disabled ) { + setAttribute( "disabled", disabled ); + } + + + public void setName( String name ) { + setAttribute( "name", name ); + } + + + public void setReadOnly( boolean readOnly ) { + setAttribute( "readonly", readOnly ); + } + + + public void setTabIndex( int tabIndex ) { + setAttribute( "tabindex", tabIndex ); + } + + + public void reset() {} + + + void addValues( ParameterProcessor processor, String characterSet ) throws IOException {} + + + public void silenceSubmitButton() {} +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLDocumentImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLDocumentImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLDocumentImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,348 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.*; +import org.w3c.dom.*; +import org.w3c.dom.Node; +import org.mozilla.javascript.*; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.ArrayList; +import java.net.URL; +import java.net.MalformedURLException; + +/** + * + * @author Russell Gold + **/ +public class HTMLDocumentImpl extends DocumentImpl implements HTMLDocument, HTMLContainerElement { + + private static Hashtable _exemplars = new Hashtable(); + private DomWindow _window; + private StringBuffer _writeBuffer; + private HTMLContainerDelegate _containerDelegate = new HTMLContainerDelegate( SKIP_IFRAMES ); + + + public void setIFramesEnabled( boolean enabled ) { + _containerDelegate = new HTMLContainerDelegate( enabled ? SKIP_IFRAMES : null ); + } + + + public Object get( String propertyName, Scriptable scriptable ) { + if (propertyName.equals( "document" )) return this; + + Object result = super.get( propertyName, scriptable ); + if (result != NOT_FOUND) return result; + + Element element = getElementById( propertyName ); + if (element != null) return element; + + NodeList elements = getElementsByName( propertyName ); + if (elements.getLength() >= 1) return elements.item( 0 ); + + return ScriptingSupport.getNamedProperty( this, getJavaPropertyName( propertyName ), scriptable ); + } + + + public void put( String propertyName, Scriptable initialObject, Object value ) { + ScriptingSupport.setNamedProperty( this, getJavaPropertyName( propertyName ), value ); + } + + +//------------------------------------------ HTMLContainerElement methods ---------------------------------------------- + + + public HTMLCollection getLinks() { + return _containerDelegate.getLinks( this ); + } + + + public HTMLCollection getImages() { + return _containerDelegate.getImages( this ); + } + + + public HTMLCollection getApplets() { + return _containerDelegate.getApplets( this ); + } + + + public HTMLCollection getForms() { + return _containerDelegate.getForms( this ); + } + + + public HTMLCollection getAnchors() { + return _containerDelegate.getAnchors( this ); + } + + +//-------------------------------------------- HTMLDocument methods ---------------------------------------------------- + + + public String getTitle() { + HTMLTitleElement result = getTitleElement(); + return result == null ? "" : result.getText(); + } + + + private HTMLTitleElement getTitleElement() { + HTMLTitleElement result = null; + NodeList titleNodes = getElementsByTagName( "title" ); + for (int i = 0; i < titleNodes.getLength(); i++) { + Node node = titleNodes.item( i ); + if (node instanceof HTMLTitleElement) { + result = ((HTMLTitleElement) node); + } + } + return result; + } + + + private HTMLHeadElement getHeadElement() { + NodeList headNodes = getElementsByTagName( "head" ); + for (int i = 0; i < headNodes.getLength(); i++) { + Node node = headNodes.item( i ); + if (node instanceof HTMLHeadElement) { + return ((HTMLHeadElement) node); + } + } + + HTMLHeadElement head = (HTMLHeadElement) createElement( "head" ); + getHtmlElement().appendChild( head ); + return head; + } + + + private HTMLHtmlElement getHtmlElement() { + NodeList htmlNodes = getElementsByTagName( "html" ); + for (int i = 0; i < htmlNodes.getLength(); i++) { + Node node = htmlNodes.item( i ); + if (node instanceof HTMLHtmlElement) { + return ((HTMLHtmlElement) node); + } + } + + HTMLHtmlElement html = (HTMLHtmlElement) createElement( "html" ); + appendChild( html ); + return html; + } + + + public void setTitle( String title ) { + HTMLTitleElement titleElement = getTitleElement(); + if (titleElement != null) { + titleElement.setText( title ); + } else { + titleElement = (HTMLTitleElement) createElement( "title" ); + titleElement.setText( title ); + getHeadElement().appendChild( titleElement ); + } + } + + + public String getReferrer() { + return null; + } + + + public String getDomain() { + return null; + } + + + public String getURL() { + return null; + } + + + public HTMLElement getBody() { + NodeList bodyNodes = getElementsByTagName( "body" ); + for (int i = 0; i < bodyNodes.getLength(); i++) { + Node node = bodyNodes.item( i ); + if (node instanceof HTMLBodyElement) { + return ((HTMLBodyElement) node); + } + } + return null; + } + + + public void setBody( HTMLElement body ) { + getHtmlElement().appendChild( body ); + } + + + public String getCookie() { + return null; + } + + + public void setCookie( String cookie ) { + } + + + public void open() { + } + + + public void close() { + if (getWindow().replaceText( getWriteBuffer().toString(), getMimeType()) ) clearWriteBuffer(); + } + + + private String getMimeType() { + return "text/html"; + } + + + public void write( String text ) { + getWriteBuffer().append( text ); + } + + + public void writeln( String text ) { + getWriteBuffer().append( text ).append( (char) 0x0d ).append( (char) 0x0a ); + } + + + public NodeList getElementsByName( String elementName ) { + ArrayList elements = new ArrayList(); + for (Iterator each = preOrderIterator(); each.hasNext();) { + Node node = (Node) each.next(); + if (!(node instanceof HTMLElementImpl)) continue; + HTMLElementImpl element = (HTMLElementImpl) node; + if (elementName.equals( element.getAttributeWithNoDefault( "name" ) )) elements.add( element ); + } + return new NodeListImpl( elements ); + } + + + public Element createElement( String tagName ) throws DOMException { + ElementImpl element = getExemplar( tagName ).create(); + element.initialize( this, toNodeCase( tagName ) ); + return element; + } + + + public Element createElementNS( String namespaceURI, String qualifiedName ) throws DOMException { + ElementImpl element = getExemplar( qualifiedName ).create(); + element.initialize( this, namespaceURI, toNodeCase( qualifiedName ) ); + return element; + } + + + public NodeList getElementsByTagName( String name ) { + return super.getElementsByTagName( toNodeCase( name ) ); + } + + + public Node cloneNode( boolean deep ) { + HTMLDocumentImpl copy = new HTMLDocumentImpl(); + if (deep) copy.importChildren( this, copy ); + return copy; + } + + + private static HTMLElementImpl getExemplar( String tagName ) { + HTMLElementImpl impl = (HTMLElementImpl) _exemplars.get( tagName.toLowerCase() ); + if (impl == null) impl = new HTMLElementImpl(); + return impl; + } + + + String toNodeCase( String nodeName ) { + return nodeName.toUpperCase(); + } + + + HTMLContainerDelegate getContainerDelegate() { + return _containerDelegate; + } + + + static { + _exemplars.put( "html", new HTMLHtmlElementImpl() ); + _exemplars.put( "head", new HTMLHeadElementImpl() ); + _exemplars.put( "link", new HTMLLinkElementImpl() ); + _exemplars.put( "title", new HTMLTitleElementImpl() ); + _exemplars.put( "meta", new HTMLMetaElementImpl() ); + _exemplars.put( "base", new HTMLBaseElementImpl() ); + _exemplars.put( "style", new HTMLStyleElementImpl() ); + _exemplars.put( "body", new HTMLBodyElementImpl() ); + _exemplars.put( "form", new HTMLFormElementImpl() ); + _exemplars.put( "select", new HTMLSelectElementImpl() ); + _exemplars.put( "option", new HTMLOptionElementImpl() ); + _exemplars.put( "input", new HTMLInputElementImpl() ); + _exemplars.put( "button", new HTMLButtonElementImpl() ); + _exemplars.put( "textarea", new HTMLTextAreaElementImpl() ); + _exemplars.put( "a", new HTMLAnchorElementImpl() ); + _exemplars.put( "area", new HTMLAreaElementImpl() ); + _exemplars.put( "img", new HTMLImageElementImpl() ); + _exemplars.put( "td", new HTMLTableCellElementImpl() ); + _exemplars.put( "th", new HTMLTableCellElementImpl() ); + _exemplars.put( "tr", new HTMLTableRowElementImpl() ); + _exemplars.put( "table", new HTMLTableElementImpl() ); + _exemplars.put( "p", new HTMLParagraphElementImpl() ); + _exemplars.put( "iframe", new HTMLIFrameElementImpl() ); + _exemplars.put( "applet", new HTMLAppletElementImpl() ); + } + + + /** + * get the Window + * @return the window + */ + public DomWindow getWindow() { + // if there is now window yet + if (_window == null) { + // create a window for this document + _window = new DomWindow( this ); + setParentScope( _window ); + } + return _window; + } + + + StringBuffer getWriteBuffer() { + if (_writeBuffer == null) _writeBuffer = new StringBuffer(); + return _writeBuffer; + } + + + public void clearWriteBuffer() { + _writeBuffer = null; + } + + + URL getBaseUrl() { + NodeList list = getElementsByTagName( "base" ); + if (list.getLength() == 0) return getWindow().getUrl(); + + HTMLBaseElement base = (HTMLBaseElement) list.item( 0 ); + try { + return new URL( getWindow().getUrl(), base.getHref() ); + } catch (MalformedURLException e) { + return getWindow().getUrl(); + } + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,150 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLElement; +import org.w3c.dom.NodeList; +import org.w3c.dom.Attr; + + +/** + * @author Russell Gold + */ +public class HTMLElementImpl extends ElementImpl implements HTMLElement { + + + public final static String UNSPECIFIED_ATTRIBUTE = null; + + + ElementImpl create() { + return new HTMLElementImpl(); + } + + + public void click() { + doClickAction(); + } + + + public void doClickAction() {} + + + public String getId() { + return getAttributeWithNoDefault( "id" ); + } + + + public void setId( String id ) { + setAttribute( "id", id ); + } + + + public String getTitle() { + return getAttributeWithNoDefault( "title" ); + } + + + public void setTitle( String title ) { + setAttribute( "title", title ); + } + + + public String getLang() { + return getAttributeWithNoDefault( "lang" ); + } + + + public void setLang( String lang ) { + setAttribute( "lang", lang ); + } + + + public String getDir() { + return getAttributeWithNoDefault( "dir" ); + } + + + public void setDir( String dir ) { + setAttribute( "dir", dir ); + } + + + public String getClassName() { + return getAttributeWithNoDefault( "class" ); + } + + + public void setClassName( String className ) { + setAttribute( "class", className ); + } + + + public NodeList getElementsByTagName( String name ) { + return super.getElementsByTagName( ((HTMLDocumentImpl) getOwnerDocument()).toNodeCase( name ) ); + } + +//---------------------------------------------- protected methods ----------------------------------------------------- + + final protected String getAttributeWithDefault( String attributeName, String defaultValue ) { + if (hasAttribute( attributeName )) return getAttribute( attributeName ); + return defaultValue; + } + + + final protected String getAttributeWithNoDefault( String attributeName ) { + if (hasAttribute( attributeName )) return getAttribute( attributeName ); + return UNSPECIFIED_ATTRIBUTE; + } + + + protected boolean getBooleanAttribute( String name ) { + Attr attr = getAttributeNode( name ); + return attr != null && !attr.getValue().equalsIgnoreCase( "false" ); + } + + + protected int getIntegerAttribute( String name ) { + String value = getAttribute( name ); + return value.length() == 0 ? 0 : Integer.parseInt( value ); + } + + + protected int getIntegerAttribute( String name, int defaultValue ) { + String value = getAttribute( name ); + return value.length() == 0 ? defaultValue : Integer.parseInt( value ); + } + + + protected void setAttribute( String name, boolean disabled ) { + setAttribute( name, disabled ? "true" : "false" ); + } + + + protected void setAttribute( String name, int value ) { + setAttribute( name, Integer.toString( value ) ); + } + + + HTMLDocumentImpl getHtmlDocument() { + return (HTMLDocumentImpl) getOwnerDocument(); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLEventHandler.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLEventHandler.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLEventHandler.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,71 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Header$ + * + * Copyright (c) 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 org.mozilla.javascript.Function; +import org.mozilla.javascript.Context; + +/** + * the handler for HTML events + * @author Russell Gold + */ +class HTMLEventHandler { + + private HTMLElementImpl _baseElement; + private String _handlerName; + + private Function _handler; + + + /** + * create a handler for the given HTML Event + * @param baseElement + * @param handlerName + */ + public HTMLEventHandler( HTMLElementImpl baseElement, String handlerName ) { + _baseElement = baseElement; + _handlerName = handlerName; + } + + + /** + * set the handler Function for this event Handler + * @param handler + */ + void setHandler( Function handler ) { + _handler = handler; + } + + + /** + * get the (cached) handler Function for this event Handler + * on first access compile the function + * @return + */ + Function getHandler() { + if (_handler == null) { + String attribute = _baseElement.getAttributeWithNoDefault( _handlerName ); + if (attribute != null && Context.getCurrentContext() != null) { + _handler = Context.getCurrentContext().compileFunction( _baseElement, "function " + AbstractDomComponent.createAnonymousFunctionName() + "() { " + attribute + "}", "httpunit", 0, null ); + } + } + return _handler; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLFormElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLFormElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLFormElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,227 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLFormElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Element; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; + +import java.util.ArrayList; +import java.util.Iterator; +import java.net.URL; +import java.io.IOException; + +import com.meterware.httpunit.scripting.FormScriptable; +import com.meterware.httpunit.protocol.URLEncodedString; + +/** + * + * @author Russell Gold + **/ +public class HTMLFormElementImpl extends HTMLElementImpl implements HTMLFormElement, FormScriptable { + + + ElementImpl create() { + return new HTMLFormElementImpl(); + } + + + //------------------------------- ScriptableObject methods ---------------------------------------------------------- + + + public Object get( String propertyName, Scriptable scriptable ) { + HTMLCollection elements = getElements(); + for (int i=0; i < elements.getLength(); i++) { + Node node = elements.item( i ); + NamedNodeMap attributes = node.getAttributes(); + AttrImpl nameAttribute = (AttrImpl) attributes.getNamedItem( "name" ); + if (nameAttribute != null && propertyName.equals( nameAttribute.getValue() )) return node; + AttrImpl idAttribute = (AttrImpl) attributes.getNamedItem( "id" ); + if (idAttribute != null && propertyName.equals( idAttribute.getValue() )) return node; + } + return super.get( propertyName, scriptable ); + } + + //------------------------------- HTMLFormElement methods ---------------------------------------------------------- + + + public String getAcceptCharset() { + return getAttributeWithDefault( "accept-charset", "UNKNOWN" ); + } + + + public void setAcceptCharset( String acceptCharset ) { + setAttribute( "accept-charset", acceptCharset ); + } + + + public String getAction() { + return getAttribute( "action" ); + } + + + public void setAction( String action ) { + setAttribute( "action", action ); + } + + + public void setParameterValue( String name, String value ) { + Object control = get( name, null ); + if (control instanceof ScriptableObject) ((ScriptableObject) control).put( "value", this, value ); + } + + + public String getEnctype() { + return getAttributeWithDefault( "enctype", "application/x-www-form-urlencoded" ); + } + + + public void setEnctype( String enctype ) { + setAttribute( "enctype", enctype ); + } + + + public String getMethod() { + return getAttributeWithDefault( "method", "get" ); + } + + + public void setMethod( String method ) { + setAttribute( "method", method ); + } + + + /** + * getter for the name + * @see org.w3c.dom.html.HTMLFormElement#getName() + */ + public String getName() { + String result=getAttributeWithNoDefault( "name" ); + if (result==null) + result=this.getId(); + return result; + } + + + public void setName( String name ) { + setAttribute( "name", name ); + } + + + public String getTarget() { + return getAttributeWithNoDefault( "target" ); + } + + + public void setTarget( String target ) { + setAttribute( "target", target ); + } + + + public HTMLCollection getElements() { + ArrayList elements = new ArrayList(); + String[] names = new String[]{"INPUT", "TEXTAREA", "BUTTON", "SELECT"}; + for (Iterator each = preOrderIteratorAfterNode(); each.hasNext();) { + Node node = (Node) each.next(); + if (node instanceof HTMLFormElement) break; + + if (node.getNodeType() != ELEMENT_NODE) continue; + String tagName = ((Element) node).getTagName(); + for (int i = 0; i < names.length; i++) { + if (tagName.equalsIgnoreCase( names[i] )) elements.add( node ); + } + } + return HTMLCollectionImpl.createHTMLCollectionImpl( new NodeListImpl( elements ) ); + } + + + public int getLength() { + return 0; + } + + + public void reset() { + HTMLCollection elements = getElements(); + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node instanceof HTMLControl) ((HTMLControl) node).reset(); + } + } + + + public void submit() { + doSubmitAction(); + } + + + /** + * Handles the actual form submission - does not handle the "submit" event. + */ + void doSubmitAction() { + try { + if ("get".equalsIgnoreCase( getMethod() )) { + getDomWindow().submitRequest( this, getMethod(), getEffectiveUrl(), getTarget(), new byte[0] ); + } else if ("post".equalsIgnoreCase( getMethod() )) { + getDomWindow().submitRequest( this, getMethod(), getAction(), getTarget(), new byte[0] ); + } + } catch (Exception e) { + throw new RuntimeException( "Error submitting form: " + e ); + } finally { + silenceSubmitButtons(); + } + } + + + private void silenceSubmitButtons() { + HTMLCollection controls = getElements(); + for (int i = 0; i < controls.getLength(); i++) { + ((HTMLControl) controls.item( i )).silenceSubmitButton(); + } + } + + + private String getEffectiveUrl() throws IOException { + StringBuffer spec = new StringBuffer( getAction() ); + if ("get".equalsIgnoreCase( getMethod() )) { + URLEncodedString parameters = new URLEncodedString(); + HTMLCollection controls = getElements(); + for (int i = 0; i < controls.getLength(); i++) { + ((HTMLControl) controls.item( i )).addValues( parameters, "us-ascii" ); + } + if ((spec.indexOf( "?" ) >= 0) && !(spec.toString().endsWith( "?" ))) { + spec.append( '&' ); + } else { + spec.append( '?' ); + } + spec.append( parameters.getString() ); + } + return new URL( getDomWindow().getUrl(), spec.toString() ).toExternalForm(); + } + + + private DomWindow getDomWindow() { + return ((HTMLDocumentImpl) getOwnerDocument()).getWindow(); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHeadElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHeadElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHeadElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,44 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLHeadElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLHeadElementImpl extends HTMLElementImpl implements HTMLHeadElement { + + ElementImpl create() { + return new HTMLHeadElementImpl(); + } + + + public String getProfile() { + return getAttributeWithNoDefault( "profile" ); + } + + + public void setProfile( String profile ) { + setAttribute( "profile", profile ); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHtmlElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHtmlElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLHtmlElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,45 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLHtmlElement; + + +/** + * + * @author Russell Gold + **/ +public class HTMLHtmlElementImpl extends HTMLElementImpl implements HTMLHtmlElement { + + ElementImpl create() { + return new HTMLHtmlElementImpl(); + } + + + public String getVersion() { + return getAttributeWithNoDefault( "version" ); + } + + + public void setVersion( String version ) { + setAttribute( "version", version ); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLIFrameElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLIFrameElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLIFrameElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,138 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLIFrameElement; +import org.w3c.dom.Document; + +/** + * @author Russell Gold + */ +public class HTMLIFrameElementImpl extends HTMLElementImpl implements HTMLIFrameElement { + + ElementImpl create() { + return new HTMLIFrameElementImpl(); + } + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public String getFrameBorder() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setFrameBorder( String frameBorder ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getHeight() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setHeight( String height ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getLongDesc() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setLongDesc( String longDesc ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getMarginHeight() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setMarginHeight( String marginHeight ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getMarginWidth() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setMarginWidth( String marginWidth ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setName( String name ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getScrolling() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setScrolling( String scrolling ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getSrc() { + return getAttributeWithNoDefault( "src" ); + } + + + public void setSrc( String src ) { + setAttribute( "src", src ); + } + + + public String getWidth() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setWidth( String width ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public Document getContentDocument() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLImageElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLImageElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLImageElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,162 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLImageElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLImageElementImpl extends HTMLElementImpl implements HTMLImageElement { + + ElementImpl create() { + return new HTMLImageElementImpl(); + } + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public String getAlt() { + return getAttributeWithNoDefault( "alt" ); + } + + + public String getBorder() { + return getAttributeWithNoDefault( "border" ); + } + + + public String getHeight() { + return getAttributeWithNoDefault( "height" ); + } + + + public String getHspace() { + return getAttributeWithNoDefault( "hspace" ); + } + + + public boolean getIsMap() { + return getBooleanAttribute( "ismap" ); + } + + + public String getLongDesc() { + return getAttributeWithNoDefault( "longdesc" ); + } + + + public String getLowSrc() { + return null; + } + + + public String getName() { + return getAttributeWithNoDefault( "name" ); + } + + + public String getSrc() { + return getAttributeWithNoDefault( "src" ); + } + + + public String getUseMap() { + return getAttributeWithNoDefault( "usemap" ); + } + + + public String getVspace() { + return getAttributeWithNoDefault( "vspace" ); + } + + + public String getWidth() { + return getAttributeWithNoDefault( "width" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public void setAlt( String alt ) { + setAttribute( "alt", alt ); + } + + + public void setBorder( String border ) { + setAttribute( "border", border ); + } + + + public void setHeight( String height ) { + setAttribute( "height", height ); + } + + + public void setHspace( String hspace ) { + setAttribute( "hspace", hspace ); + } + + + public void setIsMap( boolean isMap ) { + setAttribute( "ismap", isMap ); + } + + + public void setLongDesc( String longDesc ) { + setAttribute( "longdesc", longDesc ); + } + + + public void setLowSrc( String lowSrc ) { + } + + + public void setName( String name ) { + setAttribute( "name", name ); + } + + + public void setSrc( String src ) { + setAttribute( "src", src ); + } + + + public void setUseMap( String useMap ) { + setAttribute( "usemap", useMap ); + } + + + public void setVspace( String vspace ) { + setAttribute( "vspace", vspace ); + } + + + public void setWidth( String width ) { + setAttribute( "width", width ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLInputElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLInputElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLInputElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,418 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLInputElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import com.meterware.httpunit.protocol.ParameterProcessor; + +import java.io.IOException; + +/** + * + * @author Russell Gold + **/ +public class HTMLInputElementImpl extends HTMLControl implements HTMLInputElement { + + private String _value; + private Boolean _checked; + private TypeSpecificBehavior _behavior; + + ElementImpl create() { + return new HTMLInputElementImpl(); + } + + + /** + * simulate blur + */ + public void blur() { + handleEvent("onblur"); + } + + + /** + * simulate focus; + */ + public void focus() { + handleEvent("onfocus"); + } + + + public void doClickAction() { + getBehavior().click(); + } + + + public void select() { + } + + + public String getAccept() { + return getAttributeWithNoDefault( "accept" ); + } + + + public String getAccessKey() { + return getAttributeWithNoDefault( "accessKey" ); + } + + + public String getAlign() { + return getAttributeWithDefault( "align", "bottom" ); + } + + + public String getAlt() { + return getAttributeWithNoDefault( "alt" ); + } + + + public boolean getChecked() { + return getBehavior().getChecked(); + } + + + public boolean getDefaultChecked() { + return getBooleanAttribute( "checked" ); + } + + + public String getDefaultValue() { + return getAttributeWithNoDefault( "value" ); + } + + + public int getMaxLength() { + return getIntegerAttribute( "maxlength" ); + } + + + public String getSize() { + return getAttributeWithNoDefault( "size" ); + } + + + public String getSrc() { + return getAttributeWithNoDefault( "src" ); + } + + + public String getUseMap() { + return getAttributeWithNoDefault( "useMap" ); + } + + + public void setAccept( String accept ) { + setAttribute( "accept", accept ); + } + + + public void setAccessKey( String accessKey ) { + setAttribute( "accessKey", accessKey ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public void setAlt( String alt ) { + setAttribute( "alt", alt ); + } + + + public void setChecked( boolean checked ) { + getBehavior().setChecked( checked ); + } + + + public void setDefaultChecked( boolean defaultChecked ) { + setAttribute( "checked", defaultChecked ); + } + + + public void setDefaultValue( String defaultValue ) { + setAttribute( "value", defaultValue ); + } + + + public void setMaxLength( int maxLength ) { + setAttribute( "maxlength", maxLength ); + } + + + public void setSize( String size ) { + setAttribute( "size", size ); + } + + + public void setSrc( String src ) { + setAttribute( "src", src ); + } + + + public void setUseMap( String useMap ) { + setAttribute( "useMap", useMap ); + } + + + public String getValue() { + return getBehavior().getValue(); + } + + + public void setValue( String value ) { + getBehavior().setValue( value ); + } + + + public void reset() { + getBehavior().reset(); + } + + + public void setAttribute( String name, String value ) throws DOMException { + super.setAttribute( name, value ); + if (name.equalsIgnoreCase( "type" )) selectBehavior( getType().toLowerCase() ); + } + + + void addValues( ParameterProcessor processor, String characterSet ) throws IOException { + getBehavior().addValues( getName(), processor, characterSet ); + } + + + public void silenceSubmitButton() { + getBehavior().silenceSubmitButton(); + } + + + void setState( boolean checked ) { + _checked = checked ? Boolean.TRUE : Boolean.FALSE; + } + + + static boolean equals( String s1, String s2 ) { + return s1 == null ? s2 == null : s1.equals( s2 ); + } + + + private void selectBehavior( String type ) { + if (type == null || type.equals( "text") || type.equals( "password" ) || type.equals( "hidden" )) { + _behavior = new EditableTextBehavior( this ); + } else if (type.equals( "checkbox" )) { + _behavior = new CheckboxBehavior( this ); + } else if (type.equals( "radio" )) { + _behavior = new RadioButtonBehavior( this ); + } else if (type.equals( "reset" )) { + _behavior = new ResetButtonBehavior( this ); + } else if (type.equals( "submit" )) { + _behavior = new SubmitButtonBehavior( this ); + } else { + _behavior = new DefaultBehavior( this ); + } + } + + + private TypeSpecificBehavior getBehavior() { + if (_behavior == null) selectBehavior( getType().toLowerCase() ); + return _behavior; + } + + + interface TypeSpecificBehavior { + void setValue( String value ); + String getValue(); + + void reset(); + void click(); + + boolean getChecked(); + void setChecked( boolean checked ); + + + void addValues( String name, ParameterProcessor processor, String characterSet ) throws IOException; + + + void silenceSubmitButton(); + } + + + class DefaultBehavior implements TypeSpecificBehavior { + + private HTMLElementImpl _element; + + public DefaultBehavior( HTMLElementImpl element ) { + _element = element; + } + + + public String getValue() { + return _value != null ? _value : getDefaultValue(); + } + + public void setValue( String value ) { + if (HTMLInputElementImpl.equals( value, _value )) return; + + _value = value; + reportPropertyChanged( "value" ); + } + + + public boolean getChecked() { + return getDefaultChecked(); + } + + public void setChecked( boolean checked ) {} + + public void reset() {} + + public void click() {} + + protected void reportPropertyChanged( String propertyName ) { + _element.reportPropertyChanged( propertyName ); + } + + public void addValues( String name, ParameterProcessor processor, String characterSet ) throws IOException { + processor.addParameter( name, getValue(), characterSet ); + } + + public void silenceSubmitButton() {} + } + + + class EditableTextBehavior extends DefaultBehavior { + + public EditableTextBehavior( HTMLElementImpl element ) { + super( element ); + } + + public void reset() { + _value = null; + } + + } + + + class SubmitButtonBehavior extends DefaultBehavior { + + private boolean _sendWithSubmit; + + public SubmitButtonBehavior( HTMLElementImpl element ) { + super( element ); + } + + public void click() { + _sendWithSubmit = true; + ((HTMLFormElementImpl) getForm()).doSubmitAction(); + } + + public void addValues( String name, ParameterProcessor processor, String characterSet ) throws IOException { + if (!_sendWithSubmit) return; + super.addValues( name, processor, characterSet ); + } + + public void silenceSubmitButton() { + _sendWithSubmit = false; + } + + } + + + class CheckboxBehavior extends DefaultBehavior { + + public CheckboxBehavior( HTMLElementImpl element ) { + super( element ); + } + + public boolean getChecked() { + return _checked != null ? _checked.booleanValue() : getDefaultChecked(); + } + + public void setChecked( boolean checked ) { + setState( checked ); + } + + public void reset() { + _checked = null; + } + + + public void click() { + setChecked( !getChecked() ); + } + + + public void addValues( String name, ParameterProcessor processor, String characterSet ) throws IOException { + if (!getDisabled() && getChecked()) processor.addParameter( name, getFormValue(), characterSet ); + } + + + private String getFormValue() { + return _value == null ? "on" : _value; + } + } + + + class RadioButtonBehavior extends CheckboxBehavior { + + public RadioButtonBehavior( HTMLElementImpl element ) { + super( element ); + } + + + public void setChecked( boolean checked ) { + if (checked) { + HTMLCollection elements = getForm().getElements(); + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (!(node instanceof HTMLInputElementImpl)) continue; + HTMLInputElementImpl input = (HTMLInputElementImpl) node; + if (getName().equals( input.getName() ) && input.getType().equalsIgnoreCase( "radio" )) input.setState( false ); + } + } + setState( checked ); + } + + + public void click() { + setChecked( true ); + } + } + + + class ResetButtonBehavior extends DefaultBehavior { + + public ResetButtonBehavior( HTMLElementImpl element ) { + super( element ); + } + + + public void click() { + getForm().reset(); + } + + } + + } Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLLinkElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLLinkElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLLinkElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,124 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.html.HTMLLinkElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLLinkElementImpl extends HTMLElementImpl implements HTMLLinkElement { + + ElementImpl create() { + return new HTMLLinkElementImpl(); + } + + + public String getCharset() { + return getAttributeWithNoDefault( "charset" ); + } + + + public boolean getDisabled() { + return getBooleanAttribute( "disabled" ); + } + + + public String getHref() { + return getAttributeWithNoDefault( "href" ); + } + + + public String getHreflang() { + return getAttributeWithNoDefault( "hreflang" ); + } + + + public String getMedia() { + return getAttributeWithDefault( "media", "screen" ); + } + + + public String getRel() { + return getAttributeWithNoDefault( "rel" ); + } + + + public String getRev() { + return getAttributeWithNoDefault( "rev" ); + } + + + public String getTarget() { + return getAttributeWithNoDefault( "target" ); + } + + + public String getType() { + return getAttributeWithNoDefault( "type" ); + } + + + public void setCharset( String charset ) { + setAttribute( "charset", charset ); + } + + + public void setDisabled( boolean disabled ) { + setAttribute( "disabled", disabled ); + } + + + public void setHref( String href ) { + setAttribute( "href", href ); + } + + + public void setHreflang( String hreflang ) { + setAttribute( "hreflang", hreflang ); + } + + + public void setMedia( String media ) { + setAttribute( "media", media ); + } + + + public void setRel( String rel ) { + setAttribute( "rel", rel ); + } + + + public void setRev( String rev ) { + setAttribute( "rev", rev ); + } + + + public void setTarget( String target ) { + setAttribute( "target", target ); + } + + + public void setType( String type ) { + setAttribute( "type", type ); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLMetaElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLMetaElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLMetaElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,73 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLMetaElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLMetaElementImpl extends HTMLElementImpl implements HTMLMetaElement { + + ElementImpl create() { + return new HTMLMetaElementImpl(); + } + + + public String getContent() { + return getAttributeWithNoDefault( "content" ); + } + + + public String getHttpEquiv() { + return getAttributeWithNoDefault( "http-equiv" ); + } + + + public String getName() { + return getAttributeWithNoDefault( "name" ); + } + + + public String getScheme() { + return getAttributeWithNoDefault( "scheme" ); + } + + + public void setContent( String content ) { + setAttribute( "content", content ); + } + + + public void setHttpEquiv( String httpEquiv ) { + setAttribute( "http-equiv", httpEquiv ); + } + + + public void setName( String name ) { + setAttribute( "name", name ); + } + + + public void setScheme( String scheme ) { + setAttribute( "scheme", scheme ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLOptionElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLOptionElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLOptionElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,121 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLOptionElement; +import org.w3c.dom.Node; +import com.meterware.httpunit.protocol.ParameterProcessor; + +import java.io.IOException; + +/** + * + * @author Russell Gold + **/ +public class HTMLOptionElementImpl extends HTMLControl implements HTMLOptionElement { + + private Boolean _selected; + + ElementImpl create() { + return new HTMLOptionElementImpl(); + } + + + public boolean getDefaultSelected() { + return getBooleanAttribute( "selected" ); + } + + + public int getIndex() { + return getSelect().getIndexOf( this ); + } + + + public void setIndex( int i ) {}; // obsolete - required for compatibility with JDK 1.3 + + + public String getLabel() { + return getAttributeWithNoDefault( "label" ); + } + + + public boolean getSelected() { + return _selected != null ? _selected.booleanValue() : getDefaultSelected(); + } + + + public String getText() { + return asText(); + } + + + public void setDefaultSelected( boolean defaultSelected ) { + } + + + public void setLabel( String label ) { + setAttribute( "label", label ); + } + + + public void setSelected( boolean selected ) { + if (selected && getSelect().getType().equals( HTMLSelectElementImpl.TYPE_SELECT_ONE)) getSelect().clearSelected(); + _selected = selected ? Boolean.TRUE : Boolean.FALSE; + } + + + private HTMLSelectElementImpl getSelect() { + Node parent = getParentNode(); + while (parent != null && !("select".equalsIgnoreCase( parent.getNodeName() ))) parent = parent.getParentNode(); + return (HTMLSelectElementImpl) parent; + } + + + public String getValue() { + return getAttributeWithNoDefault( "value" ); + } + + + public void setValue( String value ) { + setAttribute( "value", value ); + } + + + public void reset() { + _selected = null; + } + + + void addValueIfSelected( ParameterProcessor processor, String name, String characterSet ) throws IOException { + if (getSelected()) { + String value = getValue(); + if (value == null) value = readDisplayedValue(); + processor.addParameter( name, value, characterSet ); + } + } + + private String readDisplayedValue() { + Node nextSibling = 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(); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLParagraphElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLParagraphElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLParagraphElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,75 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLParagraphElement; +import org.w3c.dom.html.HTMLCollection; + +/** + * @author Russell Gold + */ +public class HTMLParagraphElementImpl extends HTMLElementImpl implements HTMLParagraphElement, HTMLContainerElement { + + ElementImpl create() { + return new HTMLParagraphElementImpl(); + } + + +//------------------------------------------ HTMLContainerElement methods ---------------------------------------------- + + + public HTMLCollection getLinks() { + return getHtmlDocument().getContainerDelegate().getLinks( this ); + } + + + public HTMLCollection getImages() { + return getHtmlDocument().getContainerDelegate().getImages( this ); + } + + + public HTMLCollection getApplets() { + return getHtmlDocument().getContainerDelegate().getApplets( this ); + } + + + public HTMLCollection getForms() { + return getHtmlDocument().getContainerDelegate().getForms( this ); + } + + + public HTMLCollection getAnchors() { + return getHtmlDocument().getContainerDelegate().getAnchors( this ); + } + + +//----------------------------------------- HTMLParagraphElement methods ----------------------------------------------- + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLSelectElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLSelectElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLSelectElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,172 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 2004,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 org.w3c.dom.html.HTMLSelectElement; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLOptionElement; +import org.w3c.dom.DOMException; +import com.meterware.httpunit.protocol.ParameterProcessor; + +import java.io.IOException; + +/** + * + * @author Russell Gold + **/ +public class HTMLSelectElementImpl extends HTMLControl implements HTMLSelectElement { + + public static final String TYPE_SELECT_ONE = "select-one"; + public static final String TYPE_SELECT_MULTIPLE = "select-multiple"; + + + ElementImpl create() { + return new HTMLSelectElementImpl(); + } + + + public void add( HTMLElement element, HTMLElement before ) throws DOMException { + } + + + + /** + * simulate blur + */ + public void blur() { + handleEvent("onblur"); + } + + + /** + * simulate focus; + */ + public void focus() { + handleEvent("onfocus"); + } + + public String getType() { + return isMultiSelect() ? TYPE_SELECT_MULTIPLE : TYPE_SELECT_ONE; + } + + + private boolean isMultiSelect() { + return (getMultiple() && getSize() > 1); + } + + public int getLength() { + return getOptions().getLength(); + } + + + public boolean getMultiple() { + return getBooleanAttribute( "multiple" ); + } + + + public HTMLCollection getOptions() { + return HTMLCollectionImpl.createHTMLCollectionImpl( getElementsByTagName( getHtmlDocument().toNodeCase( "option" ) ) ); + } + + + public int getSelectedIndex() { + HTMLCollection options = getOptions(); + for (int i = 0; i < options.getLength(); i++) { + if (((HTMLOptionElement)options.item(i)).getSelected()) return i; + } + return isMultiSelect() ? -1 : 0; + } + + + public String getValue() { + HTMLCollection options = getOptions(); + for (int i = 0; i < options.getLength(); i++) { + HTMLOptionElement optionElement = ((HTMLOptionElement)options.item(i)); + if (optionElement.getSelected()) return optionElement.getValue(); + } + return (isMultiSelect() || options.getLength() == 0) ? null : ((HTMLOptionElement)options.item(0)).getValue(); + } + + + public int getSize() { + return getIntegerAttribute( "size" ); + } + + + public void remove( int index ) { + } + + + public void setMultiple( boolean multiple ) { + setAttribute( "multiple", multiple ); + } + + + public void setSelectedIndex( int selectedIndex ) { + HTMLCollection options = getOptions(); + for (int i = 0; i < options.getLength(); i++) { + HTMLOptionElementImpl optionElement = (HTMLOptionElementImpl) options.item(i); + optionElement.setSelected( i == selectedIndex ); + } + } + + + public void setSize( int size ) { + setAttribute( "size", size ); + } + + + int getIndexOf( HTMLOptionElementImpl option ) { + HTMLCollection options = getOptions(); + for (int i = 0; i < options.getLength(); i++) { + if (options.item(i) == option) return i; + } + throw new IllegalStateException( "option is not part of this select" ); + } + + + void clearSelected() { + setSelectedIndex( -1 ); + } + + + void addValues( ParameterProcessor processor, String characterSet ) throws IOException { + HTMLCollection options = getOptions(); + String name = getName(); + for (int i = 0; i < options.getLength();i++) { + ((HTMLOptionElementImpl) options.item( i )).addValueIfSelected( processor, name, characterSet ); + } + } + + + public void setValue( String value ) { + setAttribute( "value", value ); + } + + + public void reset() { + HTMLCollection options = getOptions(); + for (int i = 0; i < options.getLength(); i++) { + HTMLControl optionElement = (HTMLControl) options.item(i); + optionElement.reset(); + } + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLStyleElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLStyleElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLStyleElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,63 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLStyleElement; + +/** + * + * @author Russell Gold + **/ +public class HTMLStyleElementImpl extends HTMLElementImpl implements HTMLStyleElement { + + ElementImpl create() { + return new HTMLStyleElementImpl(); + } + + + public boolean getDisabled() { + return getBooleanAttribute( "disabled" ); + } + + + public String getMedia() { + return getAttributeWithDefault( "media", "screen" ); + } + + + public String getType() { + return getAttributeWithNoDefault( "type" ); + } + + + public void setDisabled( boolean disabled ) { + setAttribute( "disabled", disabled ); + } + + + public void setMedia( String media ) { + setAttribute( "media", media ); + } + + + public void setType( String type ) { + setAttribute( "type", type ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableCellElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableCellElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableCellElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,216 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLTableCellElement; +import org.w3c.dom.html.HTMLCollection; + +/** + * @author Russell Gold + */ +public class HTMLTableCellElementImpl extends HTMLElementImpl implements HTMLTableCellElement, HTMLContainerElement, AttributeNameAdjusted { + + ElementImpl create() { + return new HTMLTableCellElementImpl(); + } + + +//------------------------------------------ HTMLContainerElement methods ---------------------------------------------- + + + public HTMLCollection getLinks() { + return getHtmlDocument().getContainerDelegate().getLinks( this ); + } + + + public HTMLCollection getImages() { + return getHtmlDocument().getContainerDelegate().getImages( this ); + } + + + public HTMLCollection getApplets() { + return getHtmlDocument().getContainerDelegate().getApplets( this ); + } + + + public HTMLCollection getForms() { + return getHtmlDocument().getContainerDelegate().getForms( this ); + } + + + public HTMLCollection getAnchors() { + return getHtmlDocument().getContainerDelegate().getAnchors( this ); + } + + +//-------------------------------------------- HTMLTableCellElement methods -------------------------------------------- + + + public String getAbbr() { + return getAttributeWithNoDefault( "abbr" ); + } + + + public void setAbbr( String abbr ) { + setAttribute( "abbr", abbr ); + } + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public String getAxis() { + return getAttributeWithNoDefault( "axis" ); + } + + + public void setAxis( String axis ) { + setAttribute( "axis", axis ); + } + + + public String getBgColor() { + return getAttributeWithNoDefault( "bgColor" ); + } + + + public void setBgColor( String bgColor ) { + setAttribute( "bgColor", bgColor ); + } + + + public int getCellIndex() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getCh() { + return getAttributeWithDefault( "char", "." ); + } + + + public void setCh( String ch ) { + setAttribute( "char", ch ); + } + + + public String getChOff() { + return getAttributeWithNoDefault( "charoff" ); + } + + + public void setChOff( String chOff ) { + setAttribute( "charoff", chOff ); + } + + + public int getColSpan() { + return getIntegerAttribute( "colspan", 1 ); + } + + + public void setColSpan( int colSpan ) { + setAttribute( "colspan", colSpan ); + } + + + public String getHeaders() { + return getAttributeWithNoDefault( "headers" ); + } + + + public void setHeaders( String headers ) { + setAttribute( "headers", headers ); + } + + + public String getHeight() { + return getAttributeWithNoDefault( "height" ); + } + + + public void setHeight( String height ) { + setAttribute( "height", height ); + } + + + public boolean getNoWrap() { + return getBooleanAttribute( "nowrap" ); + } + + + public void setNoWrap( boolean noWrap ) { + setAttribute( "nowrap", noWrap ); + } + + + public int getRowSpan() { + return getIntegerAttribute( "rowspan", 1 ); + } + + + public void setRowSpan( int rowSpan ) { + setAttribute( "rowspan", rowSpan ); + } + + + public String getScope() { + return getAttributeWithNoDefault( "scope" ); + } + + + public void setScope( String scope ) { + setAttribute( "scope", scope ); + } + + + public String getVAlign() { + return getAttributeWithDefault( "valign", "middle" ); + } + + + public void setVAlign( String vAlign ) { + setAttribute( "valign", vAlign ); + } + + + public String getWidth() { + return getAttributeWithNoDefault( "width" ); + } + + + public void setWidth( String width ) { + setAttribute( "width", width ); + } + + + public String getJavaAttributeName( String attributeName ) { + if (attributeName.equals( "char" )) return "ch"; + if (attributeName.equals( "charoff" )) return "choff"; + return attributeName; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,203 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.*; +import org.w3c.dom.DOMException; + +/** + * @author Russell Gold + */ +public class HTMLTableElementImpl extends HTMLElementImpl implements HTMLTableElement { + + ElementImpl create() { + return new HTMLTableElementImpl(); + } + + + public String getAlign() { + return getAttributeWithDefault( "align", "center" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public String getBgColor() { + return getAttributeWithNoDefault( "bgColor" ); + } + + + public void setBgColor( String bgColor ) { + setAttribute( "bgColor", bgColor ); + } + + + public String getBorder() { + return getAttributeWithNoDefault( "border" ); + } + + + public void setBorder( String border ) { + setAttribute( "border", border ); + } + + + public String getCellPadding() { + return getAttributeWithNoDefault( "cellpadding" ); + } + + + public void setCellPadding( String cellPadding ) { + setAttribute( "cellpadding", cellPadding ); + } + + + public String getCellSpacing() { + return getAttributeWithNoDefault( "cellspacing" ); + } + + + public void setCellSpacing( String cellSpacing ) { + setAttribute( "cellspacing", cellSpacing ); + } + + + public String getFrame() { + return getAttributeWithDefault( "frame", "void" ); + } + + + public void setFrame( String frame ) { + setAttribute( "frame", frame ); + } + + + public String getRules() { + return getAttributeWithDefault( "rules", "none" ); + } + + + public void setRules( String rules ) { + setAttribute( "rules", rules ); + } + + + public String getSummary() { + return getAttributeWithNoDefault( "summary" ); + } + + + public void setSummary( String summary ) { + setAttribute( "summary", summary ); + } + + + public String getWidth() { + return getAttributeWithNoDefault( "width" ); + } + + + public void setWidth( String width ) { + setAttribute( "width", width ); + } + + + public HTMLElement createCaption() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLElement createTFoot() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLElement createTHead() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void deleteCaption() { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public void deleteRow( int index ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public void deleteTFoot() { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public void deleteTHead() { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLTableCaptionElement getCaption() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLCollection getRows() { + return HTMLCollectionImpl.createHTMLCollectionImpl( getElementsByTagName( "tr" ) ); + } + + + public HTMLCollection getTBodies() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLTableSectionElement getTFoot() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLTableSectionElement getTHead() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLElement insertRow( int index ) throws DOMException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setCaption( HTMLTableCaptionElement caption ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setTFoot( HTMLTableSectionElement tFoot ) { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setTHead( HTMLTableSectionElement tHead ) { + //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableRowElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableRowElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTableRowElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,117 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLTableRowElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.DOMException; + +/** + * @author Russell Gold + */ +public class HTMLTableRowElementImpl extends HTMLElementImpl implements HTMLTableRowElement, AttributeNameAdjusted { + + ElementImpl create() { + return new HTMLTableRowElementImpl(); + } + + + public String getAlign() { + return getAttributeWithNoDefault( "align" ); + } + + + public void setAlign( String align ) { + setAttribute( "align", align ); + } + + + public String getBgColor() { + return getAttributeWithNoDefault( "bgColor" ); + } + + + public void setBgColor( String bgColor ) { + setAttribute( "bgColor", bgColor ); + } + + + public String getCh() { + return getAttributeWithDefault( "char", "." ); + } + + + public void setCh( String ch ) { + setAttribute( "char", ch ); + } + + + public String getChOff() { + return getAttributeWithNoDefault( "charoff" ); + } + + + public void setChOff( String chOff ) { + setAttribute( "charoff", chOff ); + } + + + public String getVAlign() { + return getAttributeWithDefault( "valign", "middle" ); + } + + + public void setVAlign( String vAlign ) { + setAttribute( "valign", vAlign ); + } + + + public void deleteCell( int index ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLCollection getCells() { + return HTMLCollectionImpl.createHTMLCollectionImpl( getElementsByTagNames( new String[] { "td", "th " } ) ); + } + + + public int getRowIndex() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + + public int getSectionRowIndex() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + + public HTMLElement insertCell( int index ) throws DOMException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getJavaAttributeName( String attributeName ) { + if (attributeName.equals( "char" )) return "ch"; + if (attributeName.equals( "charoff" )) return "choff"; + return attributeName; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTextAreaElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTextAreaElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTextAreaElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,120 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.html.HTMLTextAreaElement; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * + * @author Russell Gold + **/ +public class HTMLTextAreaElementImpl extends HTMLControl implements HTMLTextAreaElement { + + private String _value; + + ElementImpl create() { + return new HTMLTextAreaElementImpl(); + } + + + /** + * simulate blur + */ + public void blur() { + handleEvent("onblur"); + } + + + /** + * simulate focus; + */ + public void focus() { + handleEvent("onfocus"); + } + + + public String getAccessKey() { + return getAttributeWithNoDefault( "accesskey" ); + } + + + public int getCols() { + return getIntegerAttribute( "cols" ); + } + + + public String getDefaultValue() { + Node node = getFirstChild(); + if (node == null || node.getNodeType() != Node.TEXT_NODE) return null; + return node.getNodeValue(); + } + + + public int getRows() { + return getIntegerAttribute( "rows" ); + } + + + public void select() { + } + + + public void setAccessKey( String accessKey ) { + setAttribute( "accesskey", accessKey ); + } + + + public void setCols( int cols ) { + setAttribute( "cols", cols ); + } + + + public void setDefaultValue( String defaultValue ) { + Text textNode = getOwnerDocument().createTextNode( defaultValue ); + Node child = getFirstChild(); + if (child == null) { + appendChild( textNode ); + } else { + replaceChild( textNode, child ); + } + } + + + public void setRows( int rows ) { + setAttribute( "rows", rows ); + } + + + public String getValue() { + return _value != null ? _value : getDefaultValue(); + } + + + public void setValue( String value ) { + _value = value; + } + + + public void reset() { + _value = null; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTitleElementImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTitleElementImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/HTMLTitleElementImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,61 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.html.HTMLTitleElement; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * + * @author Russell Gold + **/ +public class HTMLTitleElementImpl extends HTMLElementImpl implements HTMLTitleElement { + + ElementImpl create() { + return new HTMLTitleElementImpl(); + } + + + public String getText() { + Text contentNode = getContentNode(); + return contentNode == null ? "" : contentNode.getData(); + } + + + private Text getContentNode() { + NodeList childNodes = getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + if (childNodes.item(i).getNodeType() == TEXT_NODE) return (Text) childNodes.item(i); + } + return null; + } + + + public void setText( String text ) { + Text newChild = getOwnerDocument().createTextNode( text ); + Text oldChild = getContentNode(); + if (oldChild == null) { + appendChild( newChild ); + } else { + replaceChild( newChild, oldChild ); + } + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamedNodeMapImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamedNodeMapImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamedNodeMapImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,83 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.DOMException; + +import java.util.Hashtable; + +/** + * + * @author Russell Gold + **/ +public class NamedNodeMapImpl implements NamedNodeMap { + + + private Hashtable _items; + private Node[] _itemArray; + + + NamedNodeMapImpl( Hashtable items ) { + _items = (Hashtable) items.clone(); + _itemArray = (Node[]) _items.values().toArray( new Node[ _items.size() ] ); + } + + + public Node getNamedItem( String name ) { + return (Node) _items.get( name ); + } + + + public Node setNamedItem( Node arg ) throws DOMException { + return null; + } + + + public Node removeNamedItem( String name ) throws DOMException { + return null; + } + + + public Node item( int index ) { + return _itemArray[ index ]; + } + + + public int getLength() { + return _items.size(); + } + + + public Node getNamedItemNS( String namespaceURI, String localName ) { + return null; + } + + + public Node setNamedItemNS( Node arg ) throws DOMException { + return null; + } + + + public Node removeNamedItemNS( String namespaceURI, String localName ) throws DOMException { + return null; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamespaceAwareNodeImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamespaceAwareNodeImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NamespaceAwareNodeImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,78 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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. + * + *******************************************************************************************************************/ + + +/** + * + * @author Russell Gold + **/ + +public abstract class NamespaceAwareNodeImpl extends NodeImpl { + + private String _tagName; + private String _localName; + private String _namespaceUri; + + + protected void initialize( DocumentImpl owner, String tagName ) { + initialize( owner ); + _localName = _tagName = tagName; + } + + + /** + * initialize the name space + * @param owner + * @param namespaceURI + * @param qualifiedName + */ + protected void initialize( DocumentImpl owner, String namespaceURI, String qualifiedName ) { + initialize( owner ); + _tagName = qualifiedName; + _namespaceUri = namespaceURI; + if (qualifiedName.indexOf(':') < 0) { + _localName = qualifiedName; + } else { + _localName = qualifiedName.substring( qualifiedName.indexOf(':') + 1 ); + } + setParentScope(owner); + } + + public String getNodeName() { + return getTagName(); + } + + + public String getTagName() { + return _tagName; + } + + + public String getNamespaceURI() { + return _namespaceUri; + } + + + public String getLocalName() { + return _localName; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,424 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $Id$ + * + * Copyright (c) 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 org.w3c.dom.*; +import org.w3c.dom.html.HTMLIFrameElement; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; + +/** + * + * @author Russell Gold + **/ +abstract public class NodeImpl extends AbstractDomComponent implements Node { + + private DocumentImpl _ownerDocument; + private NodeImpl _parentNode; + private NodeImpl _firstChild; + private NodeImpl _nextSibling; + private NodeImpl _previousSibling; + private Hashtable _userData = new Hashtable( ); + + static IteratorMask SKIP_IFRAMES = new IteratorMask() { + public boolean skipSubtree( Node subtreeRoot ) { + return subtreeRoot instanceof HTMLIFrameElement; + } + }; + + + protected void initialize( DocumentImpl ownerDocument ) { + if (_ownerDocument != null) throw new IllegalStateException( "NodeImpl already initialized" ); + if (ownerDocument == null) throw new IllegalArgumentException( "No owner document specified" ); + _ownerDocument = ownerDocument; + } + + +//------------------------------------------ ScriptableObject methods -------------------------------------------------- + +//------------------------------------------ ScriptingEngine methods -------------------------------------------------- + +//----------------------------------------------- Node methods --------------------------------------------------------- + + + public Node getParentNode() { + return _parentNode; + } + + + public NodeList getChildNodes() { + ArrayList list = new ArrayList(); + for (NodeImpl child = _firstChild; child != null; child = child._nextSibling) { + list.add( child ); + } + return new NodeListImpl( list ); + } + + + public Node getFirstChild() { + return _firstChild; + } + + + public Node getLastChild() { + if (_firstChild == null) return null; + + Node child = _firstChild; + while (child.getNextSibling() != null) child = child.getNextSibling(); + return child; + } + + + public Node getPreviousSibling() { + return _previousSibling; + } + + + public Node getNextSibling() { + return _nextSibling; + } + + + public NamedNodeMap getAttributes() { + return null; + } + + + public Document getOwnerDocument() { + return _ownerDocument; + } + + + public Node insertBefore( Node newChild, Node refChild ) throws DOMException { + NodeImpl refChildNode = (NodeImpl) refChild; + if (refChildNode.getParentNode() != this) throw new DOMException( DOMException.NOT_FOUND_ERR, "Must specify an existing child as the reference" ); + NodeImpl newChildNode = getChildIfPermitted( newChild ); + removeFromTree( newChildNode ); + newChildNode._parentNode = this; + if (refChildNode._previousSibling == null) { + _firstChild = newChildNode; + } else { + refChildNode._previousSibling.setNextSibling( newChildNode ); + } + newChildNode.setNextSibling( refChildNode ); + return newChildNode; + } + + + private void removeFromTree( NodeImpl childNode ) { + if (childNode._parentNode != null) { + if (childNode._previousSibling != null) { + childNode._previousSibling.setNextSibling( childNode._nextSibling ); + } else { + childNode._parentNode._firstChild = childNode._nextSibling; + childNode._nextSibling._previousSibling = null; + } + childNode._parentNode = null; + } + } + + + public Node replaceChild( Node newChild, Node oldChild ) throws DOMException { + insertBefore( newChild, oldChild ); + return removeChild( oldChild ); + } + + + public Node removeChild( Node oldChild ) throws DOMException { + if (oldChild.getParentNode() != this) throw new DOMException( DOMException.NOT_FOUND_ERR, "May only remove a node from its own parent" ); + removeFromTree( (NodeImpl) oldChild ); + return oldChild; + } + + + public Node appendChild( Node newChild ) throws DOMException { + if (newChild == null) throw new IllegalArgumentException( "child to append may not be null" ); + + NodeImpl childNode = getChildIfPermitted( newChild ); + removeFromTree( childNode ); + childNode._parentNode = this; + if (_firstChild == null) { + _firstChild = childNode; + } else { + ((NodeImpl) getLastChild()).setNextSibling( childNode ); + } + return newChild; + } + + + protected NodeImpl getChildIfPermitted( Node proposedChild ) { + if (!(proposedChild instanceof NodeImpl)) throw new DOMException( DOMException.WRONG_DOCUMENT_ERR, "Specified node is from a different DOM implementation" ); + NodeImpl childNode = (NodeImpl) proposedChild; + if (getOwnerDocument() != childNode._ownerDocument) throw new DOMException( DOMException.WRONG_DOCUMENT_ERR, "Specified node is from a different document" ); + for (Node parent = this; parent != null; parent = parent.getParentNode()) { + if (proposedChild == parent) throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "May not add node as its own descendant" ); + } + + return childNode; + } + + + private void setNextSibling( NodeImpl sibling ) { + _nextSibling = sibling; + if (sibling != null) sibling._previousSibling = this; + } + + + public boolean hasChildNodes() { + return _firstChild != null; + } + + + public Node cloneNode( boolean deep ) { + return getOwnerDocument().importNode( this, deep ); + } + + + public void normalize() { + } + + + public boolean isSupported( String feature, String version ) { + return false; + } + + + public String getNamespaceURI() { + return null; + } + + + public String getPrefix() { + return null; + } + + + public void setPrefix( String prefix ) throws DOMException { + } + + + public String getLocalName() { + return null; + } + + + public boolean hasAttributes() { + return false; + } + +//------------------------------------ DOM level 3 methods ------------------------------------------------------------- + + public Object setUserData( String key, Object data, UserDataHandler handler ) { + return _userData.put( key, data ); + } + + + public Object getUserData( String key ) { + return _userData.get( key ); + } + + + public Object getFeature( String feature, String version ) { + return null; + } + + + public boolean isEqualNode( Node arg ) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + + public String lookupNamespaceURI( String prefix ) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getBaseURI() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public short compareDocumentPosition( Node other ) throws DOMException { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + + public String getTextContent() throws DOMException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public void setTextContent( String textContent ) throws DOMException { + //To change body of implemented methods use File | Settings | File Templates. + } + + + public boolean isSameNode( Node other ) { + return this == other; + } + + + public String lookupPrefix( String namespaceURI ) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + + public boolean isDefaultNamespace( String namespaceURI ) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + +//----------------------------------------- implementation internals --------------------------------------------------- + + public NodeList getElementsByTagName( String name ) { + ArrayList matchingElements = new ArrayList(); + appendElementsWithTag( name, matchingElements ); + return new NodeListImpl( matchingElements ); + } + + + private void appendElementsWithTag( String name, ArrayList matchingElements ) { + for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != ELEMENT_NODE) continue; + if (name.equals( "*" ) || ((Element) child).getTagName().equalsIgnoreCase( name )) matchingElements.add( child ); + ((NodeImpl) child).appendElementsWithTag( name, matchingElements ); + } + } + + + protected NodeList getElementsByTagNames( String[] names ) { + ArrayList matchingElements = new ArrayList(); + appendElementsWithTags( names, matchingElements ); + return new NodeListImpl( matchingElements ); + } + + + void appendElementsWithTags( String[] names, ArrayList matchingElements ) { + for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != ELEMENT_NODE) continue; + String tagName = ((Element) child).getTagName(); + for (int i = 0; i < names.length; i++) { + if (tagName.equalsIgnoreCase( names[i] )) matchingElements.add( child ); + } + ((NodeImpl) child).appendElementsWithTags( names, matchingElements ); + } + } + + + String asText() { + StringBuffer sb = new StringBuffer(); + appendContents( sb ); + return sb.toString(); + } + + + void appendContents( StringBuffer sb ) { + NodeList nl = getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + ((NodeImpl) nl.item(i)).appendContents( sb ); + } + } + + + public Iterator preOrderIterator() { + return new PreOrderIterator( this ); + } + + + public Iterator preOrderIterator( IteratorMask mask ) { + return new PreOrderIterator( this, mask ); + } + + + public Iterator preOrderIteratorAfterNode() { + return new PreOrderIterator( PreOrderIterator.nextNode( this ) ); + } + + + public Iterator preOrderIteratorAfterNode( IteratorMask mask ) { + return new PreOrderIterator( PreOrderIterator.nextNode( this ), mask ); + } + + + protected String getJavaPropertyName( String propertyName ) { + if (propertyName.equals( "document" )) { + return "ownerDocument"; + } else { + return propertyName; + } + } + + + interface IteratorMask { + boolean skipSubtree( Node subtreeRoot ); + } + + + static class PreOrderIterator implements Iterator { + private NodeImpl _nextNode; + private IteratorMask _mask; + + + PreOrderIterator( NodeImpl currentNode ) { + _nextNode = currentNode; + } + + + PreOrderIterator( NodeImpl currentNode, IteratorMask mask ) { + this( currentNode ); + _mask = mask; + } + + + public boolean hasNext() { + return null != _nextNode; + } + + + public Object next() { + NodeImpl currentNode = _nextNode; + _nextNode = nextNode( _nextNode ); + while (_mask != null && _nextNode != null && _mask.skipSubtree( _nextNode )) _nextNode = nextSubtree( _nextNode ); + return currentNode; + } + + + public void remove() { + throw new java.lang.UnsupportedOperationException(); + } + + + static NodeImpl nextNode( NodeImpl node ) { + if (node._firstChild != null) return node._firstChild; + return nextSubtree( node ); + } + + + private static NodeImpl nextSubtree( NodeImpl node ) { + if (node._nextSibling != null) return node._nextSibling; + while (node._parentNode != null) { + node = node._parentNode; + if (node._nextSibling != null) return node._nextSibling; + } + return null; + } + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeListImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeListImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/NodeListImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,68 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.NodeList; +import org.w3c.dom.Node; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.Scriptable; + +import java.util.List; + +/** + * + * @author Russell Gold + **/ +public class NodeListImpl extends ScriptableObject implements NodeList { + + private List _list; + + + public NodeListImpl( List list ) { + _list = list; + } + + + public Node item( int index ) { + return (Node) _list.get( index ); + } + + + public int getLength() { + return _list.size(); + } + + + public String getClassName() { + return NodeListImpl.class.getName(); + } + + + public Object get( String name, Scriptable start ) { + if ("length".equals( name )) return new Integer( getLength() ); + return NOT_FOUND; + } + + + public Object get( int index, Scriptable start ) { + if (index < 0 || index >= getLength()) return NOT_FOUND; + return item( index ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ProcessingInstructionImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ProcessingInstructionImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ProcessingInstructionImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,89 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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 org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * + * @author Russell Gold + **/ +public class ProcessingInstructionImpl extends NodeImpl implements ProcessingInstruction { + + private String _target; + private String _data; + + + public static ProcessingInstruction createProcessingImpl( DocumentImpl ownerDocument, String target, String data ) { + ProcessingInstructionImpl instruction = new ProcessingInstructionImpl(); + instruction.initialize( ownerDocument, target, data ); + return instruction; + } + + + private void initialize( DocumentImpl ownerDocument, String target, String data ) { + super.initialize( ownerDocument ); + _target = target; + _data = data; + } + + + public static Node importNode( DocumentImpl document, ProcessingInstruction processingInstruction ) { + return createProcessingImpl( document, processingInstruction.getTarget(), processingInstruction.getData() ); + } + + + public String getNodeName() { + return _target; + } + + + public String getNodeValue() throws DOMException { + return _data; + } + + + public void setNodeValue( String string ) throws DOMException { + setData( string ); + } + + + public short getNodeType() { + return PROCESSING_INSTRUCTION_NODE; + } + + + public String getTarget() { + return _target; + } + + + public String getData() { + return _data; + } + + + public void setData( String string ) throws DOMException { + _data = string; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ScriptingSupport.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ScriptingSupport.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/ScriptingSupport.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,175 @@ +package com.meterware.httpunit.dom; + +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.FunctionObject; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.util.Hashtable; + +/** + * Utilities to support scripting. + */ +class ScriptingSupport { + + /** A non-null method value to be used to indicate that we have already looked up and failed to find one. **/ + private static final Method NO_SUCH_PROPERTY = ScriptingSupport.class.getDeclaredMethods()[0]; + + private static final Object[] NO_ARGS = new Object[0]; + + /** map of classes to maps of string to function objects. **/ + private static Hashtable _classFunctionMaps = new Hashtable(); + + /** map of classes to maps of string to getter methods. **/ + private static Hashtable _classGetterMaps = new Hashtable(); + + /** map of classes to maps of string to setter methods. **/ + private static Hashtable _classSetterMaps = new Hashtable(); + + + static boolean hasNamedProperty( Object element, String javaPropertyName, Scriptable scriptable ) { + Method getter = getPropertyGetter( element.getClass(), javaPropertyName ); + if (getter != NO_SUCH_PROPERTY) { + return true; + } else { + Object function = getFunctionObject( element.getClass(), javaPropertyName, scriptable ); + return function != null; + } + } + + + static Object getNamedProperty( Object element, String javaPropertyName, Scriptable scriptable ) { + Method getter = getPropertyGetter( element.getClass(), javaPropertyName ); + if (getter == NO_SUCH_PROPERTY) { + Object function = getFunctionObject( element.getClass(), javaPropertyName, scriptable ); + return function == null ? Scriptable.NOT_FOUND : function; + } + try { + return getter.invoke( element, NO_ARGS ); + } catch (IllegalAccessException e) { + return Scriptable.NOT_FOUND; + } catch (InvocationTargetException e) { + return Scriptable.NOT_FOUND; + } + } + + private static FunctionObject getFunctionObject( Class aClass, String methodName, Scriptable scriptable ) { + Hashtable functionMap = (Hashtable) _classFunctionMaps.get( aClass ); + if (functionMap == null) { + _classFunctionMaps.put( aClass, functionMap = new Hashtable() ); + } + + Object result = functionMap.get( methodName ); + if (result == NO_SUCH_PROPERTY) return null; + if (result != null) return (FunctionObject) result; + + Method[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (method.getName().equalsIgnoreCase( methodName )) { + FunctionObject function = new FunctionObject( methodName, method, scriptable ); + functionMap.put( methodName, function ); + return function; + } + } + functionMap.put( methodName, NO_SUCH_PROPERTY ); + return null; + } + + + private static Method getPropertyGetter( Class aClass, String propertyName ) { + Hashtable methodMap = (Hashtable) _classGetterMaps.get( aClass ); + if (methodMap == null) { + _classGetterMaps.put( aClass, methodMap = new Hashtable() ); + } + + Method result = (Method) methodMap.get( propertyName ); + if (result != null) return result; + + Method[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (method.getParameterTypes().length > 0) continue; + if (method.getName().equalsIgnoreCase( "is" + propertyName ) || method.getName().equalsIgnoreCase( "get" + propertyName )) { + methodMap.put( propertyName, method ); + return method; + } + } + methodMap.put( propertyName, NO_SUCH_PROPERTY ); + return NO_SUCH_PROPERTY; + } + + + static void setNamedProperty( AbstractDomComponent element, String javaPropertyName, Object value ) { + Method setter = getPropertySetter( element.getClass(), javaPropertyName, value ); + if (setter == NO_SUCH_PROPERTY) return; + + try { + setter.invoke( element, new Object[] { adjustedForSetter( value, setter ) } ); + } catch (IllegalAccessException e) { /* do nothing */ + } catch (InvocationTargetException e) { /* do nothing */ + } + } + + + private static Object adjustedForSetter( Object value, Method setter ) { + if (value == null) return null; + Class targetValueClass = setter.getParameterTypes()[0]; + if (targetValueClass.equals( String.class )) return value.toString(); + if (!(value instanceof Number) || !isNumericParameter( targetValueClass )) return value; + + if (targetValueClass.getName().equals("int")) return new Integer( ((Number) value).intValue() ); + if (targetValueClass.getName().equals("byte")) return new Byte( ((Number) value).byteValue() ); + if (targetValueClass.getName().equals("long")) return new Long( ((Number) value).longValue() ); + if (targetValueClass.getName().equals("short")) return new Short( ((Number) value).shortValue() ); + if (targetValueClass.getName().equals("float")) return new Float( ((Number) value).intValue() ); + if (targetValueClass.getName().equals("double")) return new Double( ((Number) value).intValue() ); + return value; + } + + + static Method getPropertySetter( Class aClass, String propertyName, Object value ) { + Hashtable methodMap = (Hashtable) _classSetterMaps.get( aClass ); + if (methodMap == null) { + _classSetterMaps.put( aClass, methodMap = new Hashtable() ); + } + + Method result = (Method) methodMap.get( propertyName ); + if (result != null) return result; + + String setterName = "set" + Character.toUpperCase( propertyName.charAt( 0 ) ) + propertyName.substring(1); + Method[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (method.getName().equalsIgnoreCase( setterName ) && + method.getParameterTypes().length == 1 && + isConvertableTo( value.getClass(), method.getParameterTypes()[0] )) { + methodMap.put( propertyName, method ); + return method; + } + } + methodMap.put( propertyName, NO_SUCH_PROPERTY ); + return NO_SUCH_PROPERTY; + } + + + /** + * check whether the valueType is convertable to the parameterType + * @param valueType + * @param parameterType + * @return + */ + public static boolean isConvertableTo( Class valueType, Class parameterType ) { + if (valueType.equals( parameterType )) return true; + if (parameterType.equals( String.class )) return true; + if (valueType.equals( String.class ) && isNumericParameter( parameterType )) return true; + if (Number.class.isAssignableFrom( valueType ) && isNumericParameter( parameterType )) return true; + if (valueType.equals(Boolean.class )&¶meterType.equals(boolean .class)) return true; + return valueType.equals( String.class ) && parameterType.equals( Boolean.class ); + } + + private static boolean isNumericParameter( Class parameterType ) { + if (parameterType.isPrimitive() && !(parameterType.equals( boolean.class ))) return true; + return Number.class.isAssignableFrom( parameterType ); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/dom/TextImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/dom/TextImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/dom/TextImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,92 @@ +package com.meterware.httpunit.dom; +/******************************************************************************************************************** + * $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.Text; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * + * @author Russell Gold + **/ +public class TextImpl extends CharacterDataImpl implements Text { + + + static TextImpl createText( DocumentImpl ownerDocument, String data ) { + TextImpl text = new TextImpl(); + text.initialize( ownerDocument, data ); + return text; + } + + + public String getNodeName() { + return "#text"; + } + + + public String getNodeValue() throws DOMException { + return getData(); + } + + + public void setNodeValue( String nodeValue ) throws DOMException { + setData( nodeValue ); + } + + + public short getNodeType() { + return TEXT_NODE; + } + + + protected NodeImpl getChildIfPermitted( Node proposedChild ) { + throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Text nodes may not have children" ); + } + + + public Text splitText( int offset ) throws DOMException { + return null; + } + + + public static Node importNode( DocumentImpl document, Text text ) { + return document.createTextNode( text.getData() ); + } + + + void appendContents( StringBuffer sb ) { + sb.append( getData() ); + } + +//------------------------------------- DOM level 3 methods ------------------------------------------------------------ + + public boolean isElementContentWhitespace() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public String getWholeText() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Text replaceWholeText( String content ) throws DOMException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScript.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScript.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScript.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,1135 @@ +package com.meterware.httpunit.javascript; +/******************************************************************************************************************** + * $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.*; + +import com.meterware.httpunit.scripting.*; + +import java.lang.reflect.InvocationTargetException; +import java.io.IOException; +import java.net.URL; + +import org.mozilla.javascript.*; +import org.xml.sax.SAXException; + + +/** + * This class is the Rhino-compatible implementation of the JavaScript DOM objects. + * + * @author Russell Gold + **/ +public class JavaScript { + + private static boolean _throwExceptionsOnError = true; + + + public static boolean isThrowExceptionsOnError() { + return _throwExceptionsOnError; + } + + + public static void setThrowExceptionsOnError( boolean throwExceptionsOnError ) { + _throwExceptionsOnError = throwExceptionsOnError; + } + + + /** + * Initiates JavaScript execution for the specified web response. + */ + public static void run( WebResponse response ) throws IllegalAccessException, InstantiationException, + InvocationTargetException, ClassDefinitionException, NotAFunctionException, + PropertyException, SAXException, JavaScriptException { + Context context = Context.enter(); + // suggest bug fix for large java scripts see + // bug report [ 1216567 ] Exception for large javascripts + // by Grzegorz Lukasik + // and + + context.setOptimizationLevel(HttpUnitOptions.getJavaScriptOptimizationLevel()); + Scriptable scope = context.initStandardObjects( null ); + initHTMLObjects( scope ); + + Window w = (Window) context.newObject( scope, "Window" ); + w.initialize( null, response.getScriptableObject() ); + } + + + /** + * Runs the onload event for the specified web response. + */ + public static void load( WebResponse response ) throws ClassDefinitionException, InstantiationException, IllegalAccessException, InvocationTargetException, PropertyException, JavaScriptException, SAXException, NotAFunctionException { + if (!(response.getScriptableObject().getScriptEngine() instanceof JavaScriptEngine)) run( response ); + response.getScriptableObject().load(); + } + + + private static void initHTMLObjects( Scriptable scope ) throws IllegalAccessException, InstantiationException, + InvocationTargetException, ClassDefinitionException, PropertyException { + ScriptableObject.defineClass( scope, Window.class ); + ScriptableObject.defineClass( scope, Document.class ); + ScriptableObject.defineClass( scope, Style.class ); + ScriptableObject.defineClass( scope, Location.class ); + ScriptableObject.defineClass( scope, Navigator.class ); + ScriptableObject.defineClass( scope, Screen.class ); + ScriptableObject.defineClass( scope, Link.class ); + ScriptableObject.defineClass( scope, Form.class ); + ScriptableObject.defineClass( scope, Control.class ); + ScriptableObject.defineClass( scope, Link.class ); + ScriptableObject.defineClass( scope, Image.class ); + ScriptableObject.defineClass( scope, Options.class ); + ScriptableObject.defineClass( scope, Option.class ); + ScriptableObject.defineClass( scope, ElementArray.class ); + ScriptableObject.defineClass( scope, HTMLElement.class ); + } + + + /** + * abstract Engine for JavaScript + */ + abstract static class JavaScriptEngine extends ScriptingEngineImpl { + + protected ScriptableDelegate _scriptable; + protected JavaScriptEngine _parent; + + /** + * initialize JavaScript for the given ScriptEngine + * @parent - the Script Engine to use + * @scriptable - the scriptable object to do the initialization for + */ + void initialize( JavaScriptEngine parent, ScriptableDelegate scriptable ) + throws SAXException, PropertyException, JavaScriptException, NotAFunctionException { + _scriptable = scriptable; + _scriptable.setScriptEngine( this ); + _parent = parent; + if (parent != null) setParentScope( parent ); + } + + + String getName() { + return _scriptable instanceof NamedDelegate ? ((NamedDelegate) _scriptable).getName() : ""; + } + + + String getID() { + return _scriptable instanceof IdentifiedDelegate ? ((IdentifiedDelegate) _scriptable).getID() : ""; + } + + /** + * get the event Handler script for the event e.g. onchange, onmousedown, onclick, onmouseup + * execute the script if it's assigned by calling doEvent for the script + * @param eventName + * @return + */ + public boolean handleEvent(String eventName) { + return _scriptable.handleEvent(eventName); + } + + public boolean has( String propertyName, Scriptable scriptable ) { + return super.has( propertyName, scriptable ) || + (_scriptable != null && _scriptable.get( propertyName ) != null); + } + + + public Object get( String propertyName, Scriptable scriptable ) { + Object result = super.get( propertyName, scriptable ); + if (result != NOT_FOUND) return result; + if (_scriptable == null) return NOT_FOUND; + + return convertIfNeeded( _scriptable.get( propertyName ) ); + + } + + + public Object get( int i, Scriptable scriptable ) { + Object result = super.get( i, scriptable ); + if (result != NOT_FOUND) return result; + if (_scriptable == null) return NOT_FOUND; + + return convertIfNeeded( _scriptable.get( i ) ); + } + + + private Object convertIfNeeded( final Object property ) { + if (property == null) return NOT_FOUND; + + if (property instanceof ScriptableDelegate[]) return toScriptable( (ScriptableDelegate[]) property ); + if (!(property instanceof ScriptableDelegate)) return property; + return toScriptable( (ScriptableDelegate) property ); + } + + + private Object toScriptable( ScriptableDelegate[] list ) { + Object[] delegates = new Object[ list.length ]; + for (int i = 0; i < delegates.length; i++) { + delegates[i] = toScriptable( list[i] ); + } + return Context.getCurrentContext().newArray( this, delegates ); + } + + + public void put( String propertyName, Scriptable scriptable, Object value ) { + if (_scriptable == null || _scriptable.get( propertyName ) == null) { + super.put( propertyName, scriptable, value ); + } else { + _scriptable.set( propertyName, value ); + } + } + + + public String toString() { + return (_scriptable == null ? "prototype " : "") + getClassName(); + } + + + public ScriptingEngine newScriptingEngine( ScriptableDelegate child ) { + try { + return (ScriptingEngine) toScriptable( child ); + } catch (Exception e) { + HttpUnitUtils.handleException(e); + throw new RuntimeException( e.toString() ); + } + } + + + public void clearCaches() { + } + + + protected static String toStringIfNotUndefined( Object object ) { + return (object == null || Undefined.instance.equals( object )) ? null : object.toString(); + } + + + /** + * Converts a scriptable delegate obtained from a subobject into the appropriate Rhino-compatible Scriptable. + **/ + final Object toScriptable( ScriptableDelegate delegate ) { + if (delegate == null) { + return NOT_FOUND; + } else if (delegate.getScriptEngine() instanceof Scriptable) { + return (Scriptable) delegate.getScriptEngine(); + } else { + try { + JavaScriptEngine element = (JavaScriptEngine) Context.getCurrentContext().newObject( this, getScriptableClassName( delegate ) ); + element.initialize( this, delegate ); + return element; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RhinoException( e ); + } + } + } + + + /** + * get the classname of the given ScriptableDelegate + * @param delegate - the object to get the class name for + * @return - the simple local class name for the delegate e.g. Window, Document, Form, Link, Image, Options, Option, Control, HTMLElement + * @throws an IllegalArgumentException if the delegate is not known + */ + private String getScriptableClassName( ScriptableDelegate delegate ) { + if (delegate instanceof WebResponse.Scriptable) return "Window"; + if (delegate instanceof HTMLPage.Scriptable) return "Document"; + if (delegate instanceof FormScriptable) return "Form"; + if (delegate instanceof WebLink.Scriptable) return "Link"; + if (delegate instanceof WebImage.Scriptable) return "Image"; + if (delegate instanceof SelectionOptions) return "Options"; + if (delegate instanceof SelectionOption) return "Option"; + if (delegate instanceof Input) return "Control"; + if (delegate instanceof DocumentElement) return "HTMLElement"; + + throw new IllegalArgumentException( "Unknown ScriptableDelegate class: " + delegate.getClass() ); + } + + + protected ElementArray toElementArray( ScriptingHandler[] scriptables ) { + JavaScriptEngine[] elements = new JavaScriptEngine[ scriptables.length ]; + for (int i = 0; i < elements.length; i++) { + elements[ i ] = (JavaScriptEngine) toScriptable( (ScriptableDelegate) scriptables[ i ] ); + } + ElementArray result = ElementArray.newElementArray( this ); + result.initialize( elements ); + return result; + } + } + + + static public class Window extends JavaScriptEngine { + + private Document _document; + private Navigator _navigator; + private Location _location; + private Screen _screen; + private ElementArray _frames; + + + public String getClassName() { + return "Window"; + } + + + public Window jsGet_window() { + return this; + } + + + public Window jsGet_self() { + return this; + } + + + public Document jsGet_document() { + if (_document == null) { + _document = (Document) toScriptable( getDelegate().getDocument() ); + } + return _document; + } + + + public Scriptable jsGet_frames() throws SAXException, PropertyException, JavaScriptException, NotAFunctionException { + if (_frames == null) { + WebResponse.Scriptable scriptables[] = getDelegate().getFrames(); + Window[] frames = new Window[ scriptables.length ]; + for (int i = 0; i < frames.length; i++) { + frames[ i ] = (Window) toScriptable( scriptables[ i ] ); + } + _frames = (ElementArray) Context.getCurrentContext().newObject( this, "ElementArray" ); + _frames.initialize( frames ); + } + return _frames; + } + + + public Navigator jsGet_navigator() { + return _navigator; + } + + + public Screen jsGet_screen() { + return _screen; + } + + + public Location jsGet_location() { + return _location; + } + + + public void jsSet_location( String relativeURL ) throws IOException, SAXException { + setLocation( relativeURL ); + } + + + void setLocation( String relativeURL ) throws IOException, SAXException { + getDelegate().setLocation( relativeURL ); + } + + + /** + * initialize JavaScript for the given ScriptEngine + * @parent - the Script Engine to use + * @scriptable - the scriptable object to do the initialization for + */ + void initialize( JavaScriptEngine parent, ScriptableDelegate scriptable ) + throws JavaScriptException, NotAFunctionException, PropertyException, SAXException { + super.initialize( parent, scriptable ); + + _location = (Location) Context.getCurrentContext().newObject( this, "Location" ); + _location.initialize(this, ((WebResponse.Scriptable) scriptable).getURL() ); + + _navigator = (Navigator) Context.getCurrentContext().newObject( this, "Navigator" ); + _navigator.setClientProperties( getDelegate().getClientProperties() ); + + _screen = (Screen) Context.getCurrentContext().newObject( this, "Screen" ); + _screen.setClientProperties( getDelegate().getClientProperties() ); + } + + + /** + * javascript alert handling + * @param message - the alert message + */ + public void jsFunction_alert( String message ) { + getDelegate().alertUser( message ); + } + + + public boolean jsFunction_confirm( String message ) { + return getDelegate().getConfirmationResponse( message ); + } + + + public String jsFunction_prompt( String message, String defaultResponse ) { + return getDelegate().getUserResponse( message, defaultResponse ); + } + + + public void jsFunction_moveTo( int x, int y ) { + } + + + public void jsFunction_focus() { + } + + + public void jsFunction_setTimeout() { + } + + + public void jsFunction_close() { + getDelegate().closeWindow(); + } + + + public Window jsFunction_open( Object url, String name, String features, boolean replace ) + throws PropertyException, JavaScriptException, NotAFunctionException, IOException, SAXException { + WebResponse.Scriptable delegate = getDelegate().open( toStringIfNotUndefined( url ), name, features, replace ); + return delegate == null ? null : (Window) toScriptable( delegate ); + } + + + public void clearCaches() { + if (_document != null) _document.clearCaches(); + } + + + protected String getDocumentWriteBuffer() { + return jsGet_document().getWriteBuffer().toString(); + } + + + protected void discardDocumentWriteBuffer() { + jsGet_document().clearWriteBuffer(); + } + + + private WebResponse.Scriptable getDelegate() { + return (WebResponse.Scriptable) _scriptable; + } + } + + + /** + * Document script handling + */ + static public class Document extends JavaScriptEngine { + + private ElementArray _forms; + private ElementArray _links; + private ElementArray _images; + private StringBuffer _writeBuffer; + private String _mimeType; + + + public String getClassName() { + return "Document"; + } + + + public void clearCaches() { + _forms = _links = _images = null; + } + + + public String jsGet_title() throws SAXException { + return getDelegate().getTitle(); + } + + + public Scriptable jsGet_images() throws SAXException{ + if (_images == null) _images = toElementArray( getDelegate().getImages() ); + return _images; + } + + + public Scriptable jsGet_links() throws SAXException { + if (_links == null) _links = toElementArray( getDelegate().getLinks() ); + return _links; + } + + + public Scriptable jsGet_forms() throws SAXException { + if (_forms == null) _forms = toElementArray( getDelegate().getForms() ); + return _forms; + } + + + public Object jsFunction_getElementById( String id ) { + ScriptableDelegate elementWithID = getDelegate().getElementWithID( id ); + return elementWithID == null ? null : toScriptable( elementWithID ); + } + + + public Object jsFunction_getElementsByName( String name ) { + return toElementArray( getDelegate().getElementsByName( name ) ); + } + + + public Object jsFunction_getElementsByTagName( String name ) { + return toElementArray( getDelegate().getElementsByTagName( name ) ); + } + + + public Object jsGet_location() { + return _parent == null ? NOT_FOUND : getWindow().jsGet_location(); + } + + + public void jsSet_location( String urlString ) throws IOException, SAXException { + if (urlString.startsWith( "color" )) return; + getWindow().setLocation( urlString ); + } + + public String jsGet_cookie() { + return getDelegate().getCookie(); + } + + + public void jsSet_cookie( String cookieSpec ) { + final int equalsIndex = cookieSpec.indexOf( '=' ); + if (equalsIndex <0) return; + int endIndex = cookieSpec.indexOf( ";", equalsIndex ); + if (endIndex < 0) endIndex = cookieSpec.length(); + String name = cookieSpec.substring( 0, equalsIndex ); + String value = cookieSpec.substring( equalsIndex+1, endIndex ); + getDelegate().setCookie( name, value ); + } + + + private Window getWindow() { + return ((Window) _parent); + } + + + public void jsFunction_open( Object mimeType ) { + _mimeType = toStringIfNotUndefined( mimeType ); + } + + + public void jsFunction_close() { + if (getDelegate().replaceText( getWriteBuffer().toString(), _mimeType == null ? "text/html" : _mimeType )) { + getWriteBuffer().setLength(0); + } + } + + + public void jsFunction_write( String string ) { + getWriteBuffer().append( string ); + } + + + public void jsFunction_writeln( String string ) { + getWriteBuffer().append( string ).append( (char) 0x0D ).append( (char) 0x0A ); + } + + + protected StringBuffer getWriteBuffer() { + if (_writeBuffer == null) _writeBuffer = new StringBuffer(); + return _writeBuffer; + } + + + protected void clearWriteBuffer() { + _writeBuffer = null; + } + + + private HTMLPage.Scriptable getDelegate() { + return (HTMLPage.Scriptable) _scriptable; + } + + } + + + static public class Location extends JavaScriptEngine { + + private URL _url; + private Window _window; + + public String getClassName() { + return "Location"; + } + + + void initialize( Window window, URL url ) { + _window = window; + _url = url; + } + + + public void jsFunction_replace( String urlString ) throws IOException, SAXException { + _window.setLocation( urlString ); + } + + + public String jsGet_href() { + return toString(); + } + + + public void jsSet_href( String urlString ) throws SAXException, IOException { + _window.setLocation( urlString ); + } + + + public String jsGet_protocol() { + return _url.getProtocol() + ':'; + } + + + public String jsGet_host() { + return _url.getHost() + ':' + _url.getPort(); + } + + + public String jsGet_hostname() { + return _url.getHost(); + } + + + public String jsGet_port() { + return String.valueOf( _url.getPort() ); + } + + + public String jsGet_pathname() { + return _url.getPath(); + } + + + public void jsSet_pathname( String newPath ) throws SAXException, IOException { + if (!newPath.startsWith( "/" )) newPath = '/' + newPath; + URL newURL = new URL( _url, newPath ); + _window.setLocation( newURL.toExternalForm() ); + } + + + public String jsGet_search() { + return '?' + _url.getQuery(); + } + + + public void jsSet_search( String newSearch ) throws SAXException, IOException { + if (!newSearch.startsWith( "?" )) newSearch = '?' + newSearch; + _window.setLocation( jsGet_protocol() + "//" + jsGet_host() + jsGet_pathname() + newSearch ); + } + + + /** + * Returns the default value of this scriptable object. In this case, it returns simply the URL as a string. + * Note that this method is necessary, since Rhino will only call the toString method directly if there are no + * Rhino methods defined (jsGet_*, jsFunction_*, etc.) + */ + public Object getDefaultValue( Class typeHint ) { + return _url.toExternalForm(); + } + + + public String toString() { + return _url.toExternalForm(); + } + + } + + + static public class Style extends JavaScriptEngine { + + private String _display = "inline"; + private String _visibility = "visible"; + + + public String getClassName() { + return "Style"; + } + + + public String jsGet_display() { + return _display; + } + + + public void jsSet_display( String display ) { + _display = display; + } + + + public String jsGet_visibility() { + return _visibility; + } + + + public void jsSet_visibility( String visibility ) { + _visibility = visibility; + } + } + + + static public class Navigator extends JavaScriptEngine { + + private ClientProperties _clientProperties; + + public String getClassName() { + return "Navigator"; + } + + + void setClientProperties( ClientProperties clientProperties ) { + _clientProperties = clientProperties; + } + + + public String jsGet_appName() { + return _clientProperties.getApplicationName(); + } + + + public String jsGet_appCodeName() { + return _clientProperties.getApplicationCodeName(); + } + + + public String jsGet_appVersion() { + return _clientProperties.getApplicationVersion(); + } + + + public String jsGet_userAgent() { + return _clientProperties.getUserAgent(); + } + + + public String jsGet_platform() { + return _clientProperties.getPlatform(); + } + + + public Object[] jsGet_plugins() { + return new Object[0]; + } + + + public boolean jsFunction_javaEnabled() { + return false; // no support is provided for applets at present + } + + + } + + + static public class Screen extends JavaScriptEngine { + + private ClientProperties _clientProperties; + + + void setClientProperties( ClientProperties clientProperties ) { + _clientProperties = clientProperties; + } + + + public String getClassName() { + return "Screen"; + } + + + public int jsGet_availWidth() { + return _clientProperties.getAvailableScreenWidth(); + } + + + public int jsGet_availHeight() { + return _clientProperties.getAvailHeight(); + } + + + } + + + static public class ElementArray extends ScriptableObject { + + private JavaScriptEngine _contents[] = new HTMLElement[0]; + + + static ElementArray newElementArray( Scriptable parent ) { + try { + return (ElementArray) Context.getCurrentContext().newObject( parent, "ElementArray" ); + } catch (PropertyException e) { + throw new RhinoException( e ); + } catch (NotAFunctionException e) { + throw new RhinoException( e ); + } catch (JavaScriptException e) { + throw new RhinoException( e ); + } + } + + + public ElementArray() { + } + + + void initialize( JavaScriptEngine[] contents ) { + _contents = contents; + } + + + public int jsGet_length() { + return _contents.length; + } + + + public String getClassName() { + return "ElementArray"; + } + + + public Object get( int i, Scriptable scriptable ) { + if (i >= 0 && i < _contents.length) { + return _contents[i]; + } else { + return super.get( i, scriptable ); + } + } + + + public Object get( String name, Scriptable scriptable ) { + for (int i = 0; i < _contents.length; i++) { + JavaScriptEngine content = _contents[ i ]; + if (name.equalsIgnoreCase( content.getID() )) return content; + } + for (int i = 0; i < _contents.length; i++) { + JavaScriptEngine content = _contents[ i ]; + if (name.equalsIgnoreCase( content.getName() )) return content; + } + return super.get( name, scriptable ); + } + + + protected JavaScriptEngine[] getContents() { + return _contents; + } + } + + /** + * HTML Element support for JavaScript + */ + static public class HTMLElement extends JavaScriptEngine { + + private Style _style; + private Document _document; + + + public String getClassName() { + return "HTMLElement"; + } + + + public Document jsGet_document() { + return _document; + } + + + public Style jsGet_style() { + return _style; + } + + /** + * arbitrary attribute access + * @param attributeName + * @return + */ + public Object jsFunction_getAttribute(String attributeName) { + return _scriptable.get(attributeName); + } + + void initialize( JavaScriptEngine parent, ScriptableDelegate scriptable ) + throws JavaScriptException, NotAFunctionException, PropertyException, SAXException { + super.initialize( parent, scriptable ); + _document = (Document) parent; + _style = (Style) Context.getCurrentContext().newObject( this, "Style" ); + } + + } + + + static public class Image extends HTMLElement { + + public String getClassName() { + return "Image"; + } + } + + + static public class Link extends HTMLElement { + + public Document jsGet_document() { + return super.jsGet_document(); + } + + + public String getClassName() { + return "Link"; + } + } + + + static public class Form extends HTMLElement { + + private ElementArray _controls; + + public String getClassName() { + return "Form"; + } + + public String jsGet_name() { + return getDelegate().getName(); + } + + public String jsGet_action() { + return getDelegate().getAction(); + } + + + public void jsSet_action( String action ) { + getDelegate().setAction( action ); + } + + + public Scriptable jsGet_elements() throws PropertyException, NotAFunctionException, JavaScriptException { + if (_controls == null) { + initializeControls(); + } + return _controls; + } + + + public Object jsFunction_getElementsByTagName( String name ) throws SAXException { + return toElementArray( getDelegate().getElementsByTagName( name ) ); + } + + + public void jsFunction_submit() throws IOException, SAXException { + getDelegate().submit(); + } + + + public void jsFunction_reset() throws IOException, SAXException { + getDelegate().reset(); + } + + + private void initializeControls() throws PropertyException, NotAFunctionException, JavaScriptException { + ScriptableDelegate scriptables[] = getDelegate().getElementDelegates(); + Control[] controls = new Control[ scriptables.length ]; + for (int i = 0; i < controls.length; i++) { + controls[ i ] = (Control) toScriptable( scriptables[ i ] ); + } + _controls = (ElementArray) Context.getCurrentContext().newObject( this, "ElementArray" ); + _controls.initialize( controls ); + } + + + private WebForm.Scriptable getDelegate() { + return (WebForm.Scriptable) _scriptable; + } + + } + + + /** + * Javascript support for any control + */ + static public class Control extends JavaScriptEngine { + + private Form _form; + + public String getClassName() { + return "Control"; + } + + public Form jsGet_form() { + return _form; + } + + public void jsFunction_focus() {} + + + public void jsFunction_select() {} + + + /** + * click via javascript + * @throws IOException + * @throws SAXException + */ + public void jsFunction_click() throws IOException, SAXException { + getDelegate().click(); + } + + + private Input getDelegate() { + return (Input) _scriptable; + } + + + /** Support getting value of arbitrary attribute */ + public Object jsFunction_getAttribute( String attributeName ) throws JavaScriptException { + return getDelegate().get( attributeName ); + } + + /** Support getting value of arbitrary attribute */ + public void jsFunction_setAttribute( String attributeName, Object value ) throws JavaScriptException { + getDelegate().setAttribute( attributeName, value ); + } + + /** Support getting value of arbitrary attribute */ + public void jsFunction_removeAttribute( String attributeName ) throws JavaScriptException { + getDelegate().removeAttribute( attributeName ); + } + + /** Allow calling onchange() from within a JavaScript function */ + public void jsFunction_onchange() throws JavaScriptException { + Input myInput=this.getDelegate(); + myInput.sendOnChangeEvent(); + } + + void initialize( JavaScriptEngine parent, ScriptableDelegate scriptable ) + throws JavaScriptException, NotAFunctionException, PropertyException, SAXException { + super.initialize( parent, scriptable ); + if (parent instanceof Form) _form = (Form) parent; + } + + + } + + + static public class Options extends JavaScriptEngine { + + public String getClassName() { + return "Options"; + } + + + public int jsGet_length() { + return getDelegate().getLength(); + } + + + public void jsSet_length( int length ) { + getDelegate().setLength( length ); + } + + + public void put( int i, Scriptable scriptable, Object object ) { + if (object == null) { + getDelegate().put( i, null ); + } else { + if (!(object instanceof Option)) throw new IllegalArgumentException( "May only add an Option to this array" ); + Option option = (Option) object; + getDelegate().put( i, option.getDelegate() ); + } + } + + + private SelectionOptions getDelegate() { + return (SelectionOptions) _scriptable; + } + + + } + + + static public class Option extends JavaScriptEngine { + + public String getClassName() { + return "Option"; + } + + + public void jsConstructor( String text, String value, boolean defaultSelected, boolean selected ) { + _scriptable = WebResponse.newDelegate( "Option" ); + getDelegate().initialize( text, value, defaultSelected, selected ); + } + + + public int jsGet_index() { + return getDelegate().getIndex(); + } + + + public String jsGet_text() { + return getDelegate().getText(); + } + + + public void jsSet_text( String text ) { + getDelegate().setText( text ); + } + + + public String jsGet_value() { + return getDelegate().getValue(); + } + + + public void jsSet_value( String value ) { + getDelegate().setValue( value ); + } + + + public boolean jsGet_selected() { + return getDelegate().isSelected(); + } + + + public void jsSet_selected( boolean selected ) { + getDelegate().setSelected( selected ); + } + + + public boolean jsGet_defaultSelected() { + return getDelegate().isDefaultSelected(); + } + + + SelectionOption getDelegate() { + return (SelectionOption) _scriptable; + } + } + +} + +/** + * special exception for the Rhino Javscript engine + */ +class RhinoException extends RuntimeException { + + private Exception _cause; + + + public RhinoException( Exception cause ) { + _cause = cause; + } + + + public String getMessage() { + return "Rhino exception: " + _cause; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScriptEngineFactory.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScriptEngineFactory.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/JavaScriptEngineFactory.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,102 @@ +package com.meterware.httpunit.javascript; +/******************************************************************************************************************** + * $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.HttpUnitUtils; +import com.meterware.httpunit.WebResponse; +import com.meterware.httpunit.HTMLElement; +import com.meterware.httpunit.scripting.ScriptingEngineFactory; +import com.meterware.httpunit.scripting.ScriptableDelegate; +import com.meterware.httpunit.scripting.ScriptingHandler; + + +/** + * An implementation of the scripting engine factory which selects a Rhino-based implementation of JavaScript. + * + * @author Russell Gold + **/ +public class JavaScriptEngineFactory implements ScriptingEngineFactory { + + public boolean isEnabled() { + try { + Class.forName( "org.mozilla.javascript.Context" ); + return true; + } catch (Exception e) { + System.err.println( "Rhino classes (js.jar) not found - Javascript disabled" ); + return false; + } + } + + + public void associate( WebResponse response ) { + try { + JavaScript.run( response ); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + HttpUnitUtils.handleException(e); + throw new RuntimeException( e.toString() ); + } + } + + + public void load( WebResponse response ) { + try { + JavaScript.load( response ); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException( e.toString() ); + } + } + + + public void setThrowExceptionsOnError( boolean throwExceptions ) { + JavaScript.setThrowExceptionsOnError( throwExceptions ); + } + + + public boolean isThrowExceptionsOnError() { + return JavaScript.isThrowExceptionsOnError(); + } + + + public String[] getErrorMessages() { + return ScriptingEngineImpl.getErrorMessages(); + } + + + public void clearErrorMessages() { + ScriptingEngineImpl.clearErrorMessages(); + } + + + public ScriptingHandler createHandler( HTMLElement elementBase ) { + ScriptableDelegate delegate = elementBase.newScriptable(); + delegate.setScriptEngine( elementBase.getParentDelegate().getScriptEngine( delegate ) ); + return delegate; + } + + + public ScriptingHandler createHandler( WebResponse response ) { + return response.createJavascriptScriptingHandler(); + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/ScriptingEngineImpl.java =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/ScriptingEngineImpl.java (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/javascript/ScriptingEngineImpl.java (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,191 @@ +package com.meterware.httpunit.javascript; +/******************************************************************************************************************** + * $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.mozilla.javascript.*; +import com.meterware.httpunit.scripting.ScriptingEngine; +import com.meterware.httpunit.HttpUnitUtils; +import com.meterware.httpunit.ScriptException; + +import java.util.ArrayList; + + +/** + * + * @author Russell Gold + **/ +public abstract class ScriptingEngineImpl extends ScriptableObject implements ScriptingEngine { + + private final static Object[] NO_ARGS = new Object[0]; + + private static ArrayList _errorMessages = new ArrayList(); + + + static public void clearErrorMessages() { + _errorMessages.clear(); + } + + + static public String[] getErrorMessages() { + return (String[]) _errorMessages.toArray( new String[ _errorMessages.size() ] ); + } + + + /** + * handle Exceptions + * @param e - the exception to handle + * @param badScript - the script that caused the problem + */ + static public void handleScriptException( Exception e, String badScript ) { + final String errorMessage = badScript + " failed: " + e; + if (!(e instanceof EcmaError) && !(e instanceof EvaluatorException)) { + HttpUnitUtils.handleException(e); + throw new RuntimeException( errorMessage ); + } else if (JavaScript.isThrowExceptionsOnError()) { + HttpUnitUtils.handleException(e); + throw new ScriptException( errorMessage ); + } else { + _errorMessages.add( errorMessage ); + } + } + +//--------------------------------------- ScriptingEngine methods ------------------------------------------------------ + + public boolean supportsScriptLanguage( String language ) { + return language == null || language.toLowerCase().startsWith( "javascript" ); + } + + + /** + * run the given script + * @param language - the language of the script + * @param script - the script to run + */ + public String runScript( String language, String script ) { + if (!supportsScriptLanguage( language )) return ""; + try { + script = script.trim(); + if (script.startsWith( "" )) script = script.substring( 0, script.lastIndexOf( "-->" )); + } + Context context = Context.enter(); + context.initStandardObjects( null ); + context.evaluateString( this, script, "httpunit", 0, null ); + return getDocumentWriteBuffer(); + } catch (Exception e) { + handleScriptException( e, "Script '" + script + "'" ); + return ""; + } finally { + discardDocumentWriteBuffer(); + Context.exit(); + } + } + + + /** + * 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); + } + + + /** + * 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 + */ + public boolean doEventScript( String eventScript ) { + if (eventScript.length() == 0) { + return true; + } else { + try { + Context context = Context.enter(); + context.initStandardObjects( null ); + context.setOptimizationLevel( -1 ); + // wrap the eventScript into a function + Function f = context.compileFunction( this, "function x() { " + eventScript + "}", "httpunit", 0, null ); + // call the function with no arguments + Object result = f.call( context, this, this, NO_ARGS ); + // return the result of the function or false if it is not boolean + return (!(result instanceof Boolean)) || ((Boolean) result).booleanValue(); + } catch (Exception e) { + handleScriptException( e, "Event '" + eventScript + "'" ); + return false; + } finally { + Context.exit(); + } + } // if + } + + /** + * get the event Handler script for the event e.g. onchange, onmousedown, onclick, onmouseup + * execute the script if it's assigned by calling doEvent for the script + * @param eventName + * @return + */ + public boolean handleEvent(String eventName) { + throw new RuntimeException("pseudo - abstract handleEvent called "); + } + + /** + * Evaluates the specified string as JavaScript. Will return null if the script has no return value. + * @param expression - the expression to evaluate + */ + public Object evaluateExpression( String expression ) { + try { + Context context = Context.enter(); + context.initStandardObjects( null ); + Object result = context.evaluateString( this, expression, "httpunit", 0, null ); + return (result == null || result instanceof Undefined) ? null : result; + } catch (Exception e) { + handleScriptException( e, "URL '" + expression + "'" ); + return null; + } finally { + Context.exit(); + } + } + +//------------------------------------------ protected methods --------------------------------------------------------- + + protected String getDocumentWriteBuffer() { + throw new IllegalStateException( "may not run runScript() from " + getClass() ); + } + + protected void discardDocumentWriteBuffer() { + throw new IllegalStateException( "may not run runScript() from " + getClass() ); + } + + private String withoutFirstLine( String script ) { + for (int i=0; i < script.length(); i++) { + if (isLineTerminator( script.charAt(i) )) return script.substring( i ).trim(); + } + return ""; + } + + private boolean isLineTerminator( char c ) { + return c == 0x0A || c == 0x0D; + } +} Index: 3rdParty_sources/httpunit/com/meterware/httpunit/package.html =================================================================== diff -u --- 3rdParty_sources/httpunit/com/meterware/httpunit/package.html (revision 0) +++ 3rdParty_sources/httpunit/com/meterware/httpunit/package.html (revision 8e1ed196bfc1c28860729d8b0a23878bb3ecf1e7) @@ -0,0 +1,63 @@ + +Classes for testing http server systems. Each test session should begin by creating a +{@link com.meterware.httpunit.WebConversation WebConversation} to which it should submit an +initial {@link com.meterware.httpunit.GetMethodWebRequest http request} using the +{@link com.meterware.httpunit.WebConversation#getResponse getResponse} method. With each +subsequent step, +it will typically examine the response either textually or as a DOM, and create new +requests based on either submitting a form or clicking on a link. + +

Installation

+The package depends on a number of external jar files, provided in the jar directory: +
nekohtml.jar
The NekoHTML parser, +used to convert raw HTML into an XML DOM. This is required for handling HTML.
+
js.jar
The Rhino JavaScript interpreter, required for any JavaScript processing.
+
xmlParserAPIs.jar
The interfaces for a W3-compliant XML parser. Required for interpreting either HTML or XML pages.
+
xercesImpl.jar
The Xerces 2 implementation of an XML parser. +NekoHTML requires this implementation. +
servlet.jar
The APIs and common classes for the Java Servlet 1.3 standard. Required for use with ServletUnit.
+
junit.jar
JUnit, the unit test framework. Used to test HttpUnit and +recommended for writing tests that use HttpUnit.
+
tidy.jar
JTidy, an alternate HTML parser/validator. +JTidy is a lot pickier about HTML structure than NekoHTML, and uses its own implementation of the DOM classes, rather than using those +found in the xerces jar. Some JavaScript features, such as 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