return 1;
}
-CACHE_DECLARE(void) ap_cache_accept_headers(cache_handle_t *h, request_rec *r)
+CACHE_DECLARE(void) ap_cache_accept_headers(cache_handle_t *h, request_rec *r,
+ int preserve_orig)
{
- apr_table_t *cookie_table;
+ apr_table_t *cookie_table, *hdr_copy;
const char *v;
v = apr_table_get(h->resp_hdrs, "Content-Type");
apr_table_unset(r->err_headers_out, "Set-Cookie");
apr_table_unset(h->resp_hdrs, "Set-Cookie");
- apr_table_overlap(r->headers_out, h->resp_hdrs, APR_OVERLAP_TABLES_SET);
+ if (preserve_orig) {
+ hdr_copy = apr_table_copy(r->pool, h->resp_hdrs);
+ apr_table_overlap(hdr_copy, r->headers_out, APR_OVERLAP_TABLES_SET);
+ r->headers_out = hdr_copy;
+ }
+ else {
+ apr_table_overlap(r->headers_out, h->resp_hdrs, APR_OVERLAP_TABLES_SET);
+ }
if (!apr_is_empty_table(cookie_table)) {
r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out,
cookie_table);
}
/* Okay, this response looks okay. Merge in our stuff and go. */
- ap_cache_accept_headers(h, r);
+ ap_cache_accept_headers(h, r, 0);
cache->handle = h;
return OK;
/* Oh, hey. It isn't that stale! Yay! */
cache->handle = cache->stale_handle;
info = &cache->handle->cache_obj->info;
- /* Load in the saved status. */
- r->status = info->status;
- /* The cached response will override our err_headers_out. */
- apr_table_clear(r->err_headers_out);
- /* Merge in our headers. */
- ap_cache_accept_headers(cache->handle, r);
rv = OK;
}
else {
* expire date = date + defaultexpire
*/
if (exp == APR_DATE_BAD) {
+ char expire_hdr[APR_RFC822_DATE_LEN];
+
/* if lastmod == date then you get 0*conf->factor which results in
* an expiration time of now. This causes some problems with
* freshness calculations, so we choose the else path...
x = conf->maxex;
}
exp = date + x;
+ apr_rfc822_date(expire_hdr, exp);
+ apr_table_set(r->headers_out, "Expires", expire_hdr);
}
else {
exp = date + conf->defex;
+ apr_rfc822_date(expire_hdr, exp);
+ apr_table_set(r->headers_out, "Expires", expire_hdr);
}
}
info->expire = exp;
- /*
- * Write away header information to cache.
- */
+ /* We found a stale entry which wasn't really stale. */
+ if (cache->stale_handle) {
+ /* Load in the saved status and clear the status line. */
+ r->status = info->status;
+ r->status_line = NULL;
+
+ /* RFC 2616 10.3.5 states that entity headers are not supposed
+ * to be in the 304 response. Therefore, we need to load in the
+ * cached headers before we update the cached headers.
+ *
+ * However, before doing that, we need to first merge in
+ * err_headers_out and we also need to strip any hop-by-hop
+ * headers that might have snuck in.
+ */
+ r->headers_out = apr_table_overlay(r->pool, r->headers_out,
+ r->err_headers_out);
+ r->headers_out = ap_cache_cacheable_hdrs_out(r->pool, r->headers_out,
+ r->server);
+ apr_table_clear(r->err_headers_out);
+
+ /* Merge in our cached headers. However, keep any updated values. */
+ ap_cache_accept_headers(cache->handle, r, 1);
+ }
+
+ /* Write away header information to cache. */
rv = cache->provider->store_headers(cache->handle, r, info);
- /* Did we actually find an entity before, but it wasn't really stale? */
+ /* Did we just update the cached headers on a revalidated response?
+ *
+ * If so, we can now decide what to serve to the client:
+ * - If the original request was conditional and is satisified, send 304.
+ * - Otherwise, send the cached body.
+ */
if (rv == APR_SUCCESS && cache->stale_handle) {
apr_bucket_brigade *bb;
apr_bucket *bkt;
/* Were we initially a conditional request? */
if (ap_cache_request_is_conditional(cache->stale_headers)) {
- /* FIXME: Should we now go and make sure it's really not
- * modified since what the user thought?
- */
+ /* FIXME: We must ensure that the request meets conditions. */
+
+ /* Set the status to be a 304. */
+ r->status = HTTP_NOT_MODIFIED;
+
bkt = apr_bucket_flush_create(bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, bkt);
}
else {
- r->status = info->status;
cache->provider->recall_body(cache->handle, r->pool, bb);
}