Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.protocol.http.control » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *   http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    *
   17    */
   18   
   19   // For unit tests @see TestCookieManager
   20   
   21   package org.apache.jmeter.protocol.http.control;
   22   
   23   import java.io.BufferedReader;
   24   import java.io.File;
   25   import java.io.FileReader;
   26   import java.io.FileWriter;
   27   import java.io.IOException;
   28   import java.io.PrintWriter;
   29   import java.io.Serializable;
   30   import java.net.URL;
   31   import java.util.ArrayList;
   32   import java.util.Date;
   33   
   34   import org.apache.commons.httpclient.cookie.CookiePolicy;
   35   import org.apache.commons.httpclient.cookie.CookieSpec;
   36   import org.apache.commons.httpclient.cookie.MalformedCookieException;
   37   import org.apache.jmeter.config.ConfigTestElement;
   38   import org.apache.jmeter.engine.event.LoopIterationEvent;
   39   import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
   40   import org.apache.jmeter.testelement.TestListener;
   41   import org.apache.jmeter.testelement.property.BooleanProperty;
   42   import org.apache.jmeter.testelement.property.CollectionProperty;
   43   import org.apache.jmeter.testelement.property.PropertyIterator;
   44   import org.apache.jmeter.threads.JMeterContext;
   45   import org.apache.jmeter.util.JMeterUtils;
   46   import org.apache.jorphan.logging.LoggingManager;
   47   import org.apache.jorphan.util.JOrphanUtils;
   48   import org.apache.log.Logger;
   49   
   50   /**
   51    * This class provides an interface to the netscape cookies file to pass cookies
   52    * along with a request.
   53    *
   54    * Now uses Commons HttpClient parsing and matching code (since 2.1.2)
   55    *
   56    */
   57   public class CookieManager extends ConfigTestElement implements TestListener, Serializable {
   58       private static final long serialVersionUID = 233L;
   59   
   60       private static final Logger log = LoggingManager.getLoggerForClass();
   61   
   62       //++ JMX tag values
   63       private static final String CLEAR = "CookieManager.clearEachIteration";// $NON-NLS-1$
   64   
   65       private static final String COOKIES = "CookieManager.cookies";// $NON-NLS-1$
   66   
   67       private static final String POLICY = "CookieManager.policy"; //$NON-NLS-1$
   68       //-- JMX tag values
   69   
   70       private static final String TAB = "\t"; //$NON-NLS-1$
   71   
   72       // See bug 33796
   73       private static final boolean DELETE_NULL_COOKIES =
   74           JMeterUtils.getPropDefault("CookieManager.delete_null_cookies", true);// $NON-NLS-1$
   75   
   76       // See bug 28715
   77       private static final boolean ALLOW_VARIABLE_COOKIES
   78           = JMeterUtils.getPropDefault("CookieManager.allow_variable_cookies", true);// $NON-NLS-1$
   79   
   80       private static final String COOKIE_NAME_PREFIX =
   81           JMeterUtils.getPropDefault("CookieManager.name.prefix", "COOKIE_").trim();// $NON-NLS-1$ $NON-NLS-2$
   82       
   83       private static final boolean SAVE_COOKIES =
   84           JMeterUtils.getPropDefault("CookieManager.save.cookies", false);// $NON-NLS-1$
   85   
   86       private static final boolean CHECK_COOKIES =
   87           JMeterUtils.getPropDefault("CookieManager.check.cookies", true);// $NON-NLS-1$
   88   
   89       private transient CookieSpec cookieSpec;
   90   
   91       private transient CollectionProperty initialCookies;
   92   
   93       public static final String DEFAULT_POLICY = CookiePolicy.BROWSER_COMPATIBILITY;
   94   
   95       public CookieManager() {
   96           clearCookies(); // Ensure that there is always a collection available
   97       }
   98   
   99       // ensure that the initial cookies are copied to the per-thread instances
  100       public Object clone(){
  101           CookieManager clone = (CookieManager) super.clone();
  102           clone.initialCookies = initialCookies;
  103           clone.cookieSpec = cookieSpec;
  104           return clone;
  105       }
  106   
  107       public String getPolicy() {
  108           return getPropertyAsString(POLICY, DEFAULT_POLICY);
  109       }
  110   
  111       public void setCookiePolicy(String policy){
  112           setProperty(POLICY, policy, DEFAULT_POLICY);
  113       }
  114   
  115       public CollectionProperty getCookies() {
  116           return (CollectionProperty) getProperty(COOKIES);
  117       }
  118   
  119       public int getCookieCount() {// Used by GUI
  120           return getCookies().size();
  121       }
  122   
  123       public boolean getClearEachIteration() {
  124           return getPropertyAsBoolean(CLEAR);
  125       }
  126   
  127       public void setClearEachIteration(boolean clear) {
  128           setProperty(new BooleanProperty(CLEAR, clear));
  129       }
  130   
  131       /**
  132        * Save the static cookie data to a file.
  133        * Cookies are only taken from the GUI - runtime cookies are not included.
  134        */
  135       public void save(String authFile) throws IOException {
  136           File file = new File(authFile);
  137           if (!file.isAbsolute()) {
  138               file = new File(System.getProperty("user.dir") // $NON-NLS-1$
  139                       + File.separator + authFile);
  140           }
  141           PrintWriter writer = new PrintWriter(new FileWriter(file));
  142           writer.println("# JMeter generated Cookie file");// $NON-NLS-1$
  143           PropertyIterator cookies = getCookies().iterator();
  144           long now = System.currentTimeMillis();
  145           while (cookies.hasNext()) {
  146               Cookie cook = (Cookie) cookies.next().getObjectValue();
  147               final long expiresMillis = cook.getExpiresMillis();
  148               if (expiresMillis == 0 || expiresMillis > now) { // only save unexpired cookies
  149                   writer.println(cookieToString(cook));
  150               }
  151           }
  152           writer.flush();
  153           writer.close();
  154       }
  155   
  156       /**
  157        * Add cookie data from a file.
  158        */
  159       public void addFile(String cookieFile) throws IOException {
  160           File file = new File(cookieFile);
  161           if (!file.isAbsolute()) {
  162               file = new File(System.getProperty("user.dir") // $NON-NLS-1$
  163                       + File.separator + cookieFile);
  164           }
  165           BufferedReader reader = null;
  166           if (file.canRead()) {
  167               reader = new BufferedReader(new FileReader(file));
  168           } else {
  169               throw new IOException("The file you specified cannot be read.");
  170           }
  171   
  172           // N.B. this must agree with the save() and cookieToString() methods
  173           String line;
  174           try {
  175               final CollectionProperty cookies = getCookies();
  176               while ((line = reader.readLine()) != null) {
  177                   try {
  178                       if (line.startsWith("#") || line.trim().length() == 0) {//$NON-NLS-1$
  179                           continue;
  180                       }
  181                       String[] st = JOrphanUtils.split(line, TAB, false);
  182   
  183                       final int _domain = 0;
  184                       //final int _ignored = 1;
  185                       final int _path = 2;
  186                       final int _secure = 3;
  187                       final int _expires = 4;
  188                       final int _name = 5;
  189                       final int _value = 6;
  190                       final int _fields = 7;
  191                       if (st.length!=_fields) {
  192                           throw new IOException("Expected "+_fields+" fields, found "+st.length+" in "+line);
  193                       }
  194   
  195                       if (st[_path].length()==0) {
  196                           st[_path] = "/"; //$NON-NLS-1$
  197                       }
  198                       boolean secure = Boolean.valueOf(st[_secure]).booleanValue();
  199                       long expires = new Long(st[_expires]).longValue();
  200                       if (expires==Long.MAX_VALUE) {
  201                           expires=0;
  202                       }
  203                       //long max was used to represent a non-expiring cookie, but that caused problems
  204                       Cookie cookie = new Cookie(st[_name], st[_value], st[_domain], st[_path], secure, expires);
  205                       cookies.addItem(cookie);
  206                   } catch (NumberFormatException e) {
  207                       throw new IOException("Error parsing cookie line\n\t'" + line + "'\n\t" + e);
  208                   }
  209               }
  210           } finally {
  211               reader.close();
  212            }
  213       }
  214   
  215       private String cookieToString(Cookie c){
  216           StringBuffer sb=new StringBuffer(80);
  217           sb.append(c.getDomain());
  218           //flag - if all machines within a given domain can access the variable.
  219           //(from http://www.cookiecentral.com/faq/ 3.5)
  220           sb.append(TAB).append("TRUE");
  221           sb.append(TAB).append(c.getPath());
  222           sb.append(TAB).append(JOrphanUtils.booleanToSTRING(c.getSecure()));
  223           sb.append(TAB).append(c.getExpires());
  224           sb.append(TAB).append(c.getName());
  225           sb.append(TAB).append(c.getValue());
  226           return sb.toString();
  227       }
  228   
  229       public void recoverRunningVersion() {
  230           // do nothing, the cookie manager has to accept changes.
  231       }
  232   
  233       public void setRunningVersion(boolean running) {
  234           // do nothing, the cookie manager has to accept changes.
  235       }
  236   
  237       /**
  238        * Add a cookie.
  239        */
  240       public void add(Cookie c) {
  241           String cv = c.getValue();
  242           String cn = c.getName();
  243           removeMatchingCookies(c); // Can't have two matching cookies
  244   
  245           if (DELETE_NULL_COOKIES && (null == cv || cv.length()==0)) {
  246               if (log.isDebugEnabled()) {
  247                   log.debug("Dropping cookie with null value " + c.toString());
  248               }
  249           } else {
  250               if (log.isDebugEnabled()) {
  251                   log.debug("Add cookie to store " + c.toString());
  252               }
  253               getCookies().addItem(c);
  254               if (SAVE_COOKIES)  {
  255                   JMeterContext context = getThreadContext();
  256                   if (context.isSamplingStarted()) {
  257                       context.getVariables().put(COOKIE_NAME_PREFIX+cn, cv);
  258                   }
  259               }
  260           }
  261       }
  262   
  263       public void clear(){
  264           super.clear();
  265           clearCookies(); // ensure data is set up OK initially
  266       }
  267   
  268       /*
  269        * Remove all the cookies.
  270        */
  271       private void clearCookies() {
  272           log.debug("Clear all cookies from store");
  273           setProperty(new CollectionProperty(COOKIES, new ArrayList()));
  274       }
  275   
  276       /**
  277        * Remove a cookie.
  278        */
  279       public void remove(int index) {// TODO not used by GUI
  280           getCookies().remove(index);
  281       }
  282   
  283       /**
  284        * Return the cookie at index i.
  285        */
  286       public Cookie get(int i) {// Only used by GUI
  287           return (Cookie) getCookies().get(i).getObjectValue();
  288       }
  289   
  290       /*
  291        * Create an HttpClient cookie from a JMeter cookie
  292        */
  293       private org.apache.commons.httpclient.Cookie makeCookie(Cookie jmc){
  294           long exp = jmc.getExpiresMillis();
  295           org.apache.commons.httpclient.Cookie ret=
  296               new org.apache.commons.httpclient.Cookie(
  297                   jmc.getDomain(),
  298                   jmc.getName(),
  299                   jmc.getValue(),
  300                   jmc.getPath(),
  301                   exp > 0 ? new Date(exp) : null, // use null for no expiry
  302                   jmc.getSecure()
  303                  );
  304           ret.setPathAttributeSpecified(jmc.isPathSpecified());
  305           ret.setDomainAttributeSpecified(jmc.isDomainSpecified());
  306           ret.setVersion(jmc.getVersion());
  307           return ret;
  308       }
  309   
  310       /**
  311        * Get array of valid HttpClient cookies for the URL
  312        *
  313        * @param url the target URL
  314        * @return array of HttpClient cookies
  315        *
  316        */
  317       public org.apache.commons.httpclient.Cookie[] getCookiesForUrl(URL url){
  318           CollectionProperty jar=getCookies();
  319           org.apache.commons.httpclient.Cookie cookies[]=
  320               new org.apache.commons.httpclient.Cookie[jar.size()];
  321           int i=0;
  322           for (PropertyIterator iter = getCookies().iterator(); iter.hasNext();) {
  323               Cookie jmcookie = (Cookie) iter.next().getObjectValue();
  324               // Set to running version, to allow function evaluation for the cookie values (bug 28715)
  325               if (ALLOW_VARIABLE_COOKIES) {
  326                   jmcookie.setRunningVersion(true);
  327               }
  328               cookies[i++] = makeCookie(jmcookie);
  329               if (ALLOW_VARIABLE_COOKIES) {
  330                   jmcookie.setRunningVersion(false);
  331               }
  332           }
  333           String host = url.getHost();
  334           String protocol = url.getProtocol();
  335           int port= HTTPSamplerBase.getDefaultPort(protocol,url.getPort());
  336           String path = url.getPath();
  337           boolean secure = HTTPSamplerBase.isSecure(protocol);
  338           return cookieSpec.match(host, port, path, secure, cookies);
  339       }
  340   
  341       /**
  342        * Find cookies applicable to the given URL and build the Cookie header from
  343        * them.
  344        *
  345        * @param url
  346        *            URL of the request to which the returned header will be added.
  347        * @return the value string for the cookie header (goes after "Cookie: ").
  348        */
  349       public String getCookieHeaderForURL(URL url) {
  350           org.apache.commons.httpclient.Cookie[] c = getCookiesForUrl(url);
  351           int count = c.length;
  352           boolean debugEnabled = log.isDebugEnabled();
  353           if (debugEnabled){
  354               log.debug("Found "+count+" cookies for "+url.toExternalForm());
  355           }
  356           if (count <=0){
  357               return null;
  358           }
  359           String hdr=cookieSpec.formatCookieHeader(c).getValue();
  360           if (debugEnabled){
  361               log.debug("Cookie: "+hdr);
  362           }
  363           return hdr;
  364       }
  365   
  366   
  367       public void addCookieFromHeader(String cookieHeader, URL url){
  368           boolean debugEnabled = log.isDebugEnabled();
  369           if (debugEnabled) {
  370               log.debug("Received Cookie: " + cookieHeader + " From: " + url.toExternalForm());
  371           }
  372           String protocol = url.getProtocol();
  373           String host = url.getHost();
  374           int port= HTTPSamplerBase.getDefaultPort(protocol,url.getPort());
  375           String path = url.getPath();
  376           boolean isSecure=HTTPSamplerBase.isSecure(protocol);
  377           org.apache.commons.httpclient.Cookie[] cookies= null;
  378           try {
  379               cookies = cookieSpec.parse(host, port, path, isSecure, cookieHeader);
  380           } catch (MalformedCookieException e) {
  381               log.warn(cookieHeader+e.getLocalizedMessage());
  382           } catch (IllegalArgumentException e) {
  383               log.warn(cookieHeader+e.getLocalizedMessage());
  384           }
  385           if (cookies == null) {
  386               return;
  387           }
  388           for(int i=0;i<cookies.length;i++){
  389               org.apache.commons.httpclient.Cookie cookie = cookies[i];
  390               try {
  391                   if (CHECK_COOKIES) {
  392                       cookieSpec.validate(host, port, path, isSecure, cookie);
  393                   }
  394                   Date expiryDate = cookie.getExpiryDate();
  395                   long exp = 0;
  396                   if (expiryDate!= null) {
  397                       exp=expiryDate.getTime();
  398                   }
  399                   Cookie newCookie = new Cookie(
  400                           cookie.getName(),
  401                           cookie.getValue(),
  402                           cookie.getDomain(),
  403                           cookie.getPath(),
  404                           cookie.getSecure(),
  405                           exp / 1000,
  406                           cookie.isPathAttributeSpecified(),
  407                           cookie.isDomainAttributeSpecified()
  408                           );
  409   
  410                   // Store session cookies as well as unexpired ones
  411                   if (exp == 0 || exp >= System.currentTimeMillis()) {
  412                       newCookie.setVersion(cookie.getVersion());
  413                       add(newCookie); // Has its own debug log; removes matching cookies
  414                   } else {
  415                       removeMatchingCookies(newCookie);
  416                       if (debugEnabled){
  417                           log.debug("Dropping expired Cookie: "+newCookie.toString());
  418                       }
  419                   }
  420               } catch (MalformedCookieException e) { // This means the cookie was wrong for the URL
  421                   log.debug("Not storing invalid cookie: <"+cookieHeader+"> for URL "+url+" ("+e.getLocalizedMessage()+")");
  422               } catch (IllegalArgumentException e) {
  423                   log.warn(cookieHeader+e.getLocalizedMessage());
  424               }
  425           }
  426   
  427       }
  428       /**
  429        * Check if cookies match, i.e. name, path and domain are equal.
  430        * <br/>
  431        * TODO - should we compare secure too?
  432        * @param a
  433        * @param b
  434        * @return true if cookies match
  435        */
  436       private boolean match(Cookie a, Cookie b){
  437           return
  438           a.getName().equals(b.getName())
  439           &&
  440           a.getPath().equals(b.getPath())
  441           &&
  442           a.getDomain().equals(b.getDomain());
  443       }
  444   
  445       private void removeMatchingCookies(Cookie newCookie){
  446           // Scan for any matching cookies
  447           PropertyIterator iter = getCookies().iterator();
  448           while (iter.hasNext()) {
  449               Cookie cookie = (Cookie) iter.next().getObjectValue();
  450               if (cookie == null) {// TODO is this possible?
  451                   continue;
  452               }
  453               if (match(cookie,newCookie)) {
  454                   if (log.isDebugEnabled()) {
  455                       log.debug("New Cookie = " + newCookie.toString()
  456                                 + " removing matching Cookie " + cookie.toString());
  457                   }
  458                   iter.remove();
  459               }
  460           }
  461       }
  462   
  463       public void testStarted() {
  464           initialCookies = getCookies();
  465           cookieSpec = CookiePolicy.getCookieSpec(getPolicy());
  466           if (log.isDebugEnabled()){
  467               log.debug("Policy: "+getPolicy()+" Clear: "+getClearEachIteration());
  468           }
  469       }
  470   
  471       public void testEnded() {
  472       }
  473   
  474       public void testStarted(String host) {
  475           testStarted();
  476       }
  477   
  478       public void testEnded(String host) {
  479       }
  480   
  481       public void testIterationStart(LoopIterationEvent event) {
  482           if (getClearEachIteration()) {
  483               log.debug("Initialise cookies from pre-defined list");
  484               // No need to call clear
  485               setProperty((CollectionProperty)initialCookies.clone());
  486           }
  487       }
  488   }

Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.protocol.http.control » [javadoc | source]