summaryrefslogtreecommitdiffstats
path: root/modules/metadata/mod_expires.c
diff options
context:
space:
mode:
authorKen Coar <coar@apache.org>2003-05-14 19:39:14 +0200
committerKen Coar <coar@apache.org>2003-05-14 19:39:14 +0200
commitc95d30822412f0769987375664aff44d9ebeda36 (patch)
treeacff98f79cade5821a9dc75556d6dd002015e33a /modules/metadata/mod_expires.c
parentreflect a merge (diff)
downloadapache2-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.c195
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);
}