rlubke      02/02/01 19:22:52

  Added:       src/tools/org/apache/watchdog/task CookieController.java
                        GTest.java HttpCookie.java RfcDateParser.java
  Log:
   - Moved classes to new package
   - Added Copyright headers
   - Formatted code
  
  Revision  Changes    Path
  1.1                  
jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/CookieController.java
  
  Index: CookieController.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/CookieController.java,v
 1.1 2002/02/02 03:22:52 rlubke Exp $ 
   * $Revision: 1.1 $
   * $Date: 2002/02/02 03:22:52 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.watchdog.task;
  
  import java.util.*;
  import java.io.*;
  import java.net.URLConnection;
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.util.Vector;
  import java.io.FileReader;
  import java.io.BufferedReader;
  import java.io.FileWriter;
  import java.io.PrintWriter;
  import java.io.IOException;
  import java.net.URL;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyVetoException;
  import java.beans.VetoableChangeListener;
  import java.beans.VetoableChangeSupport;
  
  /**
   * Represents a collection of Cookie instances. 
   * <p>
   * Fires events when the cookies have been changed internally. Deals
   * with management of cookies in terms of saving and loading them,
   * and disabling them.
   *
   * @author    Ramesh.Mandava 
   */
  
  public class CookieController {
  
      private VetoableChangeSupport vceListeners;
  
      private int listenerNum = 0;
  
      private static Hashtable cookieJar;
  
      private static boolean initialized = false;
  
      /* public no arg constructor for bean */
      public CookieController() {
        if (!initialized) {
            vceListeners = new VetoableChangeSupport(this);
            cookieJar = new Hashtable();
            initialized = true;
        }
      }
  
  /////////////////////////////////////////////////////////////
   /**
       * Records any cookies which have been sent as part of an HTTP response.
       * The connection parameter must be already have been opened, so that
       * the response headers are available.  It's ok to pass a non-HTTP
       * URL connection, or one which does not have any set-cookie headers.
       */
      public void recordAnyCookies(Vector rcvVectorOfCookies , URL url ) {
  
        if ((rcvVectorOfCookies == null) || ( rcvVectorOfCookies.size()== 0) ) {
            // no headers here
            return;
        }       
        try {
        /*
          Properties properties = new Properties(); 
        FileInputStream fin = new FileInputStream("ServerAutoRun.properties");
        properties.load(fin);
        
        String cookiepolicy = properties.getProperty("cookie.acceptpolicy");
        if (cookiepolicy == null || cookiepolicy.equals("none")) {
            return;
        }
        */
  
  
  
  
        for (int hi = 0; hi<rcvVectorOfCookies.size(); hi++) {
  
                String cookieValue = (String)rcvVectorOfCookies.elementAt(hi) ;
                recordCookie(url, cookieValue); // What to do here
            }
  
        }
        catch( Exception e )
        {
                System.out.println("exception : " + e );
        }
      }
  
  
      /**
       * Create a cookie from the cookie, and use the HttpURLConnection to
       * fill in unspecified values in the cookie with defaults.
       */
      public void recordCookie(URL url,
                                     String cookieValue) {
        HttpCookie cookie = new HttpCookie(url, cookieValue);
        
        // First, check to make sure the cookie's domain matches the
        // server's, and has the required number of '.'s
        String twodot[]=
            {"com", "edu", "net", "org", "gov", "mil", "int"};
        String domain = cookie.getDomain();
        if( domain == null )
            return;
        int index = domain.indexOf(':');
        if (index != -1) {
            int portCookie;
            try {
                portCookie = 
(Integer.valueOf(domain.substring(index+1,domain.length()))).intValue();
            } catch (Exception e) {
                return;
            }
            portCookie = ( portCookie == -1 ) ? 80 : portCookie;
            domain=domain.substring(0,index);
        }
        domain.toLowerCase();
        
        String host = url.getHost();
        host.toLowerCase();
  
        boolean domainOK = host.equals(domain);
        if( !domainOK && host.endsWith( domain ) ) {
            int dotsNeeded = 2;
            for( int i = 0; i < twodot.length; i++ ) {
                if( domain.endsWith( twodot[i] ) ) {
                    dotsNeeded = 1;
                }
            }
  
            int lastChar = domain.length();
            for( ; lastChar > 0 && dotsNeeded > 0; dotsNeeded-- ) {
                lastChar = domain.lastIndexOf( '.', lastChar-1 );
            }
  
            if( lastChar > 0 )
                domainOK = true;
        }
  
        if( domainOK ) {
            recordCookie(cookie);
  
        }
      }
  
  
      /**
       * Record the cookie in the in-memory container of cookies.  If there
       * is already a cookie which is in the exact same domain with the
       * exact same
       */
      public void recordCookie(HttpCookie cookie) {
        if (!checkIfCookieOK(cookie)) {
            return;
        }
        synchronized (cookieJar) {
            
            String domain = cookie.getDomain().toLowerCase();
  
            Vector cookieList = (Vector)cookieJar.get(domain);
            if (cookieList == null) {
                cookieList = new Vector();
            }
  
            addOrReplaceCookie(cookieList, cookie);
            cookieJar.put(domain, cookieList);
            
        }
  
      }
  
      public boolean checkIfCookieOK(HttpCookie cookie) {
        try {
            if (vceListeners != null) {
                vceListeners.fireVetoableChange("cookie", null, cookie );
            }
        } catch (PropertyVetoException ex) {
            return false;
        }
        
        return true;
      }
  
      /**
       * Scans the vector of cookies looking for an exact match with the
       * given cookie.  Replaces it if there is one, otherwise adds
       * one at the end.  The vector is presumed to have cookies which all
       * have the same domain, so the domain of the cookie is not checked.
       * <p>
       * <p>
       * If this is called, it is assumed that the cookie jar is exclusively
       * held by the current thread.
       *
       */
      private void addOrReplaceCookie(Vector cookies,
                                       HttpCookie cookie) {
        int numCookies = cookies.size();
  
        String path = cookie.getPath();
        String name = cookie.getName();
        HttpCookie replaced = null;
        int replacedIndex = -1;
  
        for (int i = 0; i < numCookies; i++) {
            HttpCookie existingCookie = (HttpCookie)cookies.elementAt(i);
        
            String existingPath = existingCookie.getPath();
            if (path.equals(existingPath)) {
                String existingName = existingCookie.getName();
                if (name.equals(existingName)) {
                    // need to replace this one!
                    replaced = existingCookie;
                    replacedIndex = i;
                    break;
                }
            }
        }
        
        
        // Do the replace - if cookie has already expired, remove 
        // the replaced cookie. 
        if (replaced != null) {
            if (cookie.isSaveableInMemory()) {
                cookies.setElementAt(cookie, replacedIndex);
                //System.out.println("REPLACED existing cookie with " + cookie);
            } else {
                cookies.removeElementAt(replacedIndex);
                //System.out.println("Removed cookie b/c or expr " + cookie);
            }
  
        } else { // only save the cookie in memory if it is non persistent
                 // or not expired.
            if (cookie.isSaveableInMemory()) {
                cookies.addElement(cookie);
                //System.out.println("RECORDED new cookie " + cookie);
            } 
  
        }
  
      }
  
      public String applyRelevantCookies(URL url ) {
  
         try {  
                /*
                Properties properties = new Properties(); 
                FileInputStream fin = new FileInputStream("ServerAutoRun.properties");
                properties.load(fin);
                // check current accept policy instead enableCookies
                String cookiepolicy = properties.getProperty("cookie.acceptpolicy");
                if (cookiepolicy == null || cookiepolicy.equals("none")) {
                    return null;
                }
  
                */
  
                return applyCookiesForHost(url);
  
        }
        catch ( Exception e )
        {
                System.out.println("Exception : " +e );
                return null;
        }
        
  
  
  
      }
  
      
     /**
       * Host may be a FQDN, or a partial domain name starting with a dot.
       * Adds any cookies which match the host and path to the
       * cookie set on the URL connection.
       */
      private String applyCookiesForHost(URL url ){
        String cookieString = null;
        Vector cookieVector = getAllRelevantCookies(url);
        
        if (cookieVector != null) {
  
            for (Enumeration e = cookieVector.elements(); e.hasMoreElements();) {
                HttpCookie cookie = (HttpCookie)e.nextElement();
                if( cookieString == null ) {
                    cookieString = cookie.getNameValue();
                } else {
                    cookieString = cookieString + "; " + cookie.getNameValue();
                }
            }
            
         /*
  
            if( cookieString != null ) {
                httpConn.setRequestProperty("Cookie", cookieString);
         
  //            System.out.println("Returned cookie string: " + cookieString + " for 
HOST = " + host);
             }
  
          */
  
  
        }
  //            System.out.println("Returned cookie string: " + cookieString + " for 
HOST = " + host);
        return cookieString;
        
      }
  
      private Vector getAllRelevantCookies(URL url) {
        String host = url.getHost();
        Vector cookieVector = getSubsetRelevantCookies(host, url);
  
        Vector tempVector;
        int index;
  
        while ((index = host.indexOf('.', 1)) >= 0) {
            // trim off everything up to, and including the dot.
            host = host.substring(index+1);
            
              // add onto cookieVector
            tempVector = getSubsetRelevantCookies(host,url);
            if (tempVector != null ) {
                for (Enumeration e = tempVector.elements(); e.hasMoreElements(); ) {
                    if (cookieVector == null) {
                        cookieVector = new Vector(2);
                    }
  
                    cookieVector.addElement(e.nextElement());
  
                }
            }
        }
        return cookieVector;
      }
  
      private Vector getSubsetRelevantCookies(String host, URL url) {
  
        Vector cookieList = (Vector)cookieJar.get(host);
        
  //    System.out.println("getRelevantCookies() .. for host, url " + host +", "+url);
        Vector cookiePortList = (Vector)cookieJar.get(host+":"+((url.getPort() == -1) 
? 80 : url.getPort()));
        if (cookiePortList != null) {
            if (cookieList == null) {
                cookieList = new Vector(10);
            }
            Enumeration cookies = cookiePortList.elements(); 
            while (cookies.hasMoreElements()) {
                cookieList.addElement(cookies.nextElement());
            }  
        }
        
            
        if (cookieList == null) {
            return null;
        }
  
        String path = url.getFile();
  //    System.out.println("        path is " + path + "; protocol = " + 
url.getProtocol());
  
  
        int queryInd = path.indexOf('?');
        if (queryInd > 0) {
            // strip off the part following the ?
            path = path.substring(0, queryInd);
        }
  
        Enumeration cookies = cookieList.elements();
        Vector cookiesToSend = new Vector(10);
  
        while (cookies.hasMoreElements()) {
            HttpCookie cookie = (HttpCookie)cookies.nextElement();
        
            String cookiePath = cookie.getPath();
  
            if (path.startsWith(cookiePath)) {
                // larrylf: Actually, my documentation (from Netscape)
                // says that /foo should
                // match /foobar and /foo/bar.  Yuck!!!
  
                if (!cookie.hasExpired()) {
                    cookiesToSend.addElement(cookie);
                }
  
  /*
     We're keeping this piece of commented out code around just in
     case we decide to put it back.  the spec does specify the above,
     but it is so disgusting!
  
                int cookiePathLen = cookiePath.length();
  
                // verify that /foo does not match /foobar by mistake
                if ((path.length() == cookiePathLen)
                    || (path.length() > cookiePathLen &&
                        path.charAt(cookiePathLen) == '/')) {
                
                    // We have a matching cookie!
  
                    if (!cookie.hasExpired()) {
                        cookiesToSend.addElement(cookie);
                    }
                }
  */
            }
        }
  
        // Now, sort the cookies in most to least specific order
        // Yes, its the deaded bubblesort!! Wah Ha-ha-ha-ha....
        // (it should be a small vector, so perf is not an issue...)
        if( cookiesToSend.size() > 1 ) {
            for( int i = 0; i < cookiesToSend.size()-1; i++ ) {
                HttpCookie headC = (HttpCookie)cookiesToSend.elementAt(i);
                String head = headC.getPath();
                // This little excercise is a cheap way to get
                // '/foo' to read more specfic then '/'
                if( !head.endsWith("/") ) {
                    head = head + "/";
                }
                for( int j = i+1; j < cookiesToSend.size(); j++ ) {
                    HttpCookie scanC = (HttpCookie)cookiesToSend.elementAt(j);
                    String scan = scanC.getPath();
                    if( !scan.endsWith("/") ) {
                        scan = scan + "/";
                    }
  
                    int headCount = 0;
                    int index = -1;
                    while( (index=head.indexOf('/', index+1)) != -1 ) {
                        headCount++;
                    }
                    index = -1;
  
                    int scanCount = 0;
                    while( (index=scan.indexOf('/', index+1)) != -1 ) {
                        scanCount++;
                    }
  
                    if( scanCount > headCount ) {
                        cookiesToSend.setElementAt(headC, j);
                        cookiesToSend.setElementAt(scanC, i);
                        headC = scanC;
                        head = scan;
                    }
                }
            }
        }
  
  
      return cookiesToSend;
  
      }
  
      /*
       * Writes cookies out to PrintWriter if they are persistent
       * (i.e. have a expr date)
       * and haven't expired. Will remove cookies that have expired as well
       */
      private void saveCookiesToStream(PrintWriter pw) {
  
        Enumeration cookieLists = cookieJar.elements();
                
        while (cookieLists.hasMoreElements()) {
            Vector cookieList = (Vector)cookieLists.nextElement();
  
            Enumeration cookies = cookieList.elements();
  
            while (cookies.hasMoreElements()) {
                HttpCookie cookie = (HttpCookie)cookies.nextElement();
                
                if (cookie.getExpirationDate() != null) {
                    if (cookie.isSaveable()) {
                        pw.println(cookie);
                    } else { // the cookie must have expired, 
                        //remove from Vector cookieList
                        cookieList.removeElement(cookie);
                    }
                 
                }   
            }
        }
          // Must print something to the printwriter in the case that 
        // the cookieJar has been cleared - otherwise the old cookie
        // file will continue to exist.
        pw.print("");
      }
  /////////////////////////////////////////////////////////////
      /* adds cookieList to the existing cookie jar*/
      public void addToCookieJar(HttpCookie[] cookieList) {
  
        if (cookieList != null) {
            for (int i = 0; i < cookieList.length; i++) {
                
                recordCookie(cookieList[i]);
            }
        }
  
      }
  
      /*adds one cookie to the Cookie Jar */
      public void addToCookieJar(String cookieString, URL docURL) {
        recordCookie(new HttpCookie(docURL, cookieString));
      }
  
      /* loads the cookies from the given filename */
      public void loadCookieJarFromFile(String cookieFileName) {
        try {
            FileReader fr = new FileReader(cookieFileName);
            
            BufferedReader in = new BufferedReader(fr);
  
            try {
                String cookieString;
                while ((cookieString = in.readLine()) != null) {
                    HttpCookie cookie = new HttpCookie(cookieString);
                    // Record the cookie, without notification.  We don't
                    // do a notification for cookies that are read at
                    // program start-up.
                    recordCookie(cookie);
                }
            } finally {
                in.close();
            }
  
            
        } catch (IOException e) {
            // do nothing; it's not an error not to have persistent cookies
        }
  
      }
      
      /* saves the cookies to the given file specified by fname */
      public void saveCookieJarToFile(String cookieFileName) {
        try {
            FileWriter fw = new FileWriter(cookieFileName);
            PrintWriter pw = new PrintWriter(fw, false);
  
            try {
                saveCookiesToStream(pw);
            } finally {
                pw.close();
            }
  
        } catch (IOException e) {
            // REMIND: I18N
            System.err.println("Saving cookies failed " + e.getMessage());
        }
      }
  
      /**
       * Return an array with all of the cookies represented by this
       * jar.  This is useful when the bean is shutting down, and the client
       * wants to make the cookie jar persist.
       */
      public HttpCookie[] getAllCookies() {
  
        Vector result = new Vector();
        Hashtable jar;
        jar = (Hashtable) cookieJar.clone();
        
        synchronized (jar) {
        
            for (Enumeration e = jar.elements(); e.hasMoreElements() ;) {
                Vector v = (Vector) e.nextElement();
                for (int i = 0; i < v.size(); i++) {
                    HttpCookie hc = (HttpCookie) v.elementAt(i);
                    result.addElement(hc);
                    
                }
                
            }
        }
  
        HttpCookie[] resultA = new HttpCookie[result.size()];
        for (int i = 0; i < result.size(); i++) {
            resultA[i] = (HttpCookie) result.elementAt(i);
        }
        return resultA;
      }
  
      /* Gets all cookies that applies for the URL */
      public HttpCookie[] getCookiesForURL(URL url) {
  
        Vector cookieVector = getAllRelevantCookies(url);
  
        if (cookieVector == null) {
            return null;
        }
  
        int i = 0;
        HttpCookie[] cookieArr = new HttpCookie[cookieVector.size()];
  
        for (Enumeration e = cookieVector.elements(); e.hasMoreElements(); ) {
  
            cookieArr[i++] = (HttpCookie)e.nextElement();
  //        System.out.println("cookieArr["+(i-1)+"] = " +cookieArr[i-1].toString());
        }
            
        return cookieArr;
      }
  
      /* this will set the property of enableCookies to isDisabled */
      public void setCookieDisable(boolean isDisabled) {
  
        // Pending visit back this again
        try {
        Properties properties = new Properties();
        properties.load(new FileInputStream("ServerAutoRun.properties") );
        
        
        properties.put("enableCookies", isDisabled ? "false" : "true");
        properties.store(new FileOutputStream("ServerAutoRun.properties"),"comments");
        }
        catch ( Exception e )
        {
                System.out.println("Exception : " + e );
        }
      }
  
      public void discardAllCookies() {
        try {
            if (vceListeners != null) {
                vceListeners.fireVetoableChange("cookie", null, null);
            }
        } catch (PropertyVetoException ex) {
            
        }
        
        cookieJar.clear();
        
      }
  
      /* 
       * purges any expired cookies in the Cookie hashtable.
       */
      public void purgeExpiredCookies() {
        Enumeration cookieLists = cookieJar.elements();
                
        while (cookieLists.hasMoreElements()) {
            Vector cookieList = (Vector)cookieLists.nextElement();
  
            Enumeration cookies = cookieList.elements();
  
            while (cookies.hasMoreElements()) {
                HttpCookie cookie = (HttpCookie)cookies.nextElement();
                
                if (cookie.hasExpired()) {
                    cookieList.removeElement(cookie);
                }   
            }
        }
  
      }
  
      /*********************
       * Listener methods
       *********************/
  
      /* Add listener to CookieJar. If the first listener registers,
       * add CookieJar's listener to sunw.hotjava.misc.Cookies. This 
       * management done to avoid having unnecessary object retention*/
      public void addVetoableChangeListener(VetoableChangeListener l) {
        vceListeners.addVetoableChangeListener(l);
        
      }
  
      /* Removes listener to CookieJar. If there are no more listeners
       * to CookieJar, remove CookieJar's listener to sunw.hotjava.misc.Cookies.
       */
      public void removeVetoableChangeListener(VetoableChangeListener l) {
        vceListeners.removeVetoableChangeListener(l);
      }
      
  
      /*********
       * Older code that could serve as a reminder for future
       *********/
      /**
       * Predicate function which returns true if the cookie appears to be
       * invalid somehow and should not be added to the cookie set.
       */
      /* This code used to be called in recordCookie(HttpCookie cookie),
         however, I couldn't figure out what it would be good for, so
         I took it out for now. See the misc.Cookies in deleted file
         for more context*/
      private boolean shouldRejectCookie(HttpCookie cookie) {
        // REMIND: implement per http-state-mgmt Internet Draft
        return false;
      }
  
  }
  
  
  
  1.1                  
jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/GTest.java
  
  Index: GTest.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/GTest.java,v 1.1 
2002/02/02 03:22:52 rlubke Exp $ 
   * $Revision: 1.1 $
   * $Date: 2002/02/02 03:22:52 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  /**
  * @Author Costin, Ramesh.Mandava
  */
  
  package org.apache.watchdog.task;
  
  import java.net.*;
  import java.io.*;
  import java.util.*;
  import java.net.*;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.TaskContainer;
  
  
  // derived from Jsp
  
  public class GTest extends Task implements TaskContainer {
  
      private static final String ZEROS        = "00000000";
      private static final String CRLF         = "\r\n";
      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;
  
      private static int failureCount = 0;
      private static int passCount = 0;
      private static boolean hasFailed = false;
  
      String prefix = "http";
      String host = "localhost";
      int port = 8080;
      int debug = 0;
  
      private ArrayList children = new ArrayList();
  
      String description = "No description";
  
      String request;
      HashMap requestHeaders = new HashMap();
      String content;
      
      // true if task is nested
      private boolean nested = false;
  
      // Expected response
      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
      HashMap expectHeaders = new HashMap();
  
      // Headers that should not be found in response
      HashMap unexpectedHeaders = new HashMap();
  
      // Match request line
      String returnCode = "";
      String returnCodeMsg = "";
  
      // Actual response
      String responseLine;
      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 ;
  
      /**
       * 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() );
          }
      }
  
      /**
       * <code>setTestName</code> sets the current test name.
       *
       * @param tn current testname.
       */
      public void setTestName ( String tn ) {
          testName = tn;
      }
  
      /**
       * <code>setAssertion</code> sets the assertion text
       * for the current test.
       *
       * @param assertion assertion text
       */
      public void setAssertion ( String assertion ) {
          this.assertion = assertion;
      }
   
      /**
       * <code>setTestStrategy</code> sets the test strategy
       * for the current test.
       *
       * @param strategy test strategy text
       */
      public void setTestStrategy ( String strategy ) {
          testStrategy = strategy;
      }
  
      /**
       * <code>getTestName</code> returns the current 
       * test name.
       *
       * @return a <code>String</code> value
       */
      public String getTestName( ) {
          return testName;
      }
  
      /**
       * <code>getAssertion</code> returns the current
       * assertion text.
       *
       * @return a <code>String</code> value
       */
      public String getAssertion( ) {
          return assertion;
      }
  
      /**
       * <code>getTestStrategy</code> returns the current
       * test strategy test.
       *
       * @return a <code>String</code> value
       */
      public String getTestStrategy( ) {
          return testStrategy;
      }
  
      /**
       * <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() );
              }
          }
      }
  
      /**
       * <code>setFirstTask</code> denotes that current task
       * being executed is the first task within the list.
       *
       * @param a <code>boolean</code> value
       */    
      public void setFirstTask( boolean val ) {
          firstTask = val;
      }
     
  
      /**
       * <code>setLastTask</code> denotes that the current task
       * being executed is the last task within the list.
       *
       * @param a <code>boolean</code> value
       */ 
      public void setLastTask ( boolean val ) {
          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;
      }
  
      /**
       * <code>setHost</code> sets hostname where
       * the target server is running. Defaults to
       * "localhost"
       *
       * @param h a <code>String</code> value
       */
      public void setHost( String h ) {
          this.host = h;
      }
  
      /**
       * <code>setPort</code> sets the port
       * that the target server is listening on.
       * Defaults to "8080"
       *
       * @param portS a <code>String</code> value
       */
      public void setPort( String portS ) {
          this.port = Integer.valueOf( portS ).intValue();
      }
  
      /**
       * <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();
      }
  
      /**
       * <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();
      }
  
      /**
       * <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();
      }
  
      /**
       * <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;
      }
  
      /**
       * <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;
      }
  
      /**
       * <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 HashMap();
          StringTokenizer tok = new StringTokenizer( s, "|" );
          while ( tok.hasMoreElements() ) {
              String header = (String) tok.nextElement();
              setHeaderDetails( header, expectHeaders, false );
          }
      }
  
      /**
       * <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();
          setHeaderDetails( s, unexpectedHeaders, false );
      }
  
      public void setNested( String s ) {
          nested = Boolean.valueOf( s ).booleanValue();
      }
  
      /**
       * <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;
      }
  
      /**
       * <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 );
      }
  
      /**
       * <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;
      }
  
      /**
       * Describe <code>setReturnCodeMsg</code> Sets the expected
       * return 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 setReturnCodeMsg( String message ) {
          this.returnCodeMsg = message;
      }
  
      /**
       * <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 HashMap();
          StringTokenizer tok = new StringTokenizer( s, "|" );
          while ( tok.hasMoreElements() ) {
              String header = (String) tok.nextElement();
              setHeaderDetails( header, requestHeaders, true );
          }
      }
  
      /**
       * Add a Task to this container
       *
       * @param Task to add
       */
      public void addTask(Task task) {
          children.add(task);
      }
  
      /**
       * <code>execute</code> Executes the test.
       *
       * @exception BuildException if an error occurs
       */
      public void execute() throws BuildException {
  
          try {
  
              if ( resultOut != null && !nested ) {
                  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 );
  
              boolean result = checkResponse( magnitude );
  
              if ( !result ) {
                  hasFailed = true;
              }
  
              if ( !children.isEmpty() ) {
                  Iterator iter = children.iterator();
                  while (iter.hasNext()) {
                      Task task = (Task) iter.next();
                      task.perform();
                  }
              }
  
              if ( !hasFailed && !nested ) {
                        passCount++;
                  if ( resultOut != null ) {
                      resultOut.write( "<result>PASS</result>\n".getBytes() );
                  }
                  if ( testName != null ) {
                      System.out.println( " PASSED " + testName + "\n        (" + 
request + ")" );
                  } else {
                      System.out.println( " PASSED " + request );
                  }
              } else if ( hasFailed && !nested ){
                        failureCount++;
                  if ( resultOut != null ) {
                      resultOut.write( "<result>FAIL</result>\n".getBytes() );
                  }
                  if ( testName != null ) {
                      System.out.println( " FAILED " + testName + "\n        (" + 
request + ")" );
                  } else {
                      System.out.println( " FAILED " + request );
                  }
              }
  
              if ( resultOut != null && !nested ) {
                  resultOut.write( "</test>\n".getBytes() );
  
                  if ( lastTask ) {
                      resultOut.write( "</root>\n".getBytes() );
                      resultOut.close();
                  }
              }
                if ( lastTask ) {
                  System.out.println( "\n\n------- TEST SUMMARY -------\n" );
                        System.out.println( "*** " + passCount + " TEST(S) PASSED! 
***" );
                        System.out.println( "*** " + failureCount + " TEST(S) FAILED! 
***" );
              }
  
          } catch ( Exception ex ) {
                failureCount++;
              if ( "No description".equals( description ) ) {
                  System.out.println( " FAIL " + request );
              } else
                  System.out.println( " FAIL " + description + " (" + request + ")" );
  
              ex.printStackTrace();
          } finally {
              if ( !nested ) {
                  hasFailed = false;
              }
          }
      }
  
      /**
       * <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 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 ( returnCodeMsg.equals( "" ) ) {
                                match = resCode;
                        } else {
                                match = ( resCode && resMsg );
                        }
  
                        if ( match != testCondition ) {
                                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 {
                    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 );
                    return false;
            }
        } else {
            System.out.println( " Error in: " + request );
            System.out.println( "        Expecting response from server, received 
null" );
            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 ( !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 );
                                                
                                  /*
                                   * Handle the Content-Type header appropriately
                                   * based on the the test is configured to look for.
                                   */
                                  if ( currentHeaderField.equalsIgnoreCase( 
"content-type" ) ) {
                                      String resVal = (String) headerValues.get( 0 );
                                      if ( currentHeaderValue.indexOf( ';' ) > -1 ) {
                                          if ( debug > 0 ) {
                                              System.out.println( " Exact match for 
Content-Type header required." );
                                          }
                                          if ( currentHeaderValue.equals( resVal ) ) {
                                              numberFound++;
                                              headerValues.remove( 0 );
                                          }
                                      } else if ( resVal.indexOf( currentHeaderValue ) 
> -1 ) {
                                          if ( debug > 0 ) {
                                              System.out.println( " Approximate match 
for Content-Type header required." );
                                          }
                                          numberFound++;
                                          headerValues.remove( 0 );
                                      }
                                  } else 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;
              }
        }
  
             
  
          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 );
              }
          }
  
        if ( !expectResponseBody && responseBody != null ) {
            if ( debug > 0 ) {
                System.out.println( "Received a response body from the server where 
none was expected" );
            }
            return false;
        }
  
          // compare the body
          if ( goldenFile == null )
              return true;
  
          // Get the expected result from the "golden" file.
          byte[] expResult = getExpectedResult();
  
          // Compare the results and set the status
          boolean cmp = true;
  
          if ( exactMatch ) {
              if ( debug > 0 ) {
                  System.out.println( " Performing exact match of server response and 
goldenfile" );
              }
              cmp = compare( responseBody, expResult );
        } else {
              if ( debug > 0 ) {
                  System.out.println( " Performing token match of server response and 
goldenfile" );
              }
              cmp = compareWeak( responseBody, expResult );
        }
  
          if ( cmp != testCondition ) {
  
              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 false;
          }
  
          return true;
      }
  
      
      /**
       * <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, HashMap requestHeaders ) 
      throws Exception {
          // XXX headers are ignored
          Socket socket = new Socket( host, port );
  
          InputStream in = new CRBufferedInputStream( socket.getInputStream() );
  
          // Write the request
          socket.setSoLinger( true, 1000 );
  
          OutputStream out = new BufferedOutputStream( 
                                 socket.getOutputStream() );
          StringBuffer reqbuf = new StringBuffer( 128 );
  
          // set the Host header
          setHeaderDetails( "Host:" + host, requestHeaders, true );
  
          // set the Content-Length header
          if ( content != null ) {
              setHeaderDetails( "Content-Length:" + content.length(),
                                requestHeaders, true );
          }
  
          // set the Cookie header
          if ( testSession != null ) {
              cookieController = ( CookieController ) sessionHash.get( testSession );
  
              if ( cookieController != null ) {
  
                  String releventCookieString = cookieController.applyRelevantCookies( 
requestURL );
  
                  if ( ( releventCookieString != null ) && ( 
!releventCookieString.trim().equals( "" ) ) ) {
                      setHeaderDetails( "Cookie:" + releventCookieString, 
requestHeaders, true );
                  }
              }
          }
  
          if ( debug > 0 ) {
              System.out.println( " REQUEST: " + request );
          }
          reqbuf.append( request ).append( CRLF );;
  
          // append all rquest 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++ ) {
                                reqbuf.append( headerKey ).append( ": " ).append( 
value[ i ] ).append( CRLF );
                                if ( debug > 0 ) {
                                    System.out.println( " REQUEST HEADER: " + 
headerKey + ": " + value[ i ] );
                                }
                        }
              }
          }
  
          /*
  
          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 ( request.indexOf( "HTTP/1." ) > -1 ) {
              reqbuf.append( "" ).append( CRLF );
          }
  
          // append request content 
          if ( content != null ) {
              reqbuf.append( content );
              // XXX no CRLF at the end -see HTTP specs!
          }
          
          byte[] reqbytes = reqbuf.toString().getBytes();
  
          try {
              // write the request
              out.write( reqbytes, 0, reqbytes.length );
              out.flush();
              reqbuf = null;
          } catch ( Exception ex1 ) {
              System.out.println( " Error writing request " + ex1 );
                if ( debug > 0 ) {
                        System.out.println( "Message: " + ex1.getMessage() );
                        ex1.printStackTrace();
                }
          }
  
          // read the response
          try {
    
                responseLine = read( in );
  
                if ( debug > 0 ) {
                        System.out.println( " RESPONSE STATUS-LINE: " + responseLine );
                }
  
                headers = parseHeaders( in );
             
              byte[] result = readBody( in );
  
              if ( result != null ) {
                  responseBody = result;
                        if ( debug > 0 ) {
                            System.out.println( " RESPONSE BODY:\n" + new String( 
responseBody ) );
                        }
                }
                
          } catch ( SocketException ex ) {
              System.out.println( " Socket Exception: " + ex );
              ex.printStackTrace();
          } finally {
                if ( debug > 0 ) {
                        System.out.println( " closing socket" );
                }
                socket.close();
                socket = null;
            }
      }
  
      
      /**
       * <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 = new BufferedInputStream(
                                 new FileInputStream( goldenFile ) );
              return readBody ( in );
          } catch ( Exception ex ) {
              System.out.println( "Golden file not found: " + goldenFile );
              return expResult;
          }
      }
  
      /**
       * <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;
        }
  
        /*
           * 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;
      }
  
      /**
       * <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;
            }
  
          boolean status = true;
  
          String server = new String( fromServer );
          String golden = new String( fromGoldenFile );
  
          StringTokenizer st1 = new StringTokenizer( server );
  
          StringTokenizer st2 = new StringTokenizer( golden );
  
          while ( st1.hasMoreTokens() && st2.hasMoreTokens() ) {
              String tok1 = st1.nextToken();
              String tok2 = st2.nextToken();
  
              if ( !tok1.equals( tok2 ) ) {
                  System.out.println( "\t FAIL*** : Rtok1 = " + tok1
                                      + ", Etok2 = " + tok2 );
                  status = false;
              }
          }
  
          if ( st1.hasMoreTokens() || st2.hasMoreTokens() ) {
               status = false;
          }
  
          if ( !status ) {
              StringBuffer sb = new StringBuffer( 255 );
              sb.append( "ERROR: Server's response and configured goldenfile do not 
match!\n" );
              sb.append( "Response received from server:\n" );
              sb.append( "---------------------------------------------------------\n" 
);
              sb.append( server );
              sb.append( "\nContent of Goldenfile:\n" );
              sb.append( "---------------------------------------------------------\n" 
);
              sb.append( golden );
              sb.append( "\n" );
              System.out.println( sb.toString() );
          }
          return status;
      }
  
      /**
       * <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;
                    }
                }
                sb.append( ( char ) ch );
                 
              } catch ( IOException ex ) {
                  return null;
              }
          }
          return sb.toString().getBytes();
      }
  
      /**
       * <code>setHeaderDetails</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 setHeaderDetails( 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
       * request properties.
       *
       *
       * @exception IOException if an input/output error occurs
       */
      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 );
            }
  
          }
  
          if ( testSession != null ) {
              cookieController = ( CookieController ) sessionHash.get( testSession );
  
              if ( cookieController != null ) {
                  cookieController.recordAnyCookies( cookieVector, requestURL );
              }
          }
  
          return headers;
      }
  
      /**
       * <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);
  
        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.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 == 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();
                }
              }
          }
          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;
      }
  
      /**
       * <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 );
          }
  
          /**
         * <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;
          }
      }
  }
  
  
  
  1.1                  
jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/HttpCookie.java
  
  Index: HttpCookie.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/HttpCookie.java,v 
1.1 2002/02/02 03:22:52 rlubke Exp $ 
   * $Revision: 1.1 $
   * $Date: 2002/02/02 03:22:52 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.watchdog.task;
  
  import java.util.Properties;
  import java.io.*;
  import java.net.URL;
  import java.util.Date;
  import java.util.StringTokenizer;
  
  /**
   * An object which represents an HTTP cookie.  Can be constructed by
   * parsing a string from the set-cookie: header.
   *
   * Syntax: Set-Cookie: NAME=VALUE; expires=DATE;
   *             path=PATH; domain=DOMAIN_NAME; secure
   *
   * All but the first field are optional.
   *
   * @author    Ramesh.Mandava
   */
  
  public class HttpCookie {
      private Date expirationDate = null;
      private String nameAndValue;
      private String path;
      private String domain;
      private boolean isSecure = false;
      private static boolean defaultSet = true;
      private static long defExprTime = 100;
  
      public HttpCookie(String cookieString) {
        /*
        System.out.println("Calling default expiration :");
        getDefaultExpiration();
        */
        parseCookieString(cookieString);
      }
  
      //
      // Constructor for use by the bean
      //
      public HttpCookie(Date expirationDate,
                      String nameAndValue,
                      String path,
                      String domain,
                      boolean isSecure) {
        this.expirationDate = expirationDate;
        this.nameAndValue = nameAndValue;
        this.path = path;
        this.domain = domain;
        this.isSecure = isSecure;
      }
  
      public HttpCookie(URL url, String cookieString) {
        parseCookieString(cookieString);
        applyDefaults(url);
      }
  
      /**
       * Fills in default values for domain, path, etc. from the URL
       * after creation of the cookie.
       */
      private void applyDefaults(URL url) {
        if (domain == null) {
            domain = url.getHost()+":"+((url.getPort() == -1) ? 80 : url.getPort());
        }
  
        if (path == null) {
            path = url.getFile();
  
            // larrylf: The documentation for cookies say that the path is
            // by default, the path of the document, not the filename of the
            // document.  This could be read as not including that document
            // name itself, just its path (this is how NetScape intrprets it)
            // so amputate the document name!
            int last = path.lastIndexOf("/");
            if( last > -1 ) {
                path = path.substring(0, last);
            }
        }
      }
  
  
      /**
       * Parse the given string into its individual components, recording them
       * in the member variables of this object.
       */
      private void parseCookieString(String cookieString) {
        StringTokenizer tokens = new StringTokenizer(cookieString, ";");
  
        if (!tokens.hasMoreTokens()) {
            // REMIND: make this robust against parse errors
            nameAndValue="=";
            return;
        }
  
        nameAndValue = tokens.nextToken().trim();
        
        while (tokens.hasMoreTokens()) {
            String token = tokens.nextToken().trim();
        
            if (token.equalsIgnoreCase("secure")) {
                isSecure = true;
            } else {
                int equIndex = token.indexOf("=");
                
                if (equIndex < 0) {
                    continue;
                    // REMIND: malformed cookie
                }
                
                String attr = token.substring(0, equIndex);
                String val = token.substring(equIndex+1);
                
                if (attr.equalsIgnoreCase("path")) {
                    path = val;
                } else if (attr.equalsIgnoreCase("domain")) {
                    if( val.indexOf(".") == 0 ) {
                        // spec seems to allow for setting the domain in
                        // the form 'domain=.eng.sun.com'.  We want to
                        // trim off the leading '.' so we can allow for
                        // both leading dot and non leading dot forms
                        // without duplicate storage.
                        domain = val.substring(1);
                    } else {
                        domain = val;
                    }
                } else if (attr.equalsIgnoreCase("expires")) {
                    expirationDate = parseExpireDate(val);
                } else {
                    // unknown attribute -- do nothing
                }
            }
        }
  
        // commented the following out, b/c ok to have no expirationDate
        // that means that the cookie should last only for that particular 
        // session.
        //      if (expirationDate == null) {
        //          expirationDate = getDefaultExpiration();
        //      }
      }
      
      /* Returns the default expiration, which is the current time + default
         expiration as specified in the properties file.
         This uses reflection to get at the properties file, since Globals is 
         not in the utils/ directory 
         */
      private Date getDefaultExpiration() {
        if (defaultSet == false) {
            Properties props = new Properties();
            
            try {
                FileInputStream fin = new FileInputStream("ServerAutoRun.properties");
                props.load( fin );
                
                System.out.println("Got properties from ServerAutoRun.properties");
                props.list(System.out);
                
            } catch (IOException ex) {
                System.out.println("HttpCookie getDefaultExpiration : 
ServerAutoRun.properties not found!" + ex);
            }
            
                 // defExprTime = props.getProperty("cookies.default.expiration");
                 defExprTime = Long.parseLong( 
props.getProperty("cookies.default.expiration") );
  
            }
            defaultSet = true;
          
        return (new Date(System.currentTimeMillis() + defExprTime));
        
      }
  
      //======================================================================
      //
      // Accessor functions
      //
  
  
  
       public String getNameValue() {
        return nameAndValue;
      }
  
      /**
       * Returns just the name part of the cookie
       */
       public String getName() {
  
         // it probably can't have null value, but doesn't hurt much
         // to check.
         if (nameAndValue == null) {
             return "=";
         }
         int index = nameAndValue.indexOf("=");
         return (index < 0) ? "=" : nameAndValue.substring(0, index);
       }
  
  
      /**
       * Returns the domain of the cookie as it was presented
       */
       public String getDomain() {
        // REMIND: add port here if appropriate
        return domain;
      }
  
       public String getPath() {
        return path;
      }
  
       public Date getExpirationDate() {
        return expirationDate;
      }
  
      public boolean hasExpired() {
        if(expirationDate == null) {
            return false;
        }
        return (expirationDate.getTime() <= System.currentTimeMillis());
      }
  
      /**
       * Returns true if the cookie has an expiration date (meaning it's
       * persistent), and if the date nas not expired;
       */
      public boolean isSaveable() {
        return (expirationDate != null)
            && (expirationDate.getTime() > System.currentTimeMillis());
      }
  
      public boolean isSaveableInMemory() {
        return ((expirationDate == null) ||
                (expirationDate != null && expirationDate.getTime() > 
System.currentTimeMillis()));
      }
                
       public boolean isSecure() {
        return isSecure;
      }
  
      private Date parseExpireDate(String dateString) {
        // format is wdy, DD-Mon-yyyy HH:mm:ss GMT
        RfcDateParser parser = new RfcDateParser(dateString);
        Date theDate = parser.getDate();
        if (theDate == null) {
            // Expire in some intelligent default time
            theDate = getDefaultExpiration();
        }
        return theDate;
      }
  
      public String toString() {
  
        String result = (nameAndValue == null) ? "=" : nameAndValue;
        if (expirationDate != null) {
            result += "; expires=" + expirationDate;
        }
        
        if (path != null) {
            result += "; path=" + path;
        }
  
        if (domain != null) {
            result += "; domain=" + domain;
        }
  
        if (isSecure) {
            result += "; secure";
        }
  
        return result;
      }
  }
  
  
  
  1.1                  
jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/RfcDateParser.java
  
  Index: RfcDateParser.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-watchdog-4.0/src/tools/org/apache/watchdog/task/RfcDateParser.java,v 
1.1 2002/02/02 03:22:52 rlubke Exp $ 
   * $Revision: 1.1 $
   * $Date: 2002/02/02 03:22:52 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.watchdog.task;
  
  import java.util.Date;
  import java.text.DateFormat;
  import java.util.Locale;
  import java.util.Locale;
  import java.util.StringTokenizer;
  import java.util.TimeZone;
  
  /**
   * A parser for date strings commonly found in http and email headers that
   * follow various RFC conventions.  Given a date-string, the parser will
   * attempt to parse it by trying matches with a set of patterns, returning
   * null on failure, a Date object on success.
   *
   * @author Ramesh.Mandava 
   */
  public class RfcDateParser {
      private static final String debugProp = "hotjava.debug.RfcDateParser";
  
      private boolean isGMT = false;
  
      private static boolean usingJDK = false;
  
      private static DateFormat dateFormat = DateFormat.getInstance();
  
      static final String[] standardFormats = {
        "EEEE', 'dd-MMM-yy HH:mm:ss z",   // RFC 850 (obsoleted by 1036)
        "EEEE', 'dd-MMM-yy HH:mm:ss",     // ditto but no tz. Happens too often
        "EEE', 'dd-MMM-yyyy HH:mm:ss z",  // RFC 822/1123
        "EEE', 'dd MMM yyyy HH:mm:ss z",  // REMIND what rfc? Apache/1.1
        "EEEE', 'dd MMM yyyy HH:mm:ss z", // REMIND what rfc? Apache/1.1
        "EEE', 'dd MMM yyyy hh:mm:ss z",  // REMIND what rfc? Apache/1.1
        "EEEE', 'dd MMM yyyy hh:mm:ss z", // REMIND what rfc? Apache/1.1
        "EEE MMM dd HH:mm:ss z yyyy",      // Date's string output format
        "EEE MMM dd HH:mm:ss yyyy",       // ANSI C asctime format()
        "EEE', 'dd-MMM-yy HH:mm:ss",      // No time zone 2 digit year RFC 1123
        "EEE', 'dd-MMM-yyyy HH:mm:ss"     // No time zone RFC 822/1123
      };
  
      /* because there are problems with JDK1.1.6/SimpleDateFormat with
       * recognizing GMT, we have to create this workaround with the following
       * hardcoded strings */
      static final String[] gmtStandardFormats = {
        "EEEE',' dd-MMM-yy HH:mm:ss 'GMT'",   // RFC 850 (obsoleted by 1036)
        "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",  // RFC 822/1123
        "EEE',' dd MMM yyyy HH:mm:ss 'GMT'",  // REMIND what rfc? Apache/1.1
        "EEEE',' dd MMM yyyy HH:mm:ss 'GMT'", // REMIND what rfc? Apache/1.1
        "EEE',' dd MMM yyyy hh:mm:ss 'GMT'",  // REMIND what rfc? Apache/1.1
        "EEEE',' dd MMM yyyy hh:mm:ss 'GMT'", // REMIND what rfc? Apache/1.1
        "EEE MMM dd HH:mm:ss 'GMT' yyyy"      // Date's string output format
      };
  
      String dateString;
  
      public RfcDateParser(String dateString) {
        this.dateString = dateString.trim();
        if (this.dateString.indexOf("GMT") != -1) {
            isGMT = true;
        }
  
        // use java.text.SimpleDateFormat if present
        try {
            Class c = Class.forName("java.text.SimpleDateFormat");
            usingJDK = true;
        } catch (ClassNotFoundException e) {
        }
        
      }
  
      public Date getDate() {
  
          if (usingJDK == true) {
            int arrayLen = isGMT ? gmtStandardFormats.length : standardFormats.length;
            for (int i = 0; i < arrayLen; i++) {
                Date d = null;
  
                if (isGMT) {
                    d = tryParsing(gmtStandardFormats[i]);
                } else {
                    d = tryParsing(standardFormats[i]);
                }
                if (d != null) {
                    return d;
                }
  
            }
  
            return null;
  
        }  // end clause "if (usingJDK)"
  
        return parseNoJDKDate();
  
      }    
  
      private Date tryParsing(String format) {
  
        java.text.SimpleDateFormat df = new java.text.SimpleDateFormat(format, 
Locale.US);
        if (isGMT) {
            df.setTimeZone(TimeZone.getTimeZone("GMT"));
        }
        try {
                return df.parse(dateString);
        } catch (Exception e) {
            return null;
        }
      }
  
      private Date parseNoJDKDate() {
        // format is wdy, DD-Mon-yyyy HH:mm:ss GMT
        // or
        // format is wdy, DD-Mon-yy HH:mm:ss GMT
        Date fInternalDate = null;
        
        try {
            fInternalDate  = dateFormat.parse( dateString );
        }
        catch (Exception ex) {
        }
        
        // Apply emergency parsing measures to work around
        // Y2K 2 digit year date parse bug in java.util.Date
        // format is wdy, DD-Mon-yy HH:mm:ss GMT
        
        if ( fInternalDate == null ) {
            String newString = new String();
            
            StringTokenizer spaces = new StringTokenizer(dateString, " ");
            
            if ( spaces.countTokens() >= 3 ) {
                newString = newString.concat(spaces.nextToken());
                
                String DDMonyy = spaces.nextToken();
                int idx = DDMonyy.lastIndexOf('-');
                String DDMon = DDMonyy.substring(0, idx);
                
                if ( idx >= 0 ) {
                    String year = DDMonyy.substring(idx+1);
                    
                    if ( year.length() == 2 ) {
                        
                        try { 
                            int yearInt = Integer.parseInt(year);
                            
                            if ( yearInt < 70 ) {
                                yearInt = yearInt+2000;
                                String newYY = Integer.toString(yearInt);
                                
                                newString = newString.concat(" " + DDMon + "-" + 
newYY);
                            }
                            else {
                                return(null);
                            }
                        }
                        catch ( Exception ex ) {
                            return(null);
                        }
                    }
                    else {
                        return(null);
                    }
                }
                else {
                    return(null);
                }
  
                while ( spaces.hasMoreTokens() ) {
                    newString = newString.concat( " " + spaces.nextToken() );
                }
  
                try {
                    fInternalDate  = dateFormat.parse( newString );
                }
                catch (Exception ex) {
                }
            }  // end of if (spaces.countTokens() >= 3)
            else {
                return(null);
            }
        }  // end of if (fInternalDate == null)
  
        return fInternalDate;
      }
  
  } /* class RfcDateParser */
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to