Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 15600 invoked from network); 27 Aug 2008 19:48:55 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 27 Aug 2008 19:48:55 -0000 Received: (qmail 23125 invoked by uid 500); 27 Aug 2008 19:48:47 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 23061 invoked by uid 500); 27 Aug 2008 19:48:47 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 23050 invoked by uid 99); 27 Aug 2008 19:48:46 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Aug 2008 12:48:46 -0700 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received: from [140.211.11.9] (HELO minotaur.apache.org) (140.211.11.9) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 27 Aug 2008 19:47:57 +0000 Received: (qmail 15153 invoked by uid 2161); 27 Aug 2008 19:48:28 -0000 Received: from [192.168.2.4] (euler.heimnetz.de [192.168.2.4]) by cerberus.heimnetz.de (Postfix on SuSE Linux 7.0 (i386)) with ESMTP id C1BED1721C for ; Wed, 27 Aug 2008 21:48:16 +0200 (CEST) Message-ID: <48B5AF90.5020409@apache.org> Date: Wed, 27 Aug 2008 21:48:32 +0200 From: Ruediger Pluem User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 MIME-Version: 1.0 To: dev@httpd.apache.org Subject: Fix mod_expires to set correct expires date (PR41391) X-Enigmail-Version: 0.95.6 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit X-Virus-Checked: Checked by ClamAV on apache.org While reviewing the patch for PR41391 (https://issues.apache.org/bugzilla/show_bug.cgi?id=41391), I noticed that besides a possible overflow, it could happen that the expires date is in the past (just take an old file and say modification plus 1 minute). What we really want to say in this situation is that the resource is already expired. To state this RF2616 14.21 says that the Expires header should be set to the same value as the Date header. The following patch fixes this and ensures that max-age will be zero in this situation: Index: modules/metadata/mod_expires.c =================================================================== --- modules/metadata/mod_expires.c (Revision 689502) +++ modules/metadata/mod_expires.c (Arbeitskopie) @@ -386,6 +386,8 @@ return new; } +#define SECS_PER_YEAR 86400 * 365 + /* * Handle the setting of the expiration response header fields according * to our criteria. @@ -395,7 +397,6 @@ apr_table_t *t) { apr_time_t base; - apr_time_t additional; apr_time_t expires; int additional_sec; char *timestr; @@ -409,16 +410,12 @@ return DECLINED; } base = r->finfo.mtime; - additional_sec = atoi(&code[1]); - additional = apr_time_from_sec(additional_sec); break; case 'A': /* there's been some discussion and it's possible that * 'access time' will be stored in request structure */ base = r->request_time; - additional_sec = atoi(&code[1]); - additional = apr_time_from_sec(additional_sec); break; default: /* expecting the add_* routines to be case-hardened this @@ -429,7 +426,31 @@ return HTTP_INTERNAL_SERVER_ERROR; } - expires = base + additional; + additional_sec = atoi(&code[1]); + expires = base + apr_time_from_sec(additional_sec); + /* + * Check if we have an overflow, so the resource should not expire. + * According to RFC2616 14.21 we should set a date one year in the future + * then, but not more. + */ + if (expires < 0) { + expires = r->request_time + apr_time_from_sec(SECS_PER_YEAR); + } + /* + * We had an overflow again. So we seem to be less then a year from + * APR_INT64_MAX + */ + if (expires < 0) { + expires = APR_INT64_MAX; + } + /* + * Our expires date is in the past. According to RFC2616 14.21 we should + * set expires to the same value as the Date header to show that the + * resource is already expired. + */ + if (expires < r->request_time) { + expires = r->request_time; + } apr_table_mergen(t, "Cache-Control", apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT, apr_time_sec(expires - r->request_time))); The downside is that this patch breaks several tests. But I believe that this is caused by a wrong test. The following patch would fix this: Index: t/modules/expires.t =================================================================== --- t/modules/expires.t (Revision 689502) +++ t/modules/expires.t (Arbeitskopie) @@ -243,6 +243,17 @@ $actual = $headers{expires} - $headers{access}; } + ## if we use the modification date as base the calculated expiration date + ## might be past and the message that should be sent is that this resource + ## is already expired. According to RFC2616 14.21 the Date header and the + ## Expires header should be equal in this case. + ## + if (($exp_type eq 'M') + && ($headers{modified} + $expected < $headers{access})) { + $expected = 0; + $actual = $headers{expires} - $headers{access}; + } + print "# debug: expected: $expected\n"; print "# debug: actual : $actual\n"; return ($actual == $expected); Comments? Regards R�diger