participate


Sun Java System Web Server - controlling the browser cache
<<   Back to Forum  |   Give us Feedback
This topic has 9 replies on 1 page.
703703
Posts:1
Registered: 6/25/03
controlling the browser cache   
Jun 25, 2003 7:45 AM

 
Because I have no control on the contents of the site, I would like to tell the browser to check for new pages once a day.

I tried with the set-cache-control max-age=86400 parameter, this works only for the first day. Afterwards the browser keeps asking for the page, and the webserver responds with a 304 use local copy. There are no new directions in the http headers.

(How) can I do this?
 
joe.mccabe
Posts:261
Registered: 3/7/03
Re: controlling the browser cache   
Jun 26, 2003 10:54 AM (reply 1 of 9)  (In reply to original post )

 
Seems to be working correctly though. You told the browser to use the local version for maxage=86400. After this time the browser began asking the server if it should refresh. It does this with an "If-modified" header. The server replies that the browser should use its locally cached version rather than transfer a fresh copy.

If you want to force the browser to grab a new version you need to explore the "Expires" header. There's no good way to do this out-of-the-box, but a simple NSAPI could be created that would set the Expires header to now+24Hours.
 
henkfictorie
Posts:6
Registered: 7/29/02
Re: controlling the browser cache   
Jul 31, 2003 3:49 AM (reply 2 of 9)  (In reply to original post )

 
I had the same problem. The problem is that the server when it sends the 304 response doesn't set a new Expires or Cache-Control header. The result of this all is that the client browser keeps asking if a modified version of the URL exists.
I have writen a SAF which set an Expires header in a 304 response. If you wish I can send you the source code.
 
adam roybal
Posts:1
Registered: 9/3/03
Re: controlling the browser cache   
Nov 19, 2003 10:04 PM (reply 3 of 9)  (In reply to #2 )

 
I am in the same boat as the original writer of this note.

I would love to have the source code and see if it will solve my exact same problem. I am running WebServer v6.0sp6 and this problem is killing our CGI app's repsonse time. This 3rd party web app has a ton of GIFs.

Thanks,

Adam Roybal
 
joe.mccabe
Posts:261
Registered: 3/7/03
Re: controlling the browser cache   
Nov 19, 2003 10:19 PM (reply 4 of 9)  (In reply to #3 )

 
A simple SAF that would set an expires header would look something like this:

int expires_header( pblock pb, Session *sn, Request *rq ){
int return_value = REQ_NOACTION;
char expdate[50];
int res;
time_t t_expiration;
struct tm tm_expiration;

int offset=300; /
The offset, in seconds */

time(&t_expiration);
t_expiration += offset;
system_gmtime(&t_expiration, &tm_expiration);
util_strftime(expdate,HTTP_DATE_FMT,&tm_expiration);
param_free(pblock_remove("expires",rq->srvhdrs));
pblock_nvinsert("expires",expdate,rq->srvhdrs);

return return_value;
}

This would (in my humble opinion) work best as a PathCheck. It would fairly trivial to adapt this to accept different values from the obj.conf, and to only do stuff in certain situations (e.g. when a 304 is the result code).

I am certain there are more fleshed out implementations of this in NSAPI form on the net.
 
henkfictorie
Posts:6
Registered: 7/29/02
Re: controlling the browser cache   
Dec 2, 2003 4:14 AM (reply 5 of 9)  (In reply to #4 )

 
I have already emailed the source code to an interested person. The code is a more detailed version of the code from Joe. I got that code on a request I send to technical support at Sun (case 36586182). Here is my code:
int kpn_set_cacheable(pblock *pb, Session *sn, Request *rq)
{
    char *max_age = 0;
 
    rq->directive_is_cacheable = 1;
    pblock_nvinsert("Cache-control", "public", rq->srvhdrs);
    max_age = pblock_findval("max-age", pb);
    if (max_age)
    {
        time_t max_age_t = 0;
        if (sscanf(max_age, "%ld", &max_age_t) == 1)
        {
            char expires_string[128];
            time_t cur_time = 0;
            struct tm expires, *expires_ptr;
            char *ifmodifiedsince = 0;
 
            char *path, modified_time[128];
            struct stat *finfo;
            time_t tp;
            struct tm res, *resp;
 
            if (rq->protv_num > 101)          /* Must be HTTP/1.1 or lower */
            {
                log_error(LOG_INFORM, "set_cacheable", sn, rq, "protocol higher as HTTP/1.1: %d",
                          rq->protv_num );
                return REQ_NOACTION;
            }
            cur_time = time(0);
            cur_time += max_age_t;
            expires_ptr = system_gmtime(&cur_time, &expires);
            util_strftime(expires_string, HTTP_DATE_FMT, &expires);
            param_free(pblock_remove("expires", rq->srvhdrs));
            pblock_nvinsert("expires", expires_string, rq->srvhdrs);
 
            /* determine 200 or 304 */
            ifmodifiedsince = pblock_findval("if-modified-since", rq->headers);
            if (ifmodifiedsince == 0)
            {
                return REQ_NOACTION; /* 200 response */
            }
            path = pblock_findval("path", rq->vars);
            if (!(finfo = request_stat_path(path, rq)))
            {
                log_error(LOG_INFORM, "set_cacheable", sn, rq, "could not stat path %s", path);
                return REQ_NOACTION;
            }
            tp = finfo->st_mtime;
            resp = system_gmtime(&tp, &res);
            if (util_later_than(&res, ifmodifiedsince) == 1) /* if not modified since */
            {
                protocol_status(sn, rq, PROTOCOL_NOT_MODIFIED, NULL);
                /* We need to get rid of the superfluous HTTP headers. */
                param_free(pblock_remove("content-type", rq->srvhdrs));
                param_free(pblock_remove("Cache-control", rq->srvhdrs));
 
                /* send response here, do not let the iplanet internal function do this.
                   The internal function strips of the 'Expires' header */
                if (protocol_start_response(sn, rq) == REQ_ABORTED)
                {
                    log_error(LOG_INFORM, "set_cacheable", sn, rq, "Could not send HTTP response");
                    return REQ_ABORTED;
                }
                return REQ_PROCEED;
            }
        }
    }
    return REQ_NOACTION;
}


Note that in order to use this code, the server cache must be disabled for the concerned files.
The code can be loaded with (in magnus.conf for > 6.0)

Init fn="load-modules" shlib="<path>/<ourlib>.so" funcs="kpn-set-cacheable,"

And can be used with (in obj.conf):
<Object ppath="<path>/images/">
# expires in 26 weeks
Service fn="kpn-set-cacheable" max-age="15724800"
Service method="(GET|HEAD)" type="
~magnus-internal/*" fn="send-file" nocache=""
</object>

Note that I use the Service function and that two (2) service functions are called in order to return a 200 result code. This is in violation with the NSAPI guide, but is functioning in iPlanet 4.1 and in Sun ONE 6.0
 
joe.mccabe
Posts:261
Registered: 3/7/03
Re: controlling the browser cache   
Dec 2, 2003 9:04 AM (reply 6 of 9)  (In reply to #5 )

 
I'm a little confused by some of the things being done here. It seems to be doing more than it needs to.

1) Cache-control: public

This header tells all caches (browsers, proxies, etc) that the content is cachable. Are you sure you want this? This stands a good chance of unexpectedly overiding the intended Cache-control header that may be set by other SAFs. (Aside - you should not insert with mixed case - the header name in pblock should be all lower case).

2) 200 v 304

The server already figures out if a 200 or a 304 is appropriate. Why are we duplicating this effort?

3) Why does this SAF need to start the response? That seems excessive. I am also not aware of the server's internal functions stripping headers from responses. Can you provide any more detail on that?

4) Disable Server cache

I don't understand the need for this. Can you elaborate a bit?
 
joe.mccabe
Posts:261
Registered: 3/7/03
Re: controlling the browser cache   
Dec 2, 2003 10:05 AM (reply 7 of 9)  (In reply to #6 )

 
Poking Google for "NSAPI expires" finds us this implementation - it's somewhere between my incomplete function above and Henk's.

http://www.dzm.com/soft/expires.tar.gz
 
henkfictorie
Posts:6
Registered: 7/29/02
Re: controlling the browser cache   
Dec 3, 2003 4:12 AM (reply 8 of 9)  (In reply to #6 )

 
Note: this SAF was developed against the iPlanet 4.0/4.1 webserver.

1) Cache-control: public

This header tells all caches (browsers, proxies, etc)
that the content is cachable. Are you sure you want
this? This stands a good chance of unexpectedly
overiding the intended Cache-control header that may
be set by other SAFs. (Aside - you should not insert
with mixed case - the header name in pblock should be
all lower case).

This is the whole intention of this function. We want the object to be cacheable by browser/proxies. We also want to control when they have to check for a newer version. We accomplish that by setting both cache-control: public and by setting the Expires header. I tried using the iPlanet 4.1 build-in functionality, but that didn't work with 304 return codes. The iPlanet 4.1 server didn't allow to set the Expires header, only the 'Cache-control: max-age' can be set using the standard SAFs. Which is not recognized by HTTP/1.0 clients.
I could live with a 'Cache-control: max-age' and no Expires headers situation. If all was functioning well (most browsers are HTTP/1.1).

As a side-note. I have observed that other SAFs (eg. from appservers) do also set mixed-case headers. When dealing with these headers in my SAFs, I have the need for a new pblock_findval function (and alike). That function should search for the parameter ignoring the case (compliant with the spec for HTTP headers)

2) 200 v 304

The server already figures out if a 200 or a 304 is
appropriate. Why are we duplicating this effort?

Because the iPlanet 4.1server doesn't set an Expires header (or Cache-control header) on a 304 response.

3) Why does this SAF need to start the response? That
seems excessive. I am also not aware of the server's
internal functions stripping headers from responses.
Can you provide any more detail on that?

I tried the following (from memory):
- started with the common SAF for setting cache-control and the expires header. If I remember correctly the Expires/Cache-control header is send with a 200 response, but is removed with a 304 response.
- disable the server cache: same result
- wrote 1st version of this SAF, only set the expires header. Seems to be working, only a couple of weeks a noticeable increase in the number of 304 was observed.
- wrote current version of this SAF. Everything OK.
- enabled server cache: no expires/cache-control headers are sent. SAF isn't called.
- Did some experiments to minimize the SAF, eg. not start the response in this SAF, result the expires header was stripped from the 304 response.

4) Disable Server cache

I don't understand the need for this. Can you
elaborate a bit?

see above
 
joe.mccabe
Posts:261
Registered: 3/7/03
Re: controlling the browser cache   
Dec 3, 2003 10:17 AM (reply 9 of 9)  (In reply to #8 )

 
Thanks for the detail Henk. I appreciate it. Learning something new every day...
 
This topic has 9 replies on 1 page.
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums