diff options
author | Ken Coar <coar@apache.org> | 2003-05-14 19:39:14 +0200 |
---|---|---|
committer | Ken Coar <coar@apache.org> | 2003-05-14 19:39:14 +0200 |
commit | c95d30822412f0769987375664aff44d9ebeda36 (patch) | |
tree | acff98f79cade5821a9dc75556d6dd002015e33a /modules/metadata/mod_expires.c | |
parent | reflect a merge (diff) | |
download | apache2-c95d30822412f0769987375664aff44d9ebeda36.tar.xz apache2-c95d30822412f0769987375664aff44d9ebeda36.zip |
if there are any ExpiresByType directives for the current
scope, defer the setting of the expiration header fields
to an output filter, which can then apply any ExpiresByType
or ExpiresDefault settings -- including to dynamic documents.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@99827 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/metadata/mod_expires.c')
-rw-r--r-- | modules/metadata/mod_expires.c | 195 |
1 files changed, 145 insertions, 50 deletions
diff --git a/modules/metadata/mod_expires.c b/modules/metadata/mod_expires.c index e35e5544e4..d8423bbd06 100644 --- a/modules/metadata/mod_expires.c +++ b/modules/metadata/mod_expires.c @@ -212,6 +212,11 @@ typedef struct { apr_table_t *expiresbytype; } expires_dir_config; +typedef struct { + int defaulted; + apr_table_t *expfields; +} expires_interphase_t; + /* from mod_dir, why is this alias used? */ #define DIR_CMD_PERMS OR_INDEXES @@ -416,59 +421,23 @@ static void *merge_expires_dir_configs(apr_pool_t *p, void *basev, void *addv) return new; } -static int add_expires(request_rec *r) +/* + * Handle the setting of the expiration response header fields according + * to our criteria. + */ + +static int set_expiration_fields(request_rec *r, const char *code, + apr_table_t *t) { - expires_dir_config *conf; - char *code; apr_time_t base; apr_time_t additional; apr_time_t expires; int additional_sec; char *timestr; + expires_interphase_t *notes; - if (ap_is_HTTP_ERROR(r->status)) /* Don't add Expires headers to errors */ - return DECLINED; - - if (r->main != NULL) /* Say no to subrequests */ - return DECLINED; - - conf = (expires_dir_config *) ap_get_module_config(r->per_dir_config, &expires_module); - if (conf == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "internal error: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (conf->active != ACTIVE_ON) - return DECLINED; - - /* we perhaps could use the default_type(r) in its place but that - * may be 2nd guesing the desired configuration... calling table_get - * with a NULL key will SEGV us - * - * I still don't know *why* r->content_type would ever be NULL, this - * is possibly a result of fixups being called in many different - * places. Fixups is probably the wrong place to be doing all this - * work... Bah. - * - * Changed as of 08.Jun.96 don't DECLINE, look for an ExpiresDefault. - */ - if (r->content_type == NULL) - code = NULL; - else - code = (char *) apr_table_get(conf->expiresbytype, - ap_field_noparam(r->pool, r->content_type)); - - if (code == NULL) { - /* no expires defined for that type, is there a default? */ - code = conf->expiresdefault; - - if (code[0] == '\0') - return OK; - } - - /* we have our code */ - + notes = (expires_interphase_t *) ap_get_module_config(r->request_config, + &expires_module); switch (code[0]) { case 'M': if (r->finfo.filetype == 0) { @@ -499,17 +468,143 @@ static int add_expires(request_rec *r) } expires = base + additional; - apr_table_mergen(r->headers_out, "Cache-Control", - apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT, - apr_time_sec(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))); timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); apr_rfc822_date(timestr, expires); - apr_table_setn(r->headers_out, "Expires", timestr); + apr_table_setn(t, "Expires", timestr); return OK; } +/* + * Output filter to set the Expires response header field + * according to the content-type of the response -- if it hasn't + * already been set. + */ +static apr_status_t expires_by_type_filter(ap_filter_t *f, + apr_bucket_brigade *b) +{ + request_rec *r; + expires_dir_config *conf; + expires_interphase_t *notes; + const char *bytype_expiry; + apr_table_t *t; + + r = f->r; + conf = (expires_dir_config *) ap_get_module_config(r->per_dir_config, + &expires_module); + notes = (expires_interphase_t *) ap_get_module_config(r->request_config, + &expires_module); + + /* + * If this filter is getting called, it *should* mean that + * the fixup-phase handler ran and set things up for us. + * Check to see which output header table we should use; + * mod_cgi loads script fields into r->err_headers_out, + * for instance. + */ + bytype_expiry = apr_table_get(r->err_headers_out, "Expires"); + if (bytype_expiry != NULL) { + t = r->err_headers_out; + } + else { + bytype_expiry = apr_table_get(r->headers_out, "Expires"); + t = r->headers_out; + } + if (bytype_expiry == NULL) { + /* + * No expiration has been set, so we can apply any managed by + * this module. Check for one for this content type. + */ + bytype_expiry = apr_table_get(conf->expiresbytype, + ap_field_noparam(r->pool, + r->content_type)); + if (bytype_expiry != NULL) { + set_expiration_fields(r, bytype_expiry, t); + } + else if ((notes != NULL) && notes->defaulted) { + /* + * None for this type, but there was a default defined -- + * so use it. + */ + t = apr_table_overlay(r->pool, notes->expfields, t); + } + } + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, b); +} + +static int add_expires(request_rec *r) +{ + expires_dir_config *conf; + expires_interphase_t *notes; + apr_table_t *rfields; + char *code; + + if (ap_is_HTTP_ERROR(r->status)) {/* Don't add Expires headers to errors */ + return DECLINED; + } + + if (r->main != NULL) { /* Say no to subrequests */ + return DECLINED; + } + + conf = (expires_dir_config *) ap_get_module_config(r->per_dir_config, + &expires_module); + if (conf == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "internal error: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if (conf->active != ACTIVE_ON) { + return DECLINED; + } + + notes = apr_palloc(r->pool, sizeof(expires_interphase_t)); + notes->defaulted = 0; + notes->expfields = apr_table_make(r->pool, 4); + ap_set_module_config(r->request_config, &expires_module, notes); + + /* + * If there are any ExpiresByType directives for this scope, + * add the output filter and defer all setting to it. We + * do make a note of any ExpiresDefault value for its use. + */ + if (! apr_is_empty_table(conf->expiresbytype)) { + ap_add_output_filter("EXPIRATION", NULL, r, r->connection); + rfields = notes->expfields; + } + else { + rfields = r->headers_out; + } + /* + * Apply the default expiration if there is one; the filter will + * narrow it down later if possible. + */ + code = conf->expiresdefault; + + if (code[0] == '\0') { + return OK; + } + else { + /* + * Note that we're setting it from the default, so that + * the output filter (if it runs) knows it can override the + * value. This allows the by-type filter to be able to + * tell the difference between a value set by, say, a + * CGI script and the one we set by default. + */ + notes->defaulted = 1; + } + return set_expiration_fields(r, code, rfields); +} + static void register_hooks(apr_pool_t *p) { + ap_register_output_filter("EXPIRATION", expires_by_type_filter, NULL, + AP_FTYPE_CONTENT_SET); ap_hook_fixups(add_expires,NULL,NULL,APR_HOOK_MIDDLE); } |