You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by se...@apache.org on 2009/11/17 01:17:12 UTC

svn commit: r881068 - in /jakarta/jmeter/trunk: src/core/org/apache/jmeter/resources/ src/protocol/http/org/apache/jmeter/protocol/http/control/ src/protocol/http/org/apache/jmeter/protocol/http/gui/ src/protocol/http/org/apache/jmeter/protocol/http/sa...

Author: sebb
Date: Tue Nov 17 00:17:11 2009
New Revision: 881068

URL: http://svn.apache.org/viewvc?rev=881068&view=rev
Log:
Bug 47461 - Update Cache Manager to handle Expires HTTP header

Modified:
    jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/CacheManager.java
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/CacheManagerGui.java
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler.java
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPConstantsInterface.java
    jakarta/jmeter/trunk/xdocs/changes.xml
    jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Tue Nov 17 00:17:11 2009
@@ -865,6 +865,7 @@
 url_config_title=HTTP Request Defaults
 url_full_config_title=UrlFull Sample
 url_multipart_config_title=HTTP Multipart Request Defaults
+use_expires=Use Expires header when processing GET requests
 use_keepalive=Use KeepAlive
 use_multipart_for_http_post=Use multipart/form-data for HTTP POST
 use_recording_controller=Use Recording Controller

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/CacheManager.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/CacheManager.java?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/CacheManager.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/CacheManager.java Tue Nov 17 00:17:11 2009
@@ -26,10 +26,13 @@
 import java.net.URLConnection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Date;
 
 import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.util.DateParseException;
+import org.apache.commons.httpclient.util.DateUtil;
 import org.apache.jmeter.config.ConfigTestElement;
 import org.apache.jmeter.engine.event.LoopIterationEvent;
 import org.apache.jmeter.protocol.http.util.HTTPConstantsInterface;
@@ -44,17 +47,24 @@
  */
 public class CacheManager extends ConfigTestElement implements TestListener, Serializable {
 
-    private static final long serialVersionUID = 233L;
+    private static final long serialVersionUID = 234L;
 
     private static final Logger log = LoggingManager.getLoggerForClass();
 
+    //+ JMX attributes, do not change values
     public static final String CLEAR = "clearEachIteration"; // $NON-NLS-1$
-
+    public static final String USE_EXPIRES = "useExpires"; // $NON-NLS-1$
+    //-
+    
     private transient ThreadLocal<Map<String, CacheEntry>> threadCache;
 
+    private transient boolean useExpires; // Cached value
+    
     public CacheManager() {
         setProperty(new BooleanProperty(CLEAR, false));
+        setProperty(new BooleanProperty(USE_EXPIRES, false));
         clearCache();
+        useExpires = false;
     }
 
     /*
@@ -65,9 +75,11 @@
     static class CacheEntry{
         private final String lastModified;
         private final String etag;
-        public CacheEntry(String lastModified, String etag){
+        private final Date expires;
+        public CacheEntry(String lastModified, Date expires, String etag){
            this.lastModified = lastModified;
            this.etag = etag;
+           this.expires = expires;
        }
         public String getLastModified() {
             return lastModified;
@@ -79,10 +91,13 @@
         public String toString(){
             return lastModified+" "+etag;
         }
+        public Date getExpires() {
+            return expires;
+        }
     }
 
     /**
-     * Save the Last-Modified and Etag headers if the result is cacheable.
+     * Save the Last-Modified, Etag, and Expires headers if the result is cacheable.
      *
      * @param conn connection
      * @param res result
@@ -90,14 +105,15 @@
     public void saveDetails(URLConnection conn, SampleResult res){
         if (isCacheable(res)){
             String lastModified = conn.getHeaderField(HTTPConstantsInterface.LAST_MODIFIED);
+            String expires = conn.getHeaderField(HTTPConstantsInterface.EXPIRES);
             String etag = conn.getHeaderField(HTTPConstantsInterface.ETAG);
             String url = conn.getURL().toString();
-            setCache(lastModified, etag, url);
+            setCache(lastModified, expires, etag, url);
         }
     }
 
     /**
-     * Save the Last-Modified and Etag headers if the result is cacheable.
+     * Save the Last-Modified, Etag, and Expires headers if the result is cacheable.
      *
      * @param method
      * @param res result
@@ -105,18 +121,30 @@
     public void saveDetails(HttpMethod method, SampleResult res) throws URIException{
         if (isCacheable(res)){
             String lastModified = getHeader(method ,HTTPConstantsInterface.LAST_MODIFIED);
+            String expires = getHeader(method ,HTTPConstantsInterface.EXPIRES);
             String etag = getHeader(method ,HTTPConstantsInterface.ETAG);
             String url = method.getURI().toString();
-            setCache(lastModified, etag, url);
+            setCache(lastModified, expires, etag, url);
         }
     }
 
     // helper method to save the cache entry
-    private void setCache(String lastModified, String etag, String url) {
+    private void setCache(String lastModified, String expires, String etag, String url) {
         if (log.isDebugEnabled()){
-            log.debug("SET(both) "+url + " " + lastModified + " " + etag);
+            log.debug("SET(both) "+url + " " + lastModified + " " + " " + expires + " " + etag);
         }
-        getCache().put(url, new CacheEntry(lastModified, etag));
+        Date expiresDate = null; // i.e. not using Expires
+        if (expires != null && useExpires) {// Check that the header is present and we are processing Expires
+            try {
+                expiresDate = DateUtil.parseDate(expires);
+            } catch (DateParseException e) {
+                if (log.isDebugEnabled()){
+                    log.debug("Unable to parse Expires: '"+expires+"' "+e);
+                }
+                expiresDate = new Date(0L); // invalid dates must be treated as expired
+            }
+        }
+        getCache().put(url, new CacheEntry(lastModified, expiresDate, etag));
     }
 
     // Helper method to deal with missing headers
@@ -183,6 +211,31 @@
         }
     }
 
+    /**
+     * Check the cache, if the entry has an expires header and the entry has not expired, return true<br/>
+     * @param url URL to look up in cache
+     */
+    public boolean inCache(URL url) {
+        CacheEntry entry = getCache().get(url.toString());
+        if (log.isDebugEnabled()){
+            log.debug("inCache "+url.toString()+" "+entry);
+        }
+        if (entry != null){
+            final Date expiresDate = entry.getExpires();
+            if (expiresDate != null) {
+                if (expiresDate.after(new Date())) {
+                    if (log.isDebugEnabled()){
+                        log.debug("Expires= " + expiresDate + " (Valid)");
+                    }
+                    return true;
+                } else if (log.isDebugEnabled()){
+                    log.debug("Expires= " + expiresDate + " (Expired)");
+                }
+            }
+        }
+        return false;
+    }
+
     private Map<String, CacheEntry> getCache(){
         return threadCache.get();
     }
@@ -195,6 +248,14 @@
         setProperty(new BooleanProperty(CLEAR, clear));
     }
 
+    public boolean getUseExpires() {
+        return getPropertyAsBoolean(USE_EXPIRES);
+    }
+
+    public void setUseExpires(boolean expires) {
+        setProperty(new BooleanProperty(USE_EXPIRES, expires));
+    }
+
     @Override
     public void clear(){
         super.clear();
@@ -227,5 +288,6 @@
         if (getClearEachIteration()) {
             clearCache();
         }
+        useExpires=getUseExpires(); // cache the value
     }
 }
\ No newline at end of file

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/CacheManagerGui.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/CacheManagerGui.java?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/CacheManagerGui.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/CacheManagerGui.java Tue Nov 17 00:17:11 2009
@@ -37,6 +37,8 @@
 
     private JCheckBox clearEachIteration;
 
+    private JCheckBox useExpires;
+
     /**
      * Create a new LoginConfigGui as a standalone component.
      */
@@ -60,7 +62,9 @@
     @Override
     public void configure(TestElement element) {
         super.configure(element);
-        clearEachIteration.setSelected(((CacheManager)element).getClearEachIteration());
+        final CacheManager cacheManager = (CacheManager)element;
+        clearEachIteration.setSelected(cacheManager.getClearEachIteration());
+        useExpires.setSelected(cacheManager.getUseExpires());
     }
 
     /* Implements JMeterGUIComponent.createTestElement() */
@@ -73,8 +77,11 @@
     /* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
     public void modifyTestElement(TestElement element) {
         configureTestElement(element);
-        ((CacheManager)element).setClearEachIteration(clearEachIteration.isSelected());
+        final CacheManager cacheManager = (CacheManager)element;
+        cacheManager.setClearEachIteration(clearEachIteration.isSelected());
+        cacheManager.setUseExpires(useExpires.isSelected());
     }
+
     /**
      * Implements JMeterGUIComponent.clearGui
      */
@@ -82,6 +89,7 @@
     public void clearGui() {
         super.clearGui();
         clearEachIteration.setSelected(false);
+        useExpires.setSelected(false);
     }
 
     /**
@@ -92,11 +100,13 @@
         setBorder(makeBorder());
 
         clearEachIteration = new JCheckBox(JMeterUtils.getResString("clear_cache_per_iter"), false);
+        useExpires = new JCheckBox(JMeterUtils.getResString("use_expires"), false);
 
         JPanel northPanel = new JPanel();
         northPanel.setLayout(new VerticalLayout(5, VerticalLayout.BOTH));
         northPanel.add(makeTitlePanel());
         northPanel.add(clearEachIteration);
+        northPanel.add(useExpires);
         add(northPanel, BorderLayout.NORTH);
     }
 

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler.java?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler.java Tue Nov 17 00:17:11 2009
@@ -454,6 +454,19 @@
         res.setSampleLabel(urlStr);
         
         res.sampleStart(); // Count the retries as well in the time
+
+        // Check cache for an entry with an Expires header in the future
+        final CacheManager cacheManager = getCacheManager();
+        if (cacheManager != null && GET.equalsIgnoreCase(method)) {
+           if (cacheManager.inCache(url)) {
+               res.sampleEnd();
+               res.setResponseCodeOK();
+               res.setResponseMessage("Cached");
+               res.setSuccessful(true);
+               return res;
+           }
+        }
+        
         try {
             // Sampling proper - establish the connection and read the response:
             // Repeatedly try to connect:
@@ -556,7 +569,6 @@
             saveConnectionCookies(conn, url, getCookieManager());
 
             // Save cache information
-            final CacheManager cacheManager = getCacheManager();
             if (cacheManager != null){
                 cacheManager.saveDetails(conn, res);
             }

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java Tue Nov 17 00:17:11 2009
@@ -859,6 +859,16 @@
                 httpMethod = new DeleteMethod(urlStr);
             } else if (method.equals(GET)){
                 httpMethod = new GetMethod(urlStr);
+                final CacheManager cacheManager = getCacheManager();
+                if (cacheManager != null && GET.equalsIgnoreCase(method)) {
+                   if (cacheManager.inCache(url)) {
+                       res.sampleEnd();
+                       res.setResponseCodeOK();
+                       res.setResponseMessage("Cached");
+                       res.setSuccessful(true);
+                       return res;
+                   }
+                }
             } else {
                 log.error("Unexpected method (converted to GET): "+method);
                 httpMethod = new GetMethod(urlStr);

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPConstantsInterface.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPConstantsInterface.java?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPConstantsInterface.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPConstantsInterface.java Tue Nov 17 00:17:11 2009
@@ -61,5 +61,6 @@
     public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; // $NON-NLS-1$
     public static final String ETAG = "Etag"; // $NON-NLS-1$
     public static final String LAST_MODIFIED = "Last-Modified"; // $NON-NLS-1$
+    public static final String EXPIRES = "Expires"; // $NON-NLS-1$
 
 }

Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Tue Nov 17 00:17:11 2009
@@ -116,6 +116,7 @@
 <ul>
 <li>Bug 47622 - enable recording of HTTPS sessions</li>
 <li>Allow Proxy Server to be specified on HTTP Sampler GUI and HTTP Config GUI</li>
+<li>Bug 47461 - Update Cache Manager to handle Expires HTTP header</li>
 </ul>
 
 <h3>Other samplers</h3>

Modified: jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=881068&r1=881067&r2=881068&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml Tue Nov 17 00:17:11 2009
@@ -2679,12 +2679,18 @@
 The HTTP Cache Manager is used to add caching functionality to HTTP requests within its scope.
 </p>
 <p>
-If a sample is successful (i.e. has response code 2xx) then the Last-Modified and Etag values are saved for the URL.
+If a sample is successful (i.e. has response code 2xx) then the Last-Modified and Etag (and Expired if relevant) values are saved for the URL.
 Before executing the next sample, the sampler checks to see if there is an entry in the cache, 
 and if so, the If-Last-Modified and If-None-Match conditional headers are set for the request.
 </p>
 <p>
+Additionally, if the "Use Expires header" option is selected, then the Expires value is checked against the current time.
+If the request is a GET request, and the timestamp is in the future, then the sampler returns immediately,
+without requesting the URL from the remote server. This is intended to emulate browser behaviour.
+</p>
+<p>
 If the requested document has not changed since it was cached, then the response body will be empty.
+Likewise if the Expires date is in the future.
 This may cause problems for Assertions.
 </p>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org