ResourceHandler - ifModifiedSince

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

ResourceHandler - ifModifiedSince

Schmidlin Franck, Home
ResourceHandler - ifModifiedSince

 
Dear all,

My application uses jetty to expose simple HTML pages which tend to share the same name, but are located in different webroots.

The actual webroot is configurable, but the exposed URL stays the same.
Thus, http://localhost/myapp/test.html will point to either webroot1/test.html or webroot2/test.html.

My problem is that once I've accessed http://localhost/myapp/test.html, my browser (IE.5.5+) caches the file and will not reflect the actual file I am trying to access. To work around this, I have created a handler based almost entirely on ResourceHandler but with the following modifications.

This is not an elegant solution, because I would prefer to simply extend ResourceHandler. But this is not possible, because of the tight coupling between it and the Resource implementation, and the private passConditionalHeaders()

Can anyone think of a nicer way to achieve the same result?

Thanks

// -- Code extracts (my code marked as /** - */)

    private boolean passConditionalHeaders(org.mortbay.http.HttpRequest request,
                                           org.mortbay.http.HttpResponse response,
                                           org.mortbay.util.Resource resource)
        throws java.io.IOException
    {
        if (!request.getMethod().equals(org.mortbay.http.HttpRequest.__HEAD))
        {
            // If we have meta data for the file
            // Try a direct match for most common requests. Avoids parsing the date.
            org.mortbay.http.HttpContext.ResourceMetaData metaData =
                (org.mortbay.http.HttpContext.ResourceMetaData)resource.getAssociate();
            if (metaData!=null)
            {
                String ifms=request.getField(org.mortbay.http.HttpFields.__IfModifiedSince);
                String mdlm=metaData.getLastModified();
                if (ifms!=null && mdlm!=null && ifms.equals(mdlm))
                {
                    response.setStatus(org.mortbay.http.HttpResponse.__304_Not_Modified);
                    request.setHandled(true);
                    return false;
                }
            }
   
            long date=0;
            // Parse the if[un]modified dates and compare to resource
           
            if ((date=request.getDateField(org.mortbay.http.HttpFields.__IfUnmodifiedSince))>0)
            {
                if (resource.lastModified()/1000 > date/1000)
                {
                    response.sendError(org.mortbay.http.HttpResponse.__412_Precondition_Failed);
                    return false;
                }
            }
           
            if ((date=request.getDateField(org.mortbay.http.HttpFields.__IfModifiedSince))>0)
            {
/** - */                // If the browser is asking if the file was changed before this instance of MyApplication started,

/** - */                // we lie to it and say yes, to ensure it fetches one clean copy of the file
/** - */                if(date < MyApplication.StartTime)
/** - */                {
/** - */                    return true;
/** - */                }
            
/** - */                // Otherwise, we can trust that the browser has at least one clean version
/** - */                // and we can relie on the file lastmodified date.
                if (resource.lastModified()/1000 <= date/1000)
                {
                    response.setStatus(org.mortbay.http.HttpResponse.__304_Not_Modified);
                    request.setHandled(true);
                    return false;
                }
            }
  
        }
        return true;
    }//passConditionalHeaders()

// -------------------------------------------------------------------------
public void writeHeaders(
org.mortbay.http.HttpResponse response, org.mortbay.util.Resource resource, long count,
/** - */ boolean iFakeLastModifiedDate)
throws java.io.IOException
    {
        org.mortbay.http.HttpContext.ResourceMetaData metaData =
            (org.mortbay.http.HttpContext.ResourceMetaData)resource.getAssociate();

        response.setContentType(metaData.getEncoding());
        if (count != -1)
        {
            if (count==resource.length())
                response.setField(org.mortbay.http.HttpFields.__ContentLength,metaData.getLength());
            else
                response.setContentLength((int)count);
        }

/** - */        // Let the browser think that the file was last modified when we started AMyApplication
/** - */        // This will ensure that the browser reload the file at least once
/** - */        if(iFakeLastModifiedDate && resource.lastModified() < MyApplication.StartTime)
/** - */        {
/** - */            com.anite.connect.logging.LogManager.trace(this, "Setting Last-Modified to application's start date");

/** - */           
/** - */            response.setField(
/** - */                org.mortbay.http.HttpFields.__LastModified,
/** - */                org.mortbay.http.HttpFields.__dateSend.format(
/** - */                    new java.util.Date(com.anite.connect.kernel.MyApplication.StartTime)));
/** - */        }
/** - */        else
/** - */        {
            response.setField(org.mortbay.http.HttpFields.__LastModified,metaData.getLastModified());
/** - */        }
       
        if (_acceptRanges && response.getHttpRequest().getDotVersion()>0)
            response.setField(org.mortbay.http.HttpFields.__AcceptRanges,"bytes");
    }//writeHeaders()

// ------------------------------------------------------------

public void sendData(
org.mortbay.http.HttpRequest request, org.mortbay.http.HttpResponse response,
String pathInContext, org.mortbay.util.Resource resource, boolean writeHeaders)
throws java.io.IOException
    {
/** - */        // If the client only wants files last modified before we'd started this instance
/** - */        // of ApplicationConnect, it may have cached the wrong file. Better to lie to the
/** - */        // browser and let it think that the file was last modified when we started this instance.
/** - */        long date = request.getDateField(org.mortbay.http.HttpFields.__IfModifiedSince);
/** - */        boolean fakeLastModifiedDate = (date > 0 && MyApplication.StartTime/1000 > date/1000);

// Then as per org.mortbay.http.handler.ResourceHandler#sendData() but with calls to writeHeaders()
// changed to call the modified writeHeaders()


Scanned for viruses by MessageLabs. The integrity and security of this message cannot be guaranteed. This email is intended for the named recipient only, and may contain confidential information and proprietary material. Any unauthorised use or disclosure is prohibited.
Reply | Threaded
Open this post in threaded view
|

RE: ResourceHandler - ifModifiedSince

Tony Seebregts
ResourceHandler - ifModifiedSince

Hi,

 

Have you tried setting the relevant headers in the returned HTML:

 

-          Cache-Control

-          Expires

-          Last-Modified

-          Pragma: no-cache

 

Some combination of those generally stops the browser caching a page.

 

Regards

 

Tony

 


From: [hidden email] [mailto:[hidden email]] On Behalf Of Schmidlin Franck, Home
Sent: 3 June 2005 10:52
To: [hidden email]
Subject: [jetty-discuss] ResourceHandler - ifModifiedSince

 

 
Dear all,

My application uses jetty to expose simple HTML pages which tend to share the same name, but are located in different webroots.

The actual webroot is configurable, but the exposed URL stays the same.
Thus, http://localhost/myapp/test.html will point to either webroot1/test.html or webroot2/test.html.

My problem is that once I've accessed http://localhost/myapp/test.html, my browser (IE.5.5+) caches the file and will not reflect the actual file I am trying to access. To work around this, I have created a handler based almost entirely on ResourceHandler but with the following modifications.

This is not an elegant solution, because I would prefer to simply extend ResourceHandler. But this is not possible, because of the tight coupling between it and the Resource implementation, and the private passConditionalHeaders()

Can anyone think of a nicer way to achieve the same result?

Thanks

// -- Code extracts (my code marked as /** - */)

    private boolean passConditionalHeaders(org.mortbay.http.HttpRequest request,
                                           org.mortbay.http.HttpResponse response,
                                           org.mortbay.util.Resource resource)
        throws java.io.IOException
    {
        if (!request.getMethod().equals(org.mortbay.http.HttpRequest.__HEAD))
        {
            // If we have meta data for the file
            // Try a direct match for most common requests. Avoids parsing the date.
            org.mortbay.http.HttpContext.ResourceMetaData metaData =
                (org.mortbay.http.HttpContext.ResourceMetaData)resource.getAssociate();
            if (metaData!=null)
            {
                String ifms=request.getField(org.mortbay.http.HttpFields.__IfModifiedSince);
                String mdlm=metaData.getLastModified();
                if (ifms!=null && mdlm!=null && ifms.equals(mdlm))
                {
                    response.setStatus(org.mortbay.http.HttpResponse.__304_Not_Modified);
                    request.setHandled(true);
                    return false;
                }
            }
   
            long date=0;
            // Parse the if[un]modified dates and compare to resource
           
            if ((date=request.getDateField(org.mortbay.http.HttpFields.__IfUnmodifiedSince))>0)
            {
                if (resource.lastModified()/1000 > date/1000)
                {
                    response.sendError(org.mortbay.http.HttpResponse.__412_Precondition_Failed);
                    return false;
                }
            }
           
            if ((date=request.getDateField(org.mortbay.http.HttpFields.__IfModifiedSince))>0)
            {
/** - */                // If the browser is asking if the file was changed before this instance of MyApplication started,

/** - */                // we lie to it and say yes, to ensure it fetches one clean copy of the file
/** - */                if(date < MyApplication.StartTime)
/** - */                {
/** - */                    return true;
/** - */                }
            
/** - */                // Otherwise, we can trust that the browser has at least one clean version
/** - */                // and we can relie on the file lastmodified date.
                if (resource.lastModified()/1000 <= date/1000)
                {
                    response.setStatus(org.mortbay.http.HttpResponse.__304_Not_Modified);
                    request.setHandled(true);
                    return false;
                }
            }
  
        }
        return true;
    }//passConditionalHeaders()

// -------------------------------------------------------------------------
public void writeHeaders(
org.mortbay.http.HttpResponse response, org.mortbay.util.Resource resource, long count,
/** - */ boolean iFakeLastModifiedDate)
throws java.io.IOException
    {
        org.mortbay.http.HttpContext.ResourceMetaData metaData =
            (org.mortbay.http.HttpContext.ResourceMetaData)resource.getAssociate();

        response.setContentType(metaData.getEncoding());
        if (count != -1)
        {
            if (count==resource.length())
                response.setField(org.mortbay.http.HttpFields.__ContentLength,metaData.getLength());
            else
                response.setContentLength((int)count);
        }

/** - */        // Let the browser think that the file was last modified when we started AMyApplication
/** - */        // This will ensure that the browser reload the file at least once
/** - */        if(iFakeLastModifiedDate && resource.lastModified() < MyApplication.StartTime)
/** - */        {
/** - */            com.anite.connect.logging.LogManager.trace(this, "Setting Last-Modified to application's start date");

/** - */           
/** - */            response.setField(
/** - */                org.mortbay.http.HttpFields.__LastModified,
/** - */                org.mortbay.http.HttpFields.__dateSend.format(
/** - */                    new java.util.Date(com.anite.connect.kernel.MyApplication.StartTime)));
/** - */        }
/** - */        else
/** - */        {
            response.setField(org.mortbay.http.HttpFields.__LastModified,metaData.getLastModified());
/** - */        }
       
        if (_acceptRanges && response.getHttpRequest().getDotVersion()>0)
            response.setField(org.mortbay.http.HttpFields.__AcceptRanges,"bytes");
    }//writeHeaders()

// ------------------------------------------------------------

public void sendData(
org.mortbay.http.HttpRequest request, org.mortbay.http.HttpResponse response,
String pathInContext, org.mortbay.util.Resource resource, boolean writeHeaders)
throws java.io.IOException
    {
/** - */        // If the client only wants files last modified before we'd started this instance
/** - */        // of ApplicationConnect, it may have cached the wrong file. Better to lie to the
/** - */        // browser and let it think that the file was last modified when we started this instance.
/** - */        long date = request.getDateField(org.mortbay.http.HttpFields.__IfModifiedSince);
/** - */        boolean fakeLastModifiedDate = (date > 0 && MyApplication.StartTime/1000 > date/1000);

// Then as per org.mortbay.http.handler.ResourceHandler#sendData() but with calls to writeHeaders()
// changed to call the modified writeHeaders()


Scanned for viruses by MessageLabs. The integrity and security of this message cannot be guaranteed. This email is intended for the named recipient only, and may contain confidential information and proprietary material. Any unauthorised use or disclosure is prohibited.

Reply | Threaded
Open this post in threaded view
|

RE: ResourceHandler - ifModifiedSince

Schmidlin Franck, Home
In reply to this post by Schmidlin Franck, Home
RE: ResourceHandler - ifModifiedSince

 
I could,

but all it takes is one rogue file to mess it up. I prefer a solution that works regardless of the file.
Also, I do not just serve HTML files.
I have graphics that are all called banner.gif, and text files that are all called runtimeLog_0.txt

but thanks for the quick suggestion

Franck


------------------
Message: 2
From: "Tony Seebregts" <[hidden email]>
To: <[hidden email]>
Subject: RE: [jetty-discuss] ResourceHandler - ifModifiedSince
Date: Fri, 3 Jun 2005 11:09:17 +0200
Reply-To: [hidden email]

Hi,

Have you tried setting the relevant headers in the returned HTML:

-          Cache-Control
-          Expires
-          Last-Modified
-          Pragma: no-cache

Some combination of those generally stops the browser caching a page.

Regards

Tony
  _____ 


Scanned for viruses by MessageLabs. The integrity and security of this message cannot be guaranteed. This email is intended for the named recipient only, and may contain confidential information and proprietary material. Any unauthorised use or disclosure is prohibited.
Reply | Threaded
Open this post in threaded view
|

RE: RE: ResourceHandler - ifModifiedSince

Silvio Bierman-3
Franck,

You should set the headers in the servlet/filter when returning the data
instead of inside HTML files. This will work for HTML files but also for any
other data you serve to a browser like .gif, .js, .class etc.

Regards,

Silvio Bierman



-----Original Message-----
From: [hidden email]
[mailto:[hidden email]]On Behalf Of Schmidlin
Franck, Home
Sent: 03 June, 2005 11:28 AM
To: [hidden email]
Subject: [jetty-discuss] RE: ResourceHandler - ifModifiedSince



I could,
but all it takes is one rogue file to mess it up. I prefer a solution that
works regardless of the file.
Also, I do not just serve HTML files.
I have graphics that are all called banner.gif, and text files that are all
called runtimeLog_0.txt
but thanks for the quick suggestion
Franck


------------------
Message: 2
From: "Tony Seebregts" <[hidden email]>
To: <[hidden email]>
Subject: RE: [jetty-discuss] ResourceHandler - ifModifiedSince
Date: Fri, 3 Jun 2005 11:09:17 +0200
Reply-To: [hidden email]
Hi,
Have you tried setting the relevant headers in the returned HTML:
-          Cache-Control
-          Expires
-          Last-Modified
-          Pragma: no-cache
Some combination of those generally stops the browser caching a page.
Regards
Tony
  _____

Scanned for viruses by MessageLabs. The integrity and security of this
message cannot be guaranteed. This email is intended for the named recipient
only, and may contain confidential information and proprietary material. Any
unauthorised use or disclosure is prohibited.



-------------------------------------------------------
This SF.Net email is sponsored by Yahoo.
Introducing Yahoo! Search Developer Network - Create apps using Yahoo!
Search APIs Find out how you can build Yahoo! directly into your own
Applications - visit http://developer.yahoo.net/?fr=offad-ysdn-ostg-q22005
_______________________________________________
jetty-discuss mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jetty-discuss