alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

// $Header: /home/cvs/jakarta-jmeter/src/protocol/http/org/apache/jmeter/protocol/http/control/CookieManager.java,v 1.26 2004/03/23 23:23:32 mkostrze Exp $
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
*/

package org.apache.jmeter.protocol.http.control;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.Vector;

import junit.framework.TestCase;

import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.testelement.TestListener;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.PropertyIterator;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
 * This class provides an interface to the netscape cookies file to
 * pass cookies along with a request.
 *
 * @author  Sean Dowd
 * @version $Revision: 1.26 $ $Date: 2004/03/23 23:23:32 $
 */
public class CookieManager
    extends ConfigTestElement
    implements TestListener, Serializable
{
    transient private static Logger log = LoggingManager.getLoggerForClass();

    public static final String CLEAR = "CookieManager.clearEachIteration";
    public static final String COOKIES = "CookieManager.cookies";

    // SimpleDateFormat isn't thread-safe
    // TestElements are cloned for each thread, so
    // we use an instance variable.
    private SimpleDateFormat dateFormat =
        new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss zzz");

    public CookieManager()
    {
		// The cookie specification requires that the timezone be GMT.
		// See http://developer.netscape.com/docs/manuals/communicator/jsguide4/cookies.htm
		// See http://www.cookiecentral.com/faq/
		dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

        setProperty(new CollectionProperty(COOKIES, new ArrayList()));
        setProperty(new BooleanProperty(CLEAR, false));
    }

    public CollectionProperty getCookies()
    {
        return (CollectionProperty) getProperty(COOKIES);
    }

    public int getCookieCount()
    {
        return getCookies().size();
    }

    public boolean getClearEachIteration()
    {
        return getPropertyAsBoolean(CLEAR);
    }

    public void setClearEachIteration(boolean clear)
    {
        setProperty(new BooleanProperty(CLEAR, clear));
    }

    // Incorrect method. Always returns String. I changed CookiePanel code to
    // perform this lookup.
    //public Class getColumnClass(int column)
    //{
    //  return columnNames[column].getClass();
    //}

    public Cookie getCookie(int row)
    {
        return (Cookie) getCookies().get(row);
    }

    /**
     * Save the cookie data to a file.
     */
    public void save(String authFile) throws IOException
    {
        File file = new File(authFile);
        if (!file.isAbsolute())
            file =
                new File(
                    System.getProperty("user.dir") + File.separator + authFile);
        PrintWriter writer = new PrintWriter(new FileWriter(file));
        writer.println("# JMeter generated Cookie file");
        PropertyIterator cookies = getCookies().iterator();
        while (cookies.hasNext())
        {
            Cookie cook = (Cookie) cookies.next().getObjectValue();
            writer.println(cook.toString());
        }
        writer.flush();
        writer.close();
    }

    /**
     * Add cookie data from a file.
     */
    public void addFile(String cookieFile) throws IOException
    {
        File file = new File(cookieFile);
        if (!file.isAbsolute())
            file =
                new File(
                    System.getProperty("user.dir")
                        + File.separator
                        + cookieFile);
        BufferedReader reader = null;
        if (file.canRead())
        {
            reader = new BufferedReader(new FileReader(file));
        }
        else
        {
            throw new IOException("The file you specified cannot be read.");
        }

        String line;
        while ((line = reader.readLine()) != null)
        {
            try
            {
                if (line.startsWith("#") || line.trim().length() == 0)
                    continue;
                String[] st = split(line, "\t", " ");
                int domain = 0;
                int path = 2;
                if (st[path].equals(" "))
                    st[path] = "/";
                boolean secure = Boolean.valueOf(st[3]).booleanValue();
                long expires = new Long(st[4]).longValue();
                int name = 5;
                int value = 6;
                Cookie cookie =
                    new Cookie(
                        st[name],
                        st[value],
                        st[domain],
                        st[path],
                        secure,
                        expires);
                getCookies().addItem(cookie);
            }
            catch (Exception e)
            {
            	reader.close();
                throw new IOException(
                    "Error parsing cookie line\n\t'" + line + "'\n\t" + e);
            }
        }
        reader.close();
    }

    public void recoverRunningVersion()
    {
        //do nothing, the cookie manager has to accept changes.
    }

    public void setRunningVersion(boolean running)
    {
        //do nothing, the cookie manager has to accept changes.
    }

    /**
     * Add a cookie.
     */
    public void add(Cookie c)
    {
    	JMeterContext context = getThreadContext();
        getCookies().addItem(c);
        if(context.isSamplingStarted())
        {
            context.getVariables().put(c.getName(),c.getValue());
        }
    }

    /**
     * Add an empty cookie.
     */
    public void add()
    {
        getCookies().addItem(new Cookie());
    }
    
    /**
     * Remove all the cookies.
     */
    public void clear()
    {
        /*      boolean clear = getClearEachIteration();
                super.clear();
                setClearEachIteration(clear);*/
        setProperty(new CollectionProperty(COOKIES, new ArrayList()));
    }

    /**
     * Remove a cookie.
     */
    public void remove(int index)
    {
        getCookies().remove(index);
    }

    /**
     * Return the number of cookies.
     */
    public int size()
    {
        return getCookies().size();
    }

    /**
     * Return the cookie at index i.
     */
    public Cookie get(int i)
    {
        return (Cookie) getCookies().get(i);
    }

    public String convertLongToDateFormatStr(long dateLong)
    {
        return dateFormat.format(new Date(dateLong));
    }

    /**
     * Find cookies applicable to the given URL and build the Cookie header from
     * them.
     * 
     * @param url URL of the request to which the returned header will be added.
     * @return the value string for the cookie header (goes after "Cookie: "). 
     */
    public String getCookieHeaderForURL(URL url)
    {
        if (!url.getProtocol().toUpperCase().trim().equals("HTTP")
            && !url.getProtocol().toUpperCase().trim().equals("HTTPS"))
            return null;

        StringBuffer header = new StringBuffer();
        for (PropertyIterator enum = getCookies().iterator(); enum.hasNext();)
        {
            Cookie cookie = (Cookie) enum.next().getObjectValue();
            // Add a leading dot to the host name so that host X matches
            // domain .X. This is a breach of the standard, but it's how
            // browsers behave:
            String host= "."+url.getHost();
            if (host.endsWith(cookie.getDomain())
                && url.getFile().startsWith(cookie.getPath())
                && ((cookie.getExpires()==0) // treat as never expiring (bug 27713)
				    ||
                	(System.currentTimeMillis() / 1000) <= cookie.getExpires())				)
            {
                if (header.length() > 0)
                {
                    header.append("; ");
                }
                header.append(cookie.getName()).append("=").append(
                    cookie.getValue());
            }
        }

        if (header.length() != 0)
        {
            return header.toString();
        }
        else
        {
            return null;
        }
    }

    /**
     * Parse the set-cookie header value and store the cookies for later
     * retrieval.
     *
     * @param cookieHeader found after the "Set-Cookie: " in the response header
     * @param url URL used in the request for the above-mentioned response.
     */
    public void addCookieFromHeader(String cookieHeader, URL url)
    {
        StringTokenizer st = new StringTokenizer(cookieHeader, ";");
        String nvp;

        // first n=v is name=value
        nvp = st.nextToken();
        int index = nvp.indexOf("=");
        String name = nvp.substring(0, index);
        String value = nvp.substring(index + 1);
        String domain = "."+url.getHost(); // this is the default
                // the leading dot breaks the standard, but helps in
                // reproducing actual browser behaviour.
        String path = "/"; // this is the default

        Cookie newCookie =
            new Cookie(
                name,
                value,
                domain,
                path,
                false,
                System.currentTimeMillis() + 1000 * 60 * 60 * 24);
        // check the rest of the headers
        while (st.hasMoreTokens())
        {
            nvp = st.nextToken();
            nvp = nvp.trim();
            index = nvp.indexOf("=");
            if (index == -1)
            {
                index = nvp.length();
            }
            String key = nvp.substring(0, index);
            if (key.equalsIgnoreCase("expires"))
            {
                try
                {
                    String expires = nvp.substring(index + 1);
                    Date date = dateFormat.parse(expires);
                    if (date.getTime() > System.currentTimeMillis())
                        //TODO: why this conditional? If it's expired, it's
                        // expired!
                    {
                        newCookie.setExpires(date.getTime());
                    }
                }
                catch (ParseException pe)
                {
                    // This means the cookie did not come in the proper format.
                    // Log an error and don't set an expiration time:
                    log.error("Couldn't parse Cookie expiration time.", pe);
                }
                catch (Exception e)
                {
                    // DateFormat.parse() has been known to throw various
                    // unchecked exceptions in the past, and does still do that
                    // occasionally at the time of this writing (1.4.2 JDKs).
                    // E.g. see http://developer.java.sun.com/developer/bugParade/bugs/4699765.html
                    //
                    // As a workaround for such issues we will catch all
                    // exceptions and react just as we did for ParseException
                    // above:
                    log.error(
                        "Couln't parse Cookie expiration time: likely JDK bug.",
                        e);
                }
            }
            else if (key.equalsIgnoreCase("domain"))
            {
                //trim() is a workaround for bug in Oracle8iAS wherere
            	//cookies would have leading spaces in the domain portion
            	domain= nvp.substring(index + 1).trim();
                
                // The standard dictates domains must have a leading dot,
                // but the new standard (Cookie2) tells us to add it if it's not
                // there:
                if (!domain.startsWith("."))
                {
                    domain= "."+domain;
                }
                
                newCookie.setDomain(domain);
            }
            else if (key.equalsIgnoreCase("path"))
            {
                newCookie.setPath(nvp.substring(index + 1));
            }
            else if (key.equalsIgnoreCase("secure"))
            {
                newCookie.setSecure(true);
            }
        }

        Vector removeIndices = new Vector();
        for (int i = getCookies().size() - 1; i >= 0; i--)
        {
            Cookie cookie = (Cookie) getCookies().get(i).getObjectValue();
            if (cookie == null)
                continue;
            if (cookie.getPath().equals(newCookie.getPath())
                && cookie.getDomain().equals(newCookie.getDomain())
                && cookie.getName().equals(newCookie.getName()))
            {
                removeIndices.addElement(new Integer(i));
            }
        }

        for (Enumeration e = removeIndices.elements(); e.hasMoreElements();)
        {
            index = ((Integer) e.nextElement()).intValue();
            remove(index);
        }

        if (newCookie.getExpires() >= System.currentTimeMillis())
        {
            add(newCookie);
        }
    }

    public void removeCookieNamed(String name)
    {
        PropertyIterator iter = getCookies().iterator();
        while (iter.hasNext())
        {
            Cookie cookie = (Cookie) iter.next().getObjectValue();
            if (cookie.getName().equals(name))
            {
                iter.remove();
            }
        }
    }

    /**
     * Takes a String and a tokenizer character, and returns a new array of
     * strings of the string split by the tokenizer character.
     * 
     * @param splittee  string to be split
     * @param splitChar character to split the string on
     * @param def       default value to place between two split chars that have
     *                  nothing between them
     * @return array of all the tokens.
     */
    public String[] split(String splittee, String splitChar, String def)
    {
        if (splittee == null || splitChar == null)
            return new String[0];
        StringTokenizer tokens;
        String temp;
        int spot;
        while ((spot = splittee.indexOf(splitChar + splitChar)) != -1)
            splittee =
                splittee.substring(0, spot + splitChar.length())
                    + def
                    + splittee.substring(
                        spot + 1 * splitChar.length(),
                        splittee.length());
        Vector returns = new Vector();
        tokens = new StringTokenizer(splittee, splitChar);
        while (tokens.hasMoreTokens())
        {
            temp = (String) tokens.nextToken();
            returns.addElement(temp);
        }
        String[] values = new String[returns.size()];
        returns.copyInto(values);
        return values;
    }

    public String getClassLabel()
    {
        return JMeterUtils.getResString("cookie_manager_title");
    }

    public void testStarted()
    {
    }

    public void testEnded()
    {
    }

    public void testStarted(String host)
    {
    }

    public void testEnded(String host)
    {
    }

    public void testIterationStart(LoopIterationEvent event)
    {
        if (getClearEachIteration())
            clear();
    }

    public static class Test extends TestCase
    {
    	CookieManager man = null;
    	
        public Test(String name)
        {
            super(name);
        }
        private JMeterContext jmctx = null;
        
        public void setUp()
    	{
        	jmctx = JMeterContextService.getContext();
            man = new CookieManager();
            man.setThreadContext(jmctx);
        }


        public void testRemoveCookie() throws Exception
        {
            man.setThreadContext(jmctx);
            man.add(new Cookie("id", "me", "127.0.0.1", "/", false, 0));
            man.removeCookieNamed("id");
            assertEquals(0, man.getCookieCount());
        }

        public void testSendCookie() throws Exception
        {
            man.add(
                new Cookie(
                    "id",
                    "value",
                    "jakarta.apache.org",
                    "/",
                    false,
                    9999999999L));
            HTTPSampler sampler = new HTTPSampler();
            sampler.setDomain("jakarta.apache.org");
            sampler.setPath("/index.html");
            sampler.setMethod(HTTPSampler.GET);
            assertNotNull(man.getCookieHeaderForURL(sampler.getUrl()));
        }

        public void testSendCookie2() throws Exception
        {
            man.add(
                new Cookie(
                    "id",
                    "value",
                    ".apache.org",
                    "/",
                    false,
                    9999999999L));
            HTTPSampler sampler = new HTTPSampler();
            sampler.setDomain("jakarta.apache.org");
            sampler.setPath("/index.html");
            sampler.setMethod(HTTPSampler.GET);
            assertNotNull(man.getCookieHeaderForURL(sampler.getUrl()));
        }
        
        /**
         * Test that the cookie domain field is actually handled as
         * browsers do (i.e.: host X matches domain .X):
         */
        public void testDomainHandling() throws Exception
        {
            URL url= new URL("http://jakarta.apache.org/");
            man.addCookieFromHeader("test=1;domain=.jakarta.apache.org", url);
            assertNotNull(man.getCookieHeaderForURL(url));
        }
        
        /**
         * Test that we won't be tricked by similar host names (this was a past
         * bug, although it never got reported in the bug database):
         */
        public void testSimilarHostNames() throws Exception
        {
            URL url= new URL("http://ache.org/");
            man.addCookieFromHeader("test=1", url);
            url= new URL("http://jakarta.apache.org/");
            assertNull(man.getCookieHeaderForURL(url));
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.