jakarta-watchdog-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rlu...@apache.org
Subject cvs commit: jakarta-watchdog-4.0/src/tools/org/apache/tomcat/task GTest.java
Date Tue, 18 Dec 2001 02:31:01 GMT
rlubke      01/12/17 18:31:01

  Modified:    src/tools/org/apache/tomcat/task GTest.java
  Log:
  Cleaned up/enhanced GTest processing logic.
  Added the following functionality:
   - The ability to specify headers that shouldn't
     be found in the server's response.
   - The ability to handle response headers
     in the format of:
        TestHeader: 2
        TestHeader: 3
         -or-
        TestHeader: 2,3
   - If using strong comparison ( exactMatch="true" in gtest target )
     and a byte mismatch occurs, a hex dump of the server's response
     and the goldenfile are displayed to the user.
  
  Corrected the following:
   - HTTP header fields are now compared so that case is ignored while
     fields are compared in a case sensitive manner.
  
  Still to do:
   - Add logic so that a gtest target can be configured to expect
     multiple headers from the server -> expectHeader="name:val|name2:val2"
   - Continue cleanup where needed.
  
  Revision  Changes    Path
  1.4       +1206 -539 jakarta-watchdog-4.0/src/tools/org/apache/tomcat/task/GTest.java
  
  Index: GTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-watchdog-4.0/src/tools/org/apache/tomcat/task/GTest.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- GTest.java	2001/09/28 04:09:56	1.3
  +++ GTest.java	2001/12/18 02:31:01	1.4
  @@ -1,8 +1,8 @@
   /**
  - * 
  - * @Author Costin, Ramesh.Mandava
  - *
  - */
  +* 
  +* @Author Costin, Ramesh.Mandava
  +*
  +*/
   package org.apache.tomcat.task;
   
   import java.net.*;
  @@ -14,594 +14,999 @@
   
   
   // derived from Jsp
  +
   public class GTest extends Task {
  -    String prefix="http://localhost:8080/test";
  -    String host="localhost";
  -    int port=8080;
  -    int debug=0;
  +
  +    private static final String ZEROS        = "00000000";
  +    private static final int SHORTPADSIZE    = 4;
  +    private static final int BYTEPADSIZE     = 2;
  +    private static final int CARRIAGE_RETURN = 13;
  +    private static final int LINE_FEED       = 10;
  +
  +    String prefix = "http";
  +    String host = "localhost";
  +    int port = 8080;
  +    int debug = 0;
   
  -    String description="No description";
  +    String description = "No description";
   
       String request;
  -    Hashtable requestHeaders;
  +    HashMap requestHeaders = new HashMap();
       String content;
  -    
  +
       // Expected response
  -    boolean magnitude=true;
  -    boolean exactMatch=false;
  +    boolean magnitude = true;
  +    boolean exactMatch = false;
  +
  +    // expect a response body
  +    boolean expectResponseBody = true;
  +
       // Match the body against a golden file
       String goldenFile;
       // Match the body against a string
       String responseMatch;
       // the response should include the following headers
  -    Hashtable expectHeaders;
  +    HashMap expectHeaders = new HashMap();
  +
  +    // Headers that should not be found in response
  +    HashMap unexpectedHeaders = new HashMap();
  +
       // Match request line
  -    String returnCode="";
  +    String returnCode = "";
  +    String returnCodeMsg = "";
   
       // Actual response
       String responseLine;
  -    String responseBody;
  -    Hashtable headers;
  +    byte[] responseBody;
  +    HashMap headers;
   
   
       // For Report generation
  -	static String resultFileName=null;
  -	static FileOutputStream resultOut=null;
  -	boolean firstTask=false;
  -	boolean lastTask=false;
  -	String expectedString;
  -	String actualString;
  -
  -	String testName;
  -	String assertion;
  -	String testStrategy;
  -
  -     // For Session Tracking
  -	static	Hashtable sessionHash;
  -	static  Hashtable cookieHash;
  -
  -	String testSession;
  -	Vector cookieVector;
  -	URL requestURL;
  -	CookieController cookieController ; 
  +    static String resultFileName = null;
  +    static FileOutputStream resultOut = null;
  +    boolean firstTask = false;
  +    boolean lastTask = false;
  +    String expectedString;
  +    String actualString;
  +
  +    String testName;
  +    String assertion;
  +    String testStrategy;
  +
  +    // For Session Tracking
  +    static	Hashtable sessionHash;
  +    static Hashtable cookieHash;
  +
  +    String testSession;
  +    Vector cookieVector;
  +    URL requestURL;
  +    CookieController cookieController ;
   
  +    /**
  +     * Creates a new <code>GTest</code> instance.
  +     *
  +     */
  +    public GTest() {}
   
  +    /**
  +     * <code>setTestSession</code> adds a 
  +     * CookieController for the value of sessionName
  +     *
  +     * @param sessionName a <code>String</code> value
  +     */
  +    public void setTestSession( String sessionName ) {
  +        testSession = sessionName;
   
  +        if ( sessionHash == null ) {
  +            sessionHash = new Hashtable();
  +        } else if ( sessionHash.get( sessionName ) == null ) {
  +            sessionHash.put ( sessionName, new CookieController() );
  +        }
  +    }
   
  -	public void setTestSession( String sessionName )
  -	{
  -		testSession= sessionName;
  -		if ( sessionHash==null)
  -		{
  -			sessionHash= new Hashtable();
  -		}
  -		else if ( sessionHash.get( sessionName) == null )
  -		{
  -			sessionHash.put ( sessionName, new CookieController() );
  -		}
  -	}
  -	
  -	public void setTestName ( String tn )
  -		throws IOException
  -	{
  -		testName=tn;
  -	}
  +    /**
  +     * <code>setTestName</code> sets the current test name.
  +     *
  +     * @param tn current testname.
  +     */
  +    public void setTestName ( String tn ) {
  +        testName = tn;
  +    }
   
  -	public void setAssertion ( String assertion )
  -		throws IOException
  -	{
  -		this.assertion = assertion;
  -	}
  -	public void setTestStrategy ( String strategy )
  -		throws IOException
  -	{
  -		testStrategy = strategy;
  -	}
  -	
  -	public String getTestName( )
  -	{
  -		return testName;
  -	}
  -	public String getAssertion( )
  -	{
  -		return assertion;
  -	}
  -	public String getTestStrategy( )
  -	{
  -		return testStrategy;
  -	}
  +    /**
  +     * <code>setAssertion</code> sets the assertion text
  +     * for the current test.
  +     *
  +     * @param assertion assertion text
  +     */
  +    public void setAssertion ( String assertion ) {
  +        this.assertion = assertion;
  +    }
   
  -	public void setResultFileName( String fileName )
  -		throws IOException
  -	{
  -	  if ( firstTask )
  -	  {
  -		resultFileName = fileName;
  -		File passedFile= new File( fileName );
  -		System.out.println("Full Path of Result File-> " + passedFile.getAbsolutePath() );
  -		resultOut = new FileOutputStream( passedFile);
  -		if ( resultOut == null )
  -		{
  -			System.out.println("ERROR: Not able to create FileOutputStream for result");
  -		}
  -		else
  -		{
  -			resultOut.write("<root>\n".getBytes() );
  -		}
  -	  }
  -	  
  -	}
  -	public void setFirstTask( boolean val )
  -	{
  -		firstTask=val;
  -	}
  -	public void setLastTask ( boolean val )
  -		throws IOException
  -	{
  -		lastTask=val;
  -			
  -	}
  -		
  +    /**
  +     * <code>setTestStrategy</code> sets the test strategy
  +     * for the current test.
  +     *
  +     * @param strategy test strategy text
  +     */
  +    public void setTestStrategy ( String strategy ) {
  +        testStrategy = strategy;
  +    }
   
  -    public GTest() {
  +    /**
  +     * <code>getTestName</code> returns the current 
  +     * test name.
  +     *
  +     * @return a <code>String</code> value
  +     */
  +    public String getTestName( ) {
  +        return testName;
       }
  -    
  -    
  -    public void setPrefix(String prefix) {
  -	this.prefix=prefix;
  +
  +    /**
  +     * <code>getAssertion</code> returns the current
  +     * assertion text.
  +     *
  +     * @return a <code>String</code> value
  +     */
  +    public String getAssertion( ) {
  +        return assertion;
       }
  -    
  -    public void setHost(String h) {
  -	this.host=h;
  +
  +    /**
  +     * <code>getTestStrategy</code> returns the current
  +     * test strategy test.
  +     *
  +     * @return a <code>String</code> value
  +     */
  +    public String getTestStrategy( ) {
  +        return testStrategy;
       }
  -    
  -    public void setPort(String portS) {
  -	this.port=Integer.valueOf( portS).intValue();
  +
  +    /**
  +     * <code>setResultFileName</code> allows the user
  +     * to set the filename in which to write test results
  +     * to.
  +     *
  +     * @param fileName result filename
  +     * @exception IOException if an error occurs
  +     */
  +    public void setResultFileName( String fileName )
  +    throws IOException {
  +        // if ( firstTask ) {
  +            resultFileName = fileName;
  +            File passedFile = new File( fileName );
  +            System.out.println( "Full Path of Result File-> " + passedFile.getAbsolutePath() );
  +            resultOut = new FileOutputStream( passedFile );
  +
  +            if ( resultOut == null ) {
  +                System.out.println( "ERROR: Not able to create FileOutputStream for result" );
  +            } else {
  +                resultOut.write( "<root>\n".getBytes() );
  +            }
  +            // }
       }
   
  -    public void setExactMatch(String exact) {
  -	exactMatch=Boolean.valueOf( exact ).booleanValue();
  +    /*
  +     *public void setFirstTask( boolean val ) {
  +     *   firstTask = val;
  +     *}
  +     *
  +     *public void setLastTask ( boolean val )
  +     *throws IOException {
  +     *   lastTask = val;
  +     *
  +     *}
  +     */
  +
  +    /**
  +     * <code>setPrefix</code> sets the protocol
  +     * prefix.  Defaults to "http"
  +     *
  +     * @param prefix Either http or https
  +     */
  +    public void setPrefix( String prefix ) {
  +        this.prefix = prefix;
       }
   
  -    /** Set the port as int - different name to avoid confusing ant
  +    /**
  +     * <code>setHost</code> sets hostname where
  +     * the target server is running. Defaults to
  +     * "localhost"
  +     *
  +     * @param h a <code>String</code> value
        */
  -    public void setPortInt(int i) {
  -	this.port=i;
  +    public void setHost( String h ) {
  +        this.host = h;
       }
   
  -    /** Description should be in <test description=""/>
  +    /**
  +     * <code>setPort</code> sets the port
  +     * that the target server is listening on.
  +     * Defaults to "8080"
  +     *
  +     * @param portS a <code>String</code> value
        */
  -    public String getDescription() {
  -	return description;
  +    public void setPort( String portS ) {
  +        this.port = Integer.valueOf( portS ).intValue();
       }
   
  -    public void setDescription(String description) {
  -	this.description=description;
  +    /**
  +     * <code>setExactMatch</code> determines if a
  +     * byte-by-byte comparsion is made of the server's
  +     * response and the test's goldenFile, or if
  +     * a token comparison is made.  By default, only
  +     * a token comparison is made ("false").
  +     *
  +     * @param exact a <code>String</code> value
  +     */
  +    public void setExactMatch( String exact ) {
  +        exactMatch = Boolean.valueOf( exact ).booleanValue();
       }
   
  -    public void setContent(String s) {
  -	this.content=s;
  +    /**
  +     * <code>setContent</code> String value upon which
  +     * the request header Content-Length is based upon.
  +     *
  +     * @param s a <code>String</code> value
  +     */
  +    public void setContent( String s ) {
  +        this.content = s;
       }
   
  +    /**
  +     * <code>setDebug</code> enables debug output.
  +     * By default, this is disabled ( value of "0" ).
  +     *
  +     * @param debugS a <code>String</code> value
  +     */
       public void setDebug( String debugS ) {
  -	debug=Integer.valueOf( debugS).intValue();
  +        debug = Integer.valueOf( debugS ).intValue();
       }
   
  +    /**
  +     * <code>setMagnitude</code> Expected return
  +     * value of the test execution.
  +     * Defaults to "true"
  +     *
  +     * @param magnitudeS a <code>String</code> value
  +     */
       public void setMagnitude( String magnitudeS ) {
  -        magnitude = Boolean.valueOf(magnitudeS).booleanValue();   
  +        magnitude = Boolean.valueOf( magnitudeS ).booleanValue();
       }
   
  +    /**
  +     * <code>setGoldenFile</code> Sets the goldenfile
  +     * that will be used to validate the server's response.
  +     *
  +     * @param s fully qualified path and filename
  +     */
       public void setGoldenFile( String s ) {
  -	this.goldenFile=s;
  +        this.goldenFile = s;
  +    }
  +
  +    /**
  +     * <code>setExpectResponseBody</code> sets a flag
  +     * to indicate if a response body is expected from the
  +     * server or not
  +     *
  +     * @param b a <code>boolean</code> value
  +     */
  +    public void setExpectResponseBody( boolean b ) {
  +        this.expectResponseBody = b;
       }
   
  -	//Ramesh
  +    /**
  +     * <code>setExpectHeaders</code> Configures GTest
  +     * to look for the header passed in the server's
  +     * response.  
  +     *
  +     * @param s a <code>String</code> value in the 
  +     *          format of <header-field>:<header-value>
  +     */
       public void setExpectHeaders( String s ) {
  -	this.expectHeaders=new Hashtable();
  -	getHeaderDetails( s, expectHeaders );
  +        this.expectHeaders = new HashMap();
  +        getHeaderDetails( s, expectHeaders, false );
  +    }
   
  -	//parseHeader( s, expectHeaders );
  +    /**
  +     * <code>setUnexpectedHeaders</code> Configures GTest
  +     * to look for the header passed to validate that it
  +     * doesn't exist in the server's response.
  +     *
  +     * @param s a <code>String</code> value in the
  +     *          format of <header-field>:<header-value>
  +     */
  +    public void setUnexpectedHeaders( String s ) {
  +        this.unexpectedHeaders = new HashMap();
  +        getHeaderDetails( s, unexpectedHeaders, false );
       }
   
  +    /**
  +     * <code>setResponseMatch</code> Match the
  +     * passed value in the server's response.
  +     *
  +     * @param s a <code>String</code> value
  +     */
       public void setResponseMatch( String s ) {
  -	this.responseMatch=s;
  +        this.responseMatch = s;
       }
   
  +    /**
  +     * <code>setRequest</code> Sets the HTTP/HTTPS
  +     * request to be sent to the target server
  +     * Ex.
  +     *    GET /servlet_path/val HTTP/1.0
  +     *
  +     * @param s a <code>String</code> value in the form
  +     *          of METHOD PATH HTTP_VERSION
  +     * @exception Exception if an error occurs
  +     */
       public void setRequest ( String s ) throws Exception {
  -	this.request=s;
  -	String addressString = request.substring( request.indexOf("/"), request.indexOf("HTTP") ).trim();
  -	if ( addressString.indexOf("?") > -1 )
  -	{
  -		addressString = addressString.substring(0, addressString.indexOf("?") ) ;
  -	} 	
  -	requestURL= new URL("http", host, port, addressString);
  +        this.request = s;
  +        String addressString = request.substring( request.indexOf( "/" ), request.indexOf( "HTTP" ) ).trim();
  +
  +        if ( addressString.indexOf( "?" ) > -1 ) {
  +            addressString = addressString.substring( 0, addressString.indexOf( "?" ) ) ;
  +        }
  +
  +        requestURL = new URL( "http", host, port, addressString );
       }
  -    
  -   public void setReturnCode( String s ) {
  -	this.returnCode=s;
  +
  +    /**
  +     * <code>setReturnCode</code> Sets the expected
  +     * return code from the server's response.
  +     *
  +     * @param code a valid HTTP response status code
  +     */
  +    public void setReturnCode( String code ) {
  +        this.returnCode = code;
       }
   
  -   public void setHeaders( String s ) {
  -       requestHeaders=new Hashtable();
  -       parseHeader( s, requestHeaders );
  +    /**
  +     * Describe <code>setReturnCode</code> Sets the expected
  +     * return code and message to be found in the server's
  +     * response.
  +     *
  +     * @param code a valid HTTP resonse status code
  +     * @param message a <code>String</code> value
  +     */
  +    public void setReturnCode( String code, String message ) {
  +        this.returnCode = code;
  +        this.returnCodeMsg = message;
       }
   
  -	//Ramesh
  +    /**
  +     * <code>setRequestHeaders</code> Configures the request
  +     * headers GTest should send to the target server.
  +     *
  +     * @param s a <code>String</code> value in for format
  +     *          of <field-name>:<field-value>
  +     */
       public void setRequestHeaders( String s ) {
  -       requestHeaders=new Hashtable();
  -       getHeaderDetails( s, requestHeaders );
  -       if( debug>0) 
  -       {
  -	       System.out.println("Request Headers -> " );
  -	       Enumeration reqHeaderEnum = requestHeaders.keys();
  -	       while ( reqHeaderEnum.hasMoreElements() )
  -	       {
  -			String headerKey = (String)reqHeaderEnum.nextElement();
  -			System.out.println( headerKey + "::" + requestHeaders.get(headerKey) ); 
  -		}
  -	}
  -	
  -	   //parseHeader( s, requestHeaders );
  +        requestHeaders = new HashMap();
  +        getHeaderDetails( s, requestHeaders, true );
       }
  -    
  +
  +    /**
  +     * <code>execute</code> Executes the test.
  +     *
  +     * @exception BuildException if an error occurs
  +     */
       public void execute() throws BuildException {
  -	
  -	try {
   
  -	    if ( resultOut != null )
  -	    {
  -		resultOut.write("<test>".getBytes() );
  -		resultOut.write( ("\n<testName>"+ testName + "</testName>").getBytes() );
  -		resultOut.write( ("\n<assertion>"+ assertion + "</assertion>").getBytes() );
  -		resultOut.write( ("\n<testStrategy>"+ testStrategy + "</testStrategy>\n").getBytes() );
  -	    }
  -	
  -	    dispatch(request, requestHeaders);
  -	    //dispatch(request, null);
  +        try {
   
  -	    boolean result=checkResponse( magnitude );
  -	    if(result) {
  -		if ( resultOut != null )
  -		{
  -			resultOut.write("<result>PASS</result>\n".getBytes() );
  -		}
  +            if ( resultOut != null ) {
  +                resultOut.write( "<test>".getBytes() );
  +                resultOut.write( ( "\n<testName>" + testName + "</testName>" ).getBytes() );
  +                resultOut.write( ( "\n<assertion>" + assertion + "</assertion>" ).getBytes() );
  +                resultOut.write( ( "\n<testStrategy>" + testStrategy + "</testStrategy>\n" ).getBytes() );
  +            }
   
  -		if(  "No description".equals( description )) {
  -		    System.out.println("OK " + request );
  -		}
  -		else
  -		    System.out.println("OK " + description + " (" + request + ")");
  -	    } else {
  -		if ( resultOut != null )
  -		{
  -			resultOut.write("<result>FAIL</result>\n".getBytes() );
  -		}
  +            dispatch( request, requestHeaders );
  +            //dispatch(request, null);
   
  -		if(  "No description".equals( description )) {
  -		    System.out.println("FAIL " + request );
  -		} else
  -		    System.out.println("FAIL " + description + " (" + request + ")" );
  -	    }
  -	   
  -            if ( resultOut != null )
  -	    { 
  -		resultOut.write("</test>\n".getBytes() );
  -	    	if ( lastTask== true)
  -	    	{
  -			resultOut.write("</root>\n".getBytes() );
  -			resultOut.close();
  -	    	}
  -	    }
  +            boolean result = checkResponse( magnitude );
   
  -	} catch(Exception ex ) {
  -	    if(  "No description".equals( description )) {
  -		System.out.println("FAIL " + request );
  -	    } else
  -		System.out.println("FAIL " + description + " (" + request + ")" );
  -	    ex.printStackTrace();
  -	}
  +            if ( result ) {
  +                if ( resultOut != null ) {
  +                    resultOut.write( "<result>PASS</result>\n".getBytes() );
  +                }
  +
  +                if ( "No description".equals( description ) ) {
  +                    System.out.println( " OK " + request );
  +                } else
  +                    System.out.println( " OK " + description + " (" + request + ")" );
  +            } else {
  +                if ( resultOut != null ) {
  +                    resultOut.write( "<result>FAIL</result>\n".getBytes() );
  +                }
  +
  +                if ( "No description".equals( description ) ) {
  +                    System.out.println( " FAIL " + request );
  +                } else
  +                    System.out.println( " FAIL " + description + " (" + request + ")" );
  +            }
  +
  +            if ( resultOut != null ) {
  +                resultOut.write( "</test>\n".getBytes() );
  +
  +                if ( lastTask == true ) {
  +                    resultOut.write( "</root>\n".getBytes() );
  +                    resultOut.close();
  +                }
  +            }
  +
  +        } catch ( Exception ex ) {
  +            if ( "No description".equals( description ) ) {
  +                System.out.println( " FAIL " + request );
  +            } else
  +                System.out.println( " FAIL " + description + " (" + request + ")" );
  +
  +            ex.printStackTrace();
  +        }
       }
   
  -    private boolean checkResponse(boolean testCondition)
  -	throws Exception
  -    {
  +    /**
  +     * <code>checkResponse</code> Executes various response
  +     * checking mechanisms against the server's response.
  +     * Checks include:
  +     * <ul>
  +     *    <li>expected headers
  +     *    <li>unexpected headers
  +     *    <li>return codes and messages in the Status-Line
  +     *    <li>response body comparison againt a goldenfile
  +     * </ul>
  +     *
  +     * @param testCondition a <code>boolean</code> value
  +     * @return a <code>boolean</code> value
  +     * @exception Exception if an error occurs
  +     */
  +    private boolean checkResponse( boolean testCondition )
  +    throws Exception {
           boolean responseStatus = true;
  -	
  -	// If returnCode doesn't match
  -	if( request.indexOf( "HTTP/1." ) > -1) {
  -	    boolean match= ( responseLine!=null && responseLine.indexOf(returnCode) > -1);
  -	    if( match != testCondition ) {
  -				responseStatus = false;
  -				System.out.println("ERROR in: " + request);
  -				System.out.println("    Expecting: " + returnCode );
  -				System.out.println("    Got      : " + responseLine);
  -				if ( resultOut != null )
  -				{
  -					expectedString = "<expectedReturnCode>" + returnCode + "</expectedReturnCode>\n";
  -					actualString = "<actualReturnCode>"+ responseLine + "</actualReturnCode>\n";
  -					resultOut.write(expectedString.getBytes() );
  -					resultOut.write(actualString.getBytes() );
  +	boolean match = false;
  +
  +	if ( responseLine != null ) {
  +        // If returnCode doesn't match
  +	    if ( responseLine.indexOf( "HTTP/1." ) > -1 ) {
   		
  -	    			}
  -	    }
  -	}
  +		if ( !returnCode.equals( "" ) ) {
  +		    boolean resCode = ( responseLine.indexOf( returnCode ) > -1 );
  +		    boolean resMsg  = ( responseLine.indexOf( returnCodeMsg ) > -1 );
   
  -	if( expectHeaders != null ) {
  -	    // Check if we got the expected headers
  -	    if(headers==null) {
  -		System.out.println("ERROR no response header, expecting header");
  -	    }
  -	    Enumeration e=expectHeaders.keys();
  -	    while( e.hasMoreElements()) {
  -		String key=(String)e.nextElement();
  -		String value=(String)expectHeaders.get(key);
  -		String respValue=(String)headers.get(key);
  -		if( respValue==null || respValue.indexOf( value ) <0 ) {
  -		    System.out.println("ERROR expecting header " + key + ":" +
  -				       value + " GOT: " + respValue+ " HEADERS(" + headers + ")");
  -			if ( resultOut != null )
  -			{
  -				expectedString = "<expectedHeader>" + key + ":"+ value + "</expectedHeader>\n";
  -				actualString = "<actualHeader>"+ key + ":" + respValue + "</actualHeader>\n";
  -				resultOut.write(expectedString.getBytes() );
  -				resultOut.write(actualString.getBytes() );
  -	
  +		    if ( returnCodeMsg.equals( "" ) ) {
  +			match = resCode;
  +		    } else {
  +			match = ( resCode && resMsg );
  +		    }
  +
  +		    if ( match != testCondition ) {
  +			responseStatus = false;
  +			System.out.println( " Error in: " + request );
  +			System.out.println( "    Expected Status-Line with one or all of the following values:" );
  +			System.out.println( "    Status-Code: " + returnCode );
  +			System.out.println( "    Reason-Phrase: " + returnCodeMsg );
  +			System.out.println( "    Received: " + responseLine );
  +
  +			if ( resultOut != null ) {
  +			    String expectedStatusCode = "<expectedStatusCode>" + returnCode + "</expectedReturnCode>\n";
  +			    String expectedReasonPhrase = "<expectedReasonPhrase>" + returnCodeMsg + "</expectedReasonPhrase>";
  +			    actualString = "<actualStatusLine>" + responseLine + "</actualStatusLine>\n";
  +			    resultOut.write( expectedStatusCode.getBytes() );
  +			    resultOut.write( expectedReasonPhrase.getBytes() );
  +			    resultOut.write( actualString.getBytes() );
   			}
  -		    
  -		    return false;
  +		    } else {
  +			if ( debug > 0 ) {
  +			    System.out.println( " Expected values found in Status-Line" );
  +			}
  +		    }
   		}
  +	    } else {
  +		responseStatus = false;
  +		System.out.println( "  Error:  Received invalid HTTP version in response header from target Server" );
  +		System.out.println( "         Target server must support HTTP 1.0 or HTTP 1.1" );
  +		System.out.println( "         Response from server: " + responseLine );
   	    }
  -
  +	} else {
  +	    responseStatus = false;
  +	    System.out.println( " Error in: " + request );
  +	    System.out.println( "        Expecting response from server, received null" );
   	}
  -	
  -	if( responseMatch != null ) {
  -	    // check if we got the string we wanted
  -	    if( responseBody == null ) {
  -		System.out.println("ERROR: got no response, expecting " + responseMatch);
  -		return false;
  +
  +	/* 
  +	 * Check for headers the test expects to be in the server's response
  +	 */
  +
  +	// Duplicate set of response headers
  +	HashMap copiedHeaders = cloneHeaders( headers );
  +
  +	// used for error reporting
  +	String currentHeaderField = null;
  +	String currentHeaderValue = null;
  +
  +        if ( !expectHeaders.isEmpty() ) {
  +	    boolean found = false;
  +	    String expHeader = null;
  +
  +            if ( debug > 0 ) {
  +		System.out.println( " Looking for expected response headers..." );
   	    }
  -	    if( responseBody.indexOf( responseMatch ) < 0) {
  -		System.out.println("ERROR: expecting match on " + responseMatch);
  -		System.out.println("GOT: " );
  -		System.out.println(responseBody );
  +
  +	    if ( !headers.isEmpty() ) {
  +		Iterator expectIterator = expectHeaders.keySet().iterator();
  +                while ( expectIterator.hasNext() ) {
  +                    found = false;
  +                    String expFieldName = (String) expectIterator.next();
  +                    currentHeaderField = expFieldName;
  +                    ArrayList expectValues = (ArrayList) expectHeaders.get( expFieldName );
  +                    Iterator headersIterator = copiedHeaders.keySet().iterator();
  +
  +                    while( headersIterator.hasNext() ) {
  +                        String headerFieldName = (String) headersIterator.next();
  +                        ArrayList headerValues = (ArrayList) copiedHeaders.get( headerFieldName );
  +              
  +                        // compare field names and values in an HTTP 1.x compliant fashion
  +                        if ( ( headerFieldName.equalsIgnoreCase( expFieldName ) ) ) {
  +                            int hSize = headerValues.size();
  +                            int eSize = expectValues.size();
  +
  +                            // number of expected headers found in server response
  +                            int numberFound = 0;
  +             
  +                            for ( int i = 0; i < eSize; i++ ) {
  +                                currentHeaderValue = (String) expectValues.get( i );
  +
  +                                if ( headerValues.contains( currentHeaderValue ) ) {
  +                                    numberFound++;
  +                                    headerValues.remove( headerValues.indexOf( currentHeaderValue ) );
  +                                }
  +                            }
  +                            if ( numberFound == eSize ) {
  +                                found = true;
  +                            }
  +                        }
  +                    }
  +                    if ( !found ) {
  +                        /*
  +                         * Expected headers not found in server response.
  +                         * Break the processing loop.
  +                         */
  +                        break;
  +                    }
  +                }
  +            }
  +
  +	    if ( !found ) {
  +		StringBuffer actualBuffer = new StringBuffer( 128 );
  +                System.out.println( " Unable to find the expected header: '" + currentHeaderField + ": " + currentHeaderValue + "' in the server's response." );
  +		if ( resultOut != null ) {
  +		    expectedString = "<expectedHeader>" + currentHeaderField + ": " + currentHeaderValue + "</expectedHeader>\n";
  +		}
  +                if ( !headers.isEmpty() ) {
  +                    System.out.println( " The following headers were received: " );
  +                    Iterator iter = headers.keySet().iterator();
  +                    while ( iter.hasNext() ) {
  +                        String headerName = (String) iter.next();
  +                        ArrayList vals = (ArrayList) headers.get( headerName );
  +                        String[] val = (String[]) vals.toArray( new String[ vals.size() ] );
  +                        for ( int i = 0; i < val.length; i++ ) {
  +                            System.out.println( "\tHEADER -> " + headerName + ": " + val[ i ] );
  +			    if ( resultOut != null ) {
  +				actualBuffer.append( "<actualHeader>" + headerName + ": " + val[ i ] + "</actualHeader>\n" );
  +			    }
  +                        }
  +                    }
  +		    if ( resultOut != null ) {
  +			resultOut.write( expectedString.getBytes() );
  +			resultOut.write( actualBuffer.toString().getBytes() );
  +		    }
  +                }
  +                return false;
  +            }
  +        }
  +
  +	/*
  +         * Check to see if we're looking for unexpected headers.
  +         * If we are, compare the values in the unexectedHeaders
  +         * ArrayList against the headers from the server response.
  +         * if the unexpected header is found, then return false.
  +         */
  +
  +        if ( !unexpectedHeaders.isEmpty() ) {
  +            boolean found = false;
  +            String unExpHeader = null;
  +	    if ( debug > 0 ) {
  +		System.out.println( " looking for unexpected headers..." );
   	    }
  +
  +            // Check if we got any unexpected headers
  +
  +            if ( !copiedHeaders.isEmpty() ) {
  +                Iterator unexpectedIterator = unexpectedHeaders.keySet().iterator();
  +                while ( unexpectedIterator.hasNext() ) {
  +                    found = false;
  +                    String unexpectedFieldName = (String) unexpectedIterator.next();
  +                    ArrayList unexpectedValues = (ArrayList) unexpectedHeaders.get( unexpectedFieldName );
  +                    Iterator headersIterator = copiedHeaders.keySet().iterator();
  +
  +                    while ( headersIterator.hasNext() ) {
  +                        String headerFieldName = (String) headersIterator.next();
  +                        ArrayList headerValues = (ArrayList) copiedHeaders.get( headerFieldName );
  +                        
  +                        // compare field names and values in an HTTP 1.x compliant fashion
  +                        if ( ( headerFieldName.equalsIgnoreCase( unexpectedFieldName ) ) ) {
  +                            int hSize = headerValues.size();
  +                            int eSize = unexpectedValues.size();
  +                            int numberFound = 0;
  +                            for ( int i = 0; i < eSize; i++ ) {
  +                                if ( headerValues.contains( unexpectedValues.get( i ) ) ) {
  +                                    numberFound++;
  +                                    headerValues.remove( headerValues.indexOf( headerFieldName ) );
  +                                }
  +                            }
  +                            if ( numberFound == eSize ) {
  +                                found = true;
  +                            }
  +                        }
  +                    }
  +                    if ( !found ) {
  +                        /*
  +                         * Expected headers not found in server response.
  +                         * Break the processing loop.
  +                         */
  +                        break;
  +                    }
  +                }
  +            }
  +
  +            if ( found ) {
  +                System.out.println( " Unexpected header received from server: " + unExpHeader );
  +                return false;
  +            }
   	}
   
  -	// compare the body
  -	if( goldenFile==null) return responseStatus;
  -	// Get the expected result from the "golden" file.
  -	StringBuffer expResult = getExpectedResult();
  -	
  -	// Compare the results and set the status
  -	boolean cmp=true;
  -	
  -	if(exactMatch)
  -	    cmp=compare(responseBody, expResult.toString() );
  -	else
  -	    cmp=compareWeek( responseBody, expResult.toString());
  -	
  -	if( cmp  != testCondition ) {
  -	    responseStatus = false;
  -	    System.out.println("ERROR (" + cmp + "," + testCondition + ")in : " + request);
  -	    System.out.println("====================Expecting: ");
  -	    System.out.println(expResult);
  -	    System.out.println("====================Got:");
  -	    System.out.println(responseBody);
  -	    System.out.println("====================");
  -		if ( resultOut != null )
  -		{
  -			expectedString = "<expectedBody>" + expResult + "</expectedBody>\n";
  -			actualString = "<actualBody>"+ responseBody + "</actualBody>\n";
  -			resultOut.write(expectedString.getBytes() );
  -			resultOut.write(actualString.getBytes() );
  +           
   
  -		}
  -	}	    
  -	
  -	return responseStatus;
  +        if ( responseMatch != null ) {
  +            // check if we got the string we wanted
  +            if ( expectResponseBody && responseBody == null ) {
  +                System.out.println( " ERROR: got no response, expecting " + responseMatch );
  +                return false;
  +            }
  +	    String responseBodyString = new String( responseBody );
  +            if ( responseBodyString.indexOf( responseMatch ) < 0 ) {
  +                System.out.println( " ERROR: expecting match on " + responseMatch );
  +                System.out.println( "Received: " );
  +                System.out.println( responseBodyString );
  +            }
  +        }
  +
  +        // compare the body
  +        if ( goldenFile == null )
  +            return responseStatus;
  +
  +        // Get the expected result from the "golden" file.
  +        byte[] expResult = getExpectedResult();
  +
  +        // Compare the results and set the status
  +        boolean cmp = true;
  +
  +        if ( exactMatch ) {
  +            cmp = compare( responseBody, expResult );
  +	} else {
  +            cmp = compareWeak( responseBody, expResult );
  +	}
  +
  +        if ( cmp != testCondition ) {
  +            responseStatus = false;
  +
  +            if ( resultOut != null ) {
  +                expectedString = "<expectedBody>" + new String( expResult ) + "</expectedBody>\n";
  +                actualString = "<actualBody>" + new String( responseBody ) + "</actualBody>\n";
  +                resultOut.write( expectedString.getBytes() );
  +                resultOut.write( actualString.getBytes() );
  +            }
  +        }
  +
  +        return responseStatus;
       }
  +
       
  -    /** Invoke a request, set headers, responseLine, body
  +    /**
  +     * <code>dispatch</code> sends the request and any
  +     * configured request headers to the target server.
  +     *
  +     * @param request a <code>String</code> value
  +     * @param requestHeaders a <code>HashMap</code> value
        */
  -    private void dispatch(String request, Hashtable requestHeaders)
  -	throws Exception
  -    {
  -	// XXX headers are ignored
  -	Socket s = null;
  -
  -	s = new Socket( host, port);
  -	InputStream is=	s.getInputStream();
  -
  -	// Write the request
  -	s.setSoLinger( true, 1000);
  -	OutputStream os=s.getOutputStream();
  -	OutputStreamWriter out=new OutputStreamWriter(os);
  -	PrintWriter pw = new PrintWriter(out);
  +    private void dispatch( String request, HashMap requestHeaders ) 
  +    throws Exception {
  +        // XXX headers are ignored
  +        Socket socket = new Socket( host, port );
  +
  +        InputStream is = new CRBufferedInputStream( socket.getInputStream() );
  +
  +        // Write the request
  +        socket.setSoLinger( true, 1000 );
  +
  +        PrintWriter pw = new PrintWriter(
  +			     new BufferedWriter(
  +			         new OutputStreamWriter( socket.getOutputStream() ) ) );
   
  -	try {
  -	    pw.println(request);
  -	    
  -	    // Now sending any specified request headers
  -	    if ( requestHeaders != null )
  -	    {
  -	       Enumeration reqHeaderEnum = requestHeaders.keys();
  -	       while ( reqHeaderEnum.hasMoreElements() )
  -	       {
  -			String headerKey = (String)reqHeaderEnum.nextElement();
  -			if ( debug >0 )
  -			{
  -			     System.out.println( headerKey + "::" + requestHeaders.get(headerKey) ); 
  -			}
  -			pw.println( headerKey + ":" + requestHeaders.get( headerKey)); 
  -		}
  -	    }
  -	    if  ( testSession != null )
  -	    {
  -		cookieController = (CookieController)sessionHash.get( testSession );
  -		if ( cookieController != null )
  -		{
  -
  -			String releventCookieString= cookieController.applyRelevantCookies(requestURL );
  -			if ( ( releventCookieString != null ) && (!releventCookieString.trim().equals("" ) ) )
  -			{
  -				String cookieHeader= "Cookie : " + releventCookieString ;
  -				if ( debug >0 )
  -				{
  -				     System.out.println( "Sending Cookie Header:: "  + cookieHeader ); 
  -				}
  -				pw.println( cookieHeader );
  +        try {
  +            pw.println( request );
  +
  +            // Now sending any specified request headers
  +            if ( !requestHeaders.isEmpty() ) {
  +                Iterator iter = requestHeaders.keySet().iterator();
  +		
  +                while ( iter.hasNext() ) {
  +                    String headerKey = ( String ) iter.next();
  +		    ArrayList values = (ArrayList) requestHeaders.get( headerKey );
  +		    String[] value = (String[]) values.toArray( new String[ values.size() ] );
  +		    for ( int i = 0; i < value.length; i++ ) {
  +			StringBuffer sb = new StringBuffer( 25 );
  +			sb.append( headerKey );
  +			sb.append( ": " );
  +			sb.append( value[ i ] );
  +			pw.println( sb.toString() );
  +			if ( debug > 0 ) {
  +			    System.out.println( sb.toString() );
   			}
  -		}
  +		    }
  +                }
  +            }
  +
  +            if ( testSession != null ) {
  +                cookieController = ( CookieController ) sessionHash.get( testSession );
  +
  +                if ( cookieController != null ) {
  +
  +                    String releventCookieString = cookieController.applyRelevantCookies( requestURL );
  +
  +                    if ( ( releventCookieString != null ) && ( !releventCookieString.trim().equals( "" ) ) ) {
  +                        String cookieHeader = "Cookie : " + releventCookieString ;
  +
  +                        if ( debug > 0 ) {
  +                            System.out.println( " Sending Cookie Header:: " + cookieHeader );
  +                        }
  +
  +                        pw.println( cookieHeader );
  +                    }
  +                }
  +
  +            }
   
  -	     }
  -	    /*
  - 
  -	    if ( ( testSession != null ) && ( sessionHash.get( testSession ) != null ) )
  -	    {
  -		System.out.println("Sending Session Id : " + (String)sessionHash.get( testSession ) );
  -		pw.println("JSESSIONID:" + (String)sessionHash.get( testSession) );
  +            /*
  +
  +            if ( ( testSession != null ) && ( sessionHash.get( testSession ) != null ) )
  +        {
  +            System.out.println("Sending Session Id : " + (String)sessionHash.get( testSession ) );
  +            pw.println("JSESSIONID:" + (String)sessionHash.get( testSession) );
  +        }
  +
  +            */
  +
  +            if ( content != null ) {
  +                pw.println( "Content-Length: " + content.length() );
  +            }
  +
  +            if ( request.indexOf( "HTTP/1." ) > -1 )
  +                pw.println( "" );
  +
  +            if ( content != null ) {
  +                pw.print( content );
  +                // XXX no /n at the end -see HTTP specs!
  +            }
  +
  +            pw.flush();
  +        } catch ( Exception ex1 ) {
  +            System.out.println( " Error writing request " + ex1 );
  +	    if ( debug > 0 ) {
  +		System.out.println( "Message: " + ex1.getMessage() );
  +		ex1.printStackTrace();
   	    }
  +        }
   
  -	    */
  +        try {
  +  
  +	    responseLine = read( is );
   
  -	    if( content != null) {
  -		pw.println("Content-Length: " + content.length());
  +	    if ( debug > 0 ) {
  +		System.out.println( " RESPONSE STATUS-LINE: " + responseLine );
   	    }
  -	    
  -	    if( request.indexOf( "HTTP/1." ) > -1) 
  -		pw.println("");
  -	    
  -	    if( content != null) {
  -		pw.print(content);
  -		// XXX no /n at the end -see HTTP specs!
  +
  +	    headers = parseHeaders( is );
  +           
  +            byte[] result = readBody( is );
  +
  +            if ( result != null ) {
  +                responseBody = result;
  +		if ( debug > 0 ) {
  +		    System.out.println( " RESPONSE BODY:\n" + new String( responseBody ) );
  +		}
   	    }
  -	    
  -	    pw.flush();
  -	} catch (Exception ex1 ) {
  -	    System.out.println("Error writing request " + ex1);
  -	}
  -	
  -	try {
  -	    // http 0.9
  -	    if( request.indexOf( "HTTP/1." ) > -1) {
  -		responseLine = read( is );
   		
  -		if( debug>0) System.out.println("RESPONSE: " + responseLine );
  -		headers=parseHeaders( is );
  +        } catch ( SocketException ex ) {
  +            System.out.println( " Socket Exception: " + ex );
  +            ex.printStackTrace();
  +        } finally {
  +	    if ( debug > 0 ) {
  +		System.out.println( " closing socket" );
   	    }
  -
  -	    // else do content matching as well
  -	    StringBuffer result =  readBody( is );
  -	    if(result!=null)
  -		responseBody=result.toString();
  -
  -	    if(debug>0) System.out.println("BODY: " + responseBody );
  -	} catch( SocketException ex ) {
  -	    System.out.println("Socket Exception: " + ex);
  -	    ex.printStackTrace();
  -	    s.close();
  -	    return;
  +	    socket.close();
  +	    socket = null;
   	}
  -	s.close();
       }
  -
  -    // Parse a file into a String.
  -    private StringBuffer getExpectedResult()
  -	throws IOException
  -    {
  -        StringBuffer expResult = new StringBuffer("NONE");
   
  +    
  +    /**
  +     * <code>getExpectedResult</code> returns a byte array
  +     * containing the content of the configured goldenfile
  +     *
  +     * @return goldenfile as a byte[]
  +     * @exception IOException if an error occurs
  +     */
  +    private byte[] getExpectedResult()
  +    throws IOException {
  +        byte[] expResult = { 'N','O',' ',
  +                             'G','O','L','D','E','N','F','I','L','E',' ',
  +                             'F','O','U','N','D' };
  +                            
           try {
  -	    //	    InputStream in = this.getClass().getResourceAsStream(goldenFile);
  -	    InputStream in = new FileInputStream( goldenFile );
  -	    return readBody ( in );
  -        } catch (Exception ex) {
  -            System.out.println("\tGolden file not found: " + goldenFile);
  +            InputStream in = new BufferedInputStream(
  +			         new FileInputStream( goldenFile ) );
  +            return readBody ( in );
  +        } catch ( Exception ex ) {
  +            System.out.println( "Golden file not found: " + goldenFile );
               return expResult;
           }
       }
  -
   
  -    // Compare the actual result and the expected result.
  -    private boolean compare(String str1, String str2) {
  -	//System.out.println("In compare");
  -	if ( str1==null || str2==null) return false;
  -	if ( str1.length() != str2.length() ) {
  -	    System.out.println("Wrong size " + str1.length() +" " + str2.length() );
  -	    return false;
  +    /**
  +     * <code>compare</code> compares the two byte arrays passed
  +     * in to verify that the lengths of the arrays are equal, and
  +     * that the content of the two arrays, byte for byte are equal.
  +     *
  +     * @param fromServer a <code>byte[]</code> value
  +     * @param fromGoldenFile a <code>byte[]</code> value
  +     * @return <code>boolean</code> true if equal, otherwise false
  +     */
  +    private boolean compare( byte[] fromServer, byte[] fromGoldenFile ) {
  +        if ( fromServer == null || fromGoldenFile == null ) {
  +            return false;
   	}
  -	
  -        for(int i=0; i<str1.length() ; i++ ) {
  -            if (str1.charAt( i ) != str2.charAt( i ) ) {
  -		System.out.println("Error at " + i  + " " + str1.charAt(1) +
  -				   str2.charAt(i));
  -                return false;
  +
  +	/*
  +         * Check to see that the respose and golden file lengths
  +         * are equal.  If they are not, dump the hex and don't
  +         * bother comparing the bytes.  If they are equal,
  +         * iterate through the byte arrays and compare each byte.
  +         * If the bytes don't match, dump the hex representation
  +         * of the server response and the goldenfile and return
  +         * false.
  +         */
  +	if ( fromServer.length != fromGoldenFile.length ) {
  +            StringBuffer sb = new StringBuffer( 50 );
  +            sb.append( " Response and golden files lengths do not match!\n" );
  +            sb.append( " Server response length: " );
  +            sb.append( fromServer.length );
  +            sb.append( "\n Goldenfile length: " );
  +            sb.append( fromGoldenFile.length );
  +            System.out.println( sb.toString() );
  +            sb = null;
  +            // dump the hex representation of the byte arrays
  +            dumpHex( fromServer, fromGoldenFile );
  +
  +            return false;
  +        } else {
  +
  +            int i = 0;
  +            int j = 0;
  +
  +            while ( ( i < fromServer.length ) && ( j < fromGoldenFile.length ) ) {
  +                if ( fromServer[ i ] != fromGoldenFile[ j ] ) {
  +                    System.out.println( " Error at position " + ( i + 1 ) );
  +                    // dump the hex representation of the byte arrays
  +                    dumpHex( fromServer, fromGoldenFile );
  +
  +                    return false;
  +                }
  +
  +                i++;
  +                j++;
               }
           }
  -	return true;
  +
  +        return true;
       }
   
  -    // Compare the actual result and the expected result.
  -    // Original compare - ignores spaces ( because most
  -    // golden files are wrong !)
  -    private boolean compareWeek(String str1, String str2) {
  -	//System.out.println("In compareWeek");
  - 	if ( str1==null || str2==null) return false;
  -	
  -        StringTokenizer st1=new StringTokenizer(str1);
  -        StringTokenizer st2=new StringTokenizer(str2);
  +    /**
  +     * <code>compareWeak</code> creates new Strings from the passed arrays
  +     * and then uses a StringTokenizer to compare non-whitespace tokens.
  +     *
  +     * @param fromServer a <code>byte[]</code> value
  +     * @param fromGoldenFile a <code>byte[]</code> value
  +     * @return a <code>boolean</code> value
  +     */
  +    private boolean compareWeak( byte[] fromServer, byte[] fromGoldenFile ) {
  +        if ( fromServer == null || fromGoldenFile == null ) {
  +            return false;
  +	}
  +
  +        StringTokenizer st1 = new StringTokenizer( new String( fromServer ) );
   
  -        while (st1.hasMoreTokens() && st2.hasMoreTokens()) {
  +        StringTokenizer st2 = new StringTokenizer( new String( fromGoldenFile ) );
  +
  +        while ( st1.hasMoreTokens() && st2.hasMoreTokens() ) {
               String tok1 = st1.nextToken();
               String tok2 = st2.nextToken();
  -            if (!tok1.equals(tok2)) {
  -		System.out.println("\tFAIL*** : Rtok1 = " + tok1 
  -                        + ", Etok2 = " + tok2);
  +
  +            if ( !tok1.equals( tok2 ) ) {
  +                System.out.println( "\t FAIL*** : Rtok1 = " + tok1
  +                                    + ", Etok2 = " + tok2 );
                   return false;
               }
           }
   
  -        if (st1.hasMoreTokens() || st2.hasMoreTokens()) {
  +        if ( st1.hasMoreTokens() || st2.hasMoreTokens() ) {
               return false;
           } else {
               return true;
           }
       }
  -
   
  -    // XXX return byte [], fix the reading !!!!!
  -    StringBuffer readBody( InputStream input )
  -    {
  -	StringBuffer sb = new StringBuffer();
  -	while (true) {
  -	    try {
  +    /**
  +     * <code>readBody</code> reads the body of the response
  +     * from the InputStream.
  +     *
  +     * @param input an <code>InputStream</code>
  +     * @return a <code>byte[]</code> representation of the response
  +     */
  +    private byte[] readBody( InputStream input ) {
  +        StringBuffer sb = new StringBuffer( 255 );
  +        while ( true ) {
  +            try {
   		int ch = input.read();
  -		if (ch < 0) {
  -		    if (sb.length() == 0) {
  -			return (null);
  -		    } else {
  -			break;
  +
  +		if ( ch < 0 ) {
  +                    if ( sb.length() == 0 ) {
  +                        return ( null );
  +                    } else {
  +                        break;
   		    }
   		}
  -		sb.append((char) ch);
  -	    } catch(IOException ex ) {
  -		return sb;
  -	    }
  -	}
  -        return sb;
  +		sb.append( ( char ) ch );
  +		 
  +            } catch ( IOException ex ) {
  +                return null;
  +            }
  +        }
  +        return sb.toString().getBytes();
       }
   
  -	//Ramesh
  -    private void getHeaderDetails( String line, Hashtable headerHash )
  -	{
  -		StringTokenizer stk = new StringTokenizer( line, "##" );
  -		while ( stk.hasMoreElements( ) )
  -		{
  -			String presentHeader = stk.nextToken();
  -			parseHeader( presentHeader, headerHash );
  -		}
  -	}
  +    /**
  +     * <code>getHeaderDetails</code> Wrapper method for parseHeader.
  +     * Allows easy addition of headers to the specified
  +     * HashMap
  +     *
  +     * @param line a <code>String</code> value
  +     * @param headerMap a <code>HashMap</code> value
  +     * @param isRequest a <code>boolean</code> indicating if the passed Header 
  +     *                  HashMap is for request headers
  +     */
  +    private void getHeaderDetails( String line, HashMap headerHash, boolean isRequest ) {
  +        StringTokenizer stk = new StringTokenizer( line, "##" );
   
  +        while ( stk.hasMoreElements( ) ) {
  +            String presentHeader = stk.nextToken();
  +            parseHeader( presentHeader, headerHash, isRequest );
  +        }
  +    }
  +
       // ==================== Code from JSERV !!! ====================
       /**
        * Parse the incoming HTTP request headers, and set the corresponding
  @@ -610,106 +1015,368 @@
        *
        * @exception IOException if an input/output error occurs
        */
  -    private Hashtable parseHeaders(InputStream is) throws IOException {
  -	Hashtable headers=new Hashtable();
  -	cookieVector = new Vector();
  -	while (true) {
  -	    // Read the next header line
  -	    String line = read(is);
  -	    if ((line == null) || (line.length() < 1)) {
  -		break;
  +    private HashMap parseHeaders( InputStream is ) throws IOException {
  +        HashMap headers = new HashMap();
  +        cookieVector = new Vector();
  +
  +        while ( true ) {
  +            // Read the next header line
  +            String line = read( is );
  +
  +            if ( ( line == null ) || ( line.length() < 1 ) ) {
  +                break;
  +            }
  +
  +            parseHeader( line, headers, false );
  +
  +            if ( debug > 0 ) {
  +                System.out.println( " RESPONSE HEADER: " + line );
   	    }
   
  -	    parseHeader( line, headers);
  -	    if( debug>0) System.out.println("HEADER: " +line +"X" );
  +        }
   
  -	}
  -	if ( testSession != null ) 
  -	{
  -		cookieController = (CookieController)sessionHash.get(testSession);
  -		if ( cookieController != null )
  -		{
  -			cookieController.recordAnyCookies(cookieVector,requestURL);
  -		}
  -	}
  +        if ( testSession != null ) {
  +            cookieController = ( CookieController ) sessionHash.get( testSession );
  +
  +            if ( cookieController != null ) {
  +                cookieController.recordAnyCookies( cookieVector, requestURL );
  +            }
  +        }
   
  -	return headers;
  +        return headers;
       }
   
  -    private void parseHeader(String line, Hashtable headers) {
  -	// Parse the header name and value
  -	int colon = line.indexOf(":");
  -	if (colon < 0) {
  -	    System.out.println("ERROR: Wrong Header Line: " +  line );
  -	    return;
  -	}
  -	String name = line.substring(0, colon).trim();
  -	String value = line.substring(colon + 1).trim();
  -	if ( (cookieVector != null ) && ( name.equalsIgnoreCase("Set-Cookie") ) )
  -	{
  -		cookieVector.addElement(value);
  -		/*
  -		if ( ( value.indexOf("JSESSIONID") > -1 ) || (value.indexOf("jsessionid")  > -1 ) )
  -		{
  -		     String sessionId= value.substring( value.indexOf("=")+1);
  -		     if ( testSession != null )
  -		     {
  -		     	sessionHash.put( testSession, sessionId );
  -		     }
  -		     System.out.println("Got Session-ID : " + sessionId );
  -		}
  -		*/
  -	} 
  +    /**
  +     * <code>parseHeader</code> parses input headers in format of "key:value"
  +     * The parsed header field-name will be used as a key in the passed 
  +     * HashMap object, and the values found will be stored in an ArrayList
  +     * associated with the field-name key.
  +     *
  +     * @param line String representation of an HTTP header line.
  +     * @param headers a<code>HashMap</code> to store key/value header objects.
  +     * @param isRequest set to true if the headers being processed are 
  +     *        requestHeaders.
  +     */
  +    private void parseHeader( String line, HashMap headerMap, boolean isRequest ) {
  +        // Parse the header name and value
  +        int colon = line.indexOf( ":" );
  +
  +        if ( colon < 0 ) {
  +            System.out.println( " ERROR: Header is in incorrect format: " + line );
  +            return ;
  +        }
  +
  +        String name = line.substring( 0, colon ).trim();
  +        String value = line.substring( colon + 1 ).trim();
  +
  +        if ( ( cookieVector != null ) && ( name.equalsIgnoreCase( "Set-Cookie" ) ) ) {
  +            cookieVector.addElement( value );
  +            /*
  +            if ( ( value.indexOf("JSESSIONID") > -1 ) || (value.indexOf("jsessionid")  > -1 ) )
  +        {
  +                 String sessionId= value.substring( value.indexOf("=")+1);
  +                 if ( testSession != null )
  +                 {
  +                 	sessionHash.put( testSession, sessionId );
  +                 }
  +                 System.out.println("Got Session-ID : " + sessionId );
  +        }
  +            */
  +        }
   
  -	//	System.out.println("HEADER: " +name + " " + value);
  -	headers.put(name, value);
  +        //	System.out.println("HEADER: " +name + " " + value);
  +
  +	ArrayList values = (ArrayList) headerMap.get( name );
  +	if ( values == null ) {
  +	    values = new ArrayList();
  +	}
  +	// HACK
  +	if ( value.indexOf( ',' ) > -1 && !isRequest && !name.equalsIgnoreCase( "Date" ) ) {
  +	    StringTokenizer st = new StringTokenizer( value, "," );
  +	    while ( st.hasMoreElements() ) {
  +		values.add( st.nextToken() );
  +	    }
  +	} else {
  +	    values.add( value );
  +	}
  +	
  +        headerMap.put( name, values );
       }
   
       /**
        * Read a line from the specified servlet input stream, and strip off
        * the trailing carriage return and newline (if any).  Return the remaining
  -     * characters that were read as a string.
  +     * characters that were read as a string.7
        *
        * @returns The line that was read, or <code>null</code> if end of file
        *  was encountered
        *
        * @exception IOException if an input/output error occurred
        */
  -    private String read(InputStream input) throws IOException {
  -	// Read the next line from the input stream
  -	StringBuffer sb = new StringBuffer();
  -	while (true) {
  -	    try {
  -		int ch = input.read();
  -		//		System.out.println("XXX " + (char)ch );
  -		if (ch < 0) {
  -		    if (sb.length() == 0) {
  -			if(debug>0) System.out.println("Error reading line " + ch + " " + sb.toString() );
  -			return "";
  -		    } else {
  -			break;
  -		    }
  -		} else if (ch == '\n') {
  -		    break;
  +    private String read( InputStream input ) throws IOException {
  +        // Read the next line from the input stream
  +        StringBuffer sb = new StringBuffer();
  +
  +        while ( true ) {
  +            try {
  +                int ch = input.read();
  +                //		System.out.println("XXX " + (char)ch );
  +                if ( ch < 0 ) {
  +                    if ( sb.length() == 0 ) {
  +                        if ( debug > 0 )
  +                            System.out.println( " Error reading line " + ch + " " + sb.toString() );
  +                        return "";
  +                    } else {
  +                        break;
  +                    }
  +                } else if ( ch == LINE_FEED ) {
  +                    break;
  +                }
  +
  +                sb.append( ( char ) ch );
  +            } catch ( IOException ex ) {
  +                System.out.println( " Error reading : " + ex );
  +                debug = 1;
  +
  +                if ( debug > 0 ) {
  +                    System.out.println( "Partial read: " + sb.toString() );
  +		    ex.printStackTrace();
   		}
  -		sb.append((char) ch);
  -	    } catch( IOException ex ) {
  -		System.out.println("Error reading : " + ex );
  -		debug=1;
  -		if(debug>0) System.out.println("Partial read: " + sb.toString());
  -		ex.printStackTrace();
  -		//break;
  +            }
  +        }
  +        return  sb.toString();
  +    }
  +
  +    /**
  +     * <code>dumpHex</code> helper method to dump formatted
  +     * hex output of the server response and the goldenfile.
  +     *
  +     * @param serverResponse a <code>byte[]</code> value
  +     * @param goldenFile a <code>byte[]</code> value
  +     */
  +    private void dumpHex( byte[] serverResponse, byte[] goldenFile ) {
  +        StringBuffer outBuf = new StringBuffer( ( serverResponse.length + goldenFile.length ) * 2 );
  +
  +        String fromServerString = getHexValue( serverResponse, 0, serverResponse.length );
  +        String fromGoldenFileString = getHexValue( goldenFile, 0, goldenFile.length );
  +
  +        outBuf.append( " Hex dump of server response and goldenfile below.\n\n### RESPONSE FROM SERVER ###\n" );
  +        outBuf.append( "----------------------------\n" );
  +        outBuf.append( fromServerString );
  +        outBuf.append( "\n\n### GOLDEN FILE ###\n" );
  +        outBuf.append( "-------------------\n" );
  +        outBuf.append( fromGoldenFileString );
  +        outBuf.append( "\n\n### END OF DUMP ###\n" );
  +
  +        System.out.println( outBuf.toString() );
  +
  +    }
  +
  +    /**
  +     * <code>getHexValue</code> displays a formatted hex
  +     * representation of the passed byte array.  It also
  +     * allows for only a specified offset and length of 
  +     * a particular array to be returned.
  +     *
  +     * @param bytes <code>byte[]</code> array to process.
  +     * @param pos <code>int</code> specifies offset to begin processing.
  +     * @param len <code>int</code> specifies the number of bytes to process.
  +     * @return <code>String</code> formatted hex representation of processed 
  +     *         array.
  +     */
  +    private String getHexValue( byte[] bytes, int pos, int len ) {
  +        StringBuffer outBuf = new StringBuffer( bytes.length * 2 );
  +        int bytesPerLine = 36;
  +        int cnt = 1;
  +        int groups = 4;
  +        int curPos = pos;
  +        int linePos = 1;
  +        boolean displayOffset = true;
  +
  +        while ( len-- > 0 ) {
  +            if ( displayOffset ) {
  +
  +                outBuf.append( "\n" + paddedHexString( pos, SHORTPADSIZE,
  +                                                       true ) + ": " );
  +                displayOffset = false;
  +            }
  +
  +            outBuf.append(
  +                paddedHexString( ( int ) bytes[ pos ], BYTEPADSIZE, false ) );
  +            linePos += 2;  // Byte is padded to 2 characters
  +
  +            if ( ( cnt % 4 ) == 0 ) {
  +                outBuf.append( " " );
  +                linePos++;
  +            }
  +
  +            // Now display the characters that are printable
  +            if ( ( cnt % ( groups * 4 ) ) == 0 ) {
  +                outBuf.append( " " );
  +
  +                while ( curPos <= pos ) {
  +                    if ( !Character.isWhitespace( ( char ) bytes[ curPos ] ) ) {
  +                        outBuf.append( ( char ) bytes[ curPos ] );
  +                    } else {
  +                        outBuf.append( "." );
  +                    }
  +
  +                    curPos++;
  +                }
  +
  +                curPos = pos + 1;
  +                linePos = 1;
  +                displayOffset = true;
  +            }
  +
  +            cnt++;
  +            pos++;
  +        }
  +
  +        // pad out the line with spaces
  +        while ( linePos++ <= bytesPerLine ) {
  +            outBuf.append( " " );
  +        }
  +
  +        outBuf.append( " " );
  +        // Now display the printable characters for the trailing bytes
  +        while ( curPos < pos ) {
  +            if ( !Character.isWhitespace( ( char ) bytes[ curPos ] ) ) {
  +                outBuf.append( ( char ) bytes[ curPos ] );
  +            } else {
  +                outBuf.append( "." );
  +            }
  +
  +            curPos++;
  +        }
  +
  +        return outBuf.toString();
  +    }
  +
  +    /**
  +     * <code>paddedHexString</code> pads the passed value
  +     * based on the specified wordsize and the value of the
  +     * prefixFlag.
  +     *
  +     * @param val an <code>int</code> value
  +     * @param wordsize an <code>int</code> value
  +     * @param prefixFlag a <code>boolean</code> value
  +     * @return a <code>String</code> value
  +     */
  +    private String paddedHexString( int val, int wordsize,
  +                                    boolean prefixFlag ) {
  +
  +        String prefix = prefixFlag ? "0x" : "" ;
  +        String hexVal = Integer.toHexString( val );
  +
  +        if ( hexVal.length() > wordsize )
  +            hexVal = hexVal.substring( hexVal.length() - wordsize );
  +
  +        return ( prefix + ( wordsize > hexVal.length() ?
  +                            ZEROS.substring( 0, wordsize - hexVal.length() ) : "" ) + hexVal );
  +    }
  +
  +    /**
  +     * <code>cloneHeaders</code> returns a "cloned"
  +     * HashMap of the map passed in.
  +     *
  +     * @param map a <code>HashMap</code> value
  +     * @return a <code>HashMap</code> value
  +     */
  +    private HashMap cloneHeaders( HashMap map ) {
  +	HashMap dupMap = new HashMap();
  +	Iterator iter = map.keySet().iterator();
  +	
  +	while ( iter.hasNext() ) {
  +	    String key = new String( (String) iter.next() );
  +	    ArrayList origValues = (ArrayList) map.get( key );
  +	    ArrayList dupValues = new ArrayList();
  +
  +	    String[] dupVal = (String[]) origValues.toArray( new String[ origValues.size() ] );
  +	    for ( int i = 0; i < dupVal.length; i++ ) {
  +		dupValues.add( new String( dupVal[ i ] ) );
   	    }
  +	    
  +	    dupMap.put( key, dupValues );
   	}
  +	return dupMap;
  +    }
   
  -	// Strip any trailing carriage return
  -	int n = sb.length();
  -	if ((n > 0) && (sb.charAt(n - 1) == '\r')) {
  -	    sb.setLength(n - 1);
  -	}
  +    /**
  +     * <code>CRBufferedInputStream</code> is a modified version of
  +     * the java.io.BufferedInputStream class.  The fill code is 
  +     * the same, but the read is modified in that if a carriage return
  +     * is found in the response stream from the target server, 
  +     * it will skip that byte and return the next in the stream.
  +     */
  +    private class CRBufferedInputStream extends BufferedInputStream {
  +        
  +	private static final int DEFAULT_BUFFER = 2048;
  +
  +        /**
  +	 * Creates a new <code>CRBufferedInputStream</code> instance.
  +	 *
  +	 * @param in an <code>InputStream</code> value
  +	 */
  +	public CRBufferedInputStream( InputStream in ) {
  +            super( in, DEFAULT_BUFFER );
  +        }
   
  -	// Convert the line to a String and return it
  -	return (sb.toString());
  -    }
  +        /**
  +	 * <code>read</code> reads a single byte value per call.
  +	 * If, the byte read, is a carriage return, the next byte
  +	 * in the stream in returned instead.
  +	 *
  +	 * @return an <code>int</code> value
  +	 * @exception IOException if an error occurs
  +	 */
  +	public int read() throws IOException {
  +            if ( in == null ) {
  +                throw new IOException ( "Stream closed" );
  +            }
  +            if ( pos >= count ) {
  +                fill();
  +                if ( pos >= count ) {
  +                    return -1;
  +                }
  +            }
  +            int val = buf[pos++] & 0xff;
  +            if ( val == CARRIAGE_RETURN ) {
  +                return buf[pos++] & 0xff;
  +            }
  +            return val;
  +        }
   
  +        /**
  +	 * <code>fill</code> is used to fill the internal
  +	 * buffer used by this BufferedInputStream class.
  +	 *
  +	 * @exception IOException if an error occurs
  +	 */
  +	private void fill() throws IOException {
  +            if (markpos < 0)
  +                pos = 0;        /* no mark: throw away the buffer */
  +            else if (pos >= buf.length)  /* no room left in buffer */
  +                if (markpos > 0) {  /* can throw away early part of the buffer */
  +                    int sz = pos - markpos;
  +                    System.arraycopy(buf, markpos, buf, 0, sz);
  +                    pos = sz;
  +                    markpos = 0;
  +                } else if (buf.length >= marklimit) {
  +                    markpos = -1;   /* buffer got too big, invalidate mark */
  +                    pos = 0;    /* drop buffer contents */
  +                } else {        /* grow buffer */
  +                    int nsz = pos * 2;
  +                    if (nsz > marklimit)
  +                        nsz = marklimit;
  +                    byte nbuf[] = new byte[nsz];
  +                    System.arraycopy(buf, 0, nbuf, 0, pos);
  +                    buf = nbuf;
  +                }
  +                count = pos;
  +                int n = in.read(buf, pos, buf.length - pos); 
  +                if (n > 0)
  +                count = n + pos;
  +        }
  +    }
   }
  
  
  

--
To unsubscribe, e-mail:   <mailto:watchdog-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:watchdog-dev-help@jakarta.apache.org>


Mime
View raw message