cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Miles Elam <mi...@pcextremist.com>
Subject Re: invalid caching problem
Date Sat, 17 May 2003 04:27:55 GMT
Jeremy Quinn wrote:

> I did a set of tests (below) to see the different HTTP Request and 
> Response headers, when using expiring and non-expiring Pipelines.
>
> Tests: (just request/response & cache-relevant headers)


<snip />

> 1) There are never any 'date' headers in the Response, so you never 
> get a 'conditional-GET' from the Browser and consequentially never 
> send a 304 response, meaning we always send the page. (This just isn't 
> implemented yet, right?) 


I just poked around in the code and can't find where a problem would 
occur (I don't have my dev server up right now so I can't check it right 
away).  Are you sure that you are using a caching pipeline?  A 
non-caching pipeline will not send a timestamp for non-readers...ever.  
The timestamp is keyed to the cached object.  No cached object == no 
last modified timestamp.  These are the relevant functions to my knowledge:

AbstractProcessingPipeline.java starting at line 461

    public boolean process(Environment environment)
    throws ProcessingException {
        // If this is an internal request, lastConsumer was reset!
        if ( null == this.lastConsumer ) {
            this.lastConsumer = this.serializer;
        }
        this.preparePipeline(environment);

        // See if we need to set an "Expires:" header
        if (this.expires != 0) {
            Response res = 
ObjectModelHelper.getResponse(environment.getObjectModel());
            res.setDateHeader("Expires", System.currentTimeMillis() + 
expires);
            res.setHeader("Cache-Control", "max-age=" + expires/1000 + 
", public");
            if (this.getLogger().isDebugEnabled())
                this.getLogger().debug("Setting a new Expires object for 
this resource");
            
environment.getObjectModel().put(ObjectModelHelper.EXPIRES_OBJECT,
                 new Long(expires + System.currentTimeMillis()));
        }

        if ( this.reader != null ) {
            if (this.checkIfModified( environment, 
this.reader.getLastModified() )) {
                return true;
            }

            return this.processReader(environment);
        } else {
            this.connectPipeline(environment);
            return this.processXMLPipeline(environment);
        }
    }


AbstractCachingProcessingPipeline.java starting at line 214

    protected boolean processXMLPipeline(Environment environment)
    throws ProcessingException {
        if (this.toCacheKey == null && this.cachedResponse == null) {
            return super.processXMLPipeline( environment );
        } else if (this.cachedResponse != null && 
this.completeResponseIsCached) {

            // Allow for 304 (not modified) responses in dynamic content
            if (super.checkIfModified( environment, 
this.cachedLastModified )) {
                return true;
            }

             ...truncated...

----------------------------------------------------

"validatePipeline" checks the expiration on the CachedResponse.  If the 
resource hasn't expired, no subsequent CacheValidity checks are made.  
This is the primer for the "process" method.

"checkIfModified" calls HttpEnvironment's "isResponseModified".  It is 
the latter that sets the Last-Modified HTTP header.  As you can see, the 
test for a reader happens in "process".  For dynamic (pipeline) content, 
"checkIfModified" is called from within "processXMLPipeline" if and only 
if there is a CachedResponse object handy.

And this is where I am confused.  In your tests, the expiration is 
affecting the freshness of the response.  This implies that you are in a 
caching pipeline.  However, the lack of a last mod timestamp should only 
happen if you are using a non-caching pipeline or if it's the very first 
access on the resource.  (If there is no cached response, there can be 
no timestamp associated with that response.)

There are basically four behaviors for pipelines (I'm lumping Caching 
and CachingPoint together here):

1) Non-caching/non-expiring
  - No CachedResponse object is generated
  - Never sets a Last-Modified nor an Expires header
  - Pipelines are always executed

2) Non-caching/expiring
  - No CachedResponse object is generated
  - Never sets a Last-Modified header
  - Sets an Expires header
  - Pipelines are always executed

3) Caching/non-expiring
  - CachedResponse object is generated
  - Sets Last-Modified header on second and subsequent accesses.  (Needs 
a cached value to work)
  - Never sets an Expires header
  - Pipelines are only executed when CacheValidity checks fail

4) Caching/expiring
  - CachedResponse object is generated
  - Sets an Expires header
  - Sets Last-Modified header on second (and subsequent) accesses.
  - Pipelines are only executed when both (a) resource expiry timeout 
has elapsed and (b) CacheValidity checks fail

Someone correct me if I'm wrong as I'm learning as I go.  Anyone's 
insights into this are more than welcome.

- Miles Elam



Mime
View raw message