return DECLINED;
}
-static int set_cookie_doo_doo(void *v, const char *key, const char *val)
+static int filter_header_do(void *v, const char *key, const char *val)
+{
+ if ((*key == 'W' || *key == 'w') && !strcasecmp(key, "Warning")
+ && *val == '1') {
+ /* any stored Warning headers with warn-code 1xx (see section
+ * 14.46) MUST be deleted from the cache entry and the forwarded
+ * response.
+ */
+ }
+ else {
+ apr_table_addn(v, key, val);
+ }
+ return 1;
+}
+static int remove_header_do(void *v, const char *key, const char *val)
+{
+ if ((*key == 'W' || *key == 'w') && !strcasecmp(key, "Warning")) {
+ /* any stored Warning headers with warn-code 2xx MUST be retained
+ * in the cache entry and the forwarded response.
+ */
+ }
+ else {
+ apr_table_unset(v, key);
+ }
+ return 1;
+}
+static int add_header_do(void *v, const char *key, const char *val)
{
apr_table_addn(v, key, val);
return 1;
}
/**
- * Take headers from the cache, and overlap them over the existing response
- * headers.
+ * Take two sets of headers, sandwich them together, and apply the result to
+ * r->headers_out.
+ *
+ * To complicate this, a header may be duplicated in either table. Should a
+ * header exist in the top table, all matching headers will be removed from
+ * the bottom table before the headers are combined. The Warning headers are
+ * handled specially. Warnings are added rather than being replaced, while
+ * in the case of revalidation 1xx Warnings are stripped.
+ *
+ * The Content-Type and Last-Modified headers are then re-parsed and inserted
+ * into the request.
*/
-void cache_accept_headers(cache_handle_t *h, request_rec *r,
- int preserve_orig)
+void cache_accept_headers(cache_handle_t *h, request_rec *r, apr_table_t *top,
+ apr_table_t *bottom, int revalidation)
{
- apr_table_t *cookie_table, *hdr_copy;
const char *v;
- v = apr_table_get(h->resp_hdrs, "Content-Type");
+ if (revalidation) {
+ r->headers_out = apr_table_make(r->pool, 10);
+ apr_table_do(filter_header_do, r->headers_out, bottom, NULL);
+ }
+ else if (r->headers_out != bottom) {
+ r->headers_out = apr_table_copy(r->pool, bottom);
+ }
+ apr_table_do(remove_header_do, r->headers_out, top, NULL);
+ apr_table_do(add_header_do, r->headers_out, top, NULL);
+
+ v = apr_table_get(r->headers_out, "Content-Type");
if (v) {
ap_set_content_type(r, v);
- apr_table_unset(h->resp_hdrs, "Content-Type");
/*
* Also unset possible Content-Type headers in r->headers_out and
* r->err_headers_out as they may be different to what we have received
/* If the cache gave us a Last-Modified header, we can't just
* pass it on blindly because of restrictions on future values.
*/
- v = apr_table_get(h->resp_hdrs, "Last-Modified");
+ v = apr_table_get(r->headers_out, "Last-Modified");
if (v) {
ap_update_mtime(r, apr_date_parse_http(v));
ap_set_last_modified(r);
- apr_table_unset(h->resp_hdrs, "Last-Modified");
}
- /* The HTTP specification says that it is legal to merge duplicate
- * headers into one. Some browsers that support Cookies don't like
- * merged headers and prefer that each Set-Cookie header is sent
- * separately. Lets humour those browsers by not merging.
- * Oh what a pain it is.
- */
- cookie_table = apr_table_make(r->pool, 2);
- apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out,
- "Set-Cookie", NULL);
- apr_table_do(set_cookie_doo_doo, cookie_table, h->resp_hdrs,
- "Set-Cookie", NULL);
- apr_table_unset(r->err_headers_out, "Set-Cookie");
- apr_table_unset(h->resp_hdrs, "Set-Cookie");
-
- 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. */
- cache_accept_headers(h, r, 0);
+ cache_accept_headers(h, r, h->resp_hdrs, r->headers_out, 0);
cache->handle = h;
return OK;
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
r->headers_in = cache->stale_headers;
+ r->headers_out = ap_cache_cacheable_headers_out(r);
+
+ /* Merge in our cached headers. However, keep any updated values. */
+ /* take output, overlay on top of cached */
+ cache_accept_headers(cache->handle, r, r->headers_out,
+ cache->handle->resp_hdrs, 1);
+
status = ap_meets_conditions(r);
if (status != OK) {
r->status = status;
APR_BRIGADE_INSERT_TAIL(bb, bkt);
}
else {
- /* RFC 2616 10.3.5 states that entity headers are not supposed
- * to be in the 304 response. Therefore, we need to combine the
- * response headers with 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 = ap_cache_cacheable_headers_out(r);
-
- /* Merge in our cached headers. However, keep any updated values. */
- cache_accept_headers(cache->handle, r, 1);
-
cache->provider->recall_body(cache->handle, r->pool, bb);
bkt = apr_bucket_eos_create(bb->bucket_alloc);
r->headers_out = ap_cache_cacheable_headers_out(r);
/* Merge in our cached headers. However, keep any updated values. */
- cache_accept_headers(cache->handle, r, 1);
+ /* take output, overlay on top of cached */
+ cache_accept_headers(cache->handle, r, r->headers_out,
+ cache->handle->resp_hdrs, 1);
}
/* Write away header information to cache. It is possible that we are