mod_cache.c revision c1ba97f41a4526d84fb7a1596afe3dd11e065a2c
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny/* Licensed to the Apache Software Foundation (ASF) under one or more
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * contributor license agreements. See the NOTICE file distributed with
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * this work for additional information regarding copyright ownership.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * The ASF licenses this file to You under the Apache License, Version 2.0
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * (the "License"); you may not use this file except in compliance with
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * the License. You may obtain a copy of the License at
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * Unless required by applicable law or agreed to in writing, software
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * distributed under the License is distributed on an "AS IS" BASIS,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * See the License for the specific language governing permissions and
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * limitations under the License.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan ZelenyAPR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny/* -------------------------------------------------------------- */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny/* Handles for cache filters, resolved at startup to eliminate
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * a name-to-function mapping on each request
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic ap_filter_rec_t *cache_save_subreq_filter_handle;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic ap_filter_rec_t *cache_out_subreq_filter_handle;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic ap_filter_rec_t *cache_remove_url_filter_handle;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * CACHE handler
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * -------------
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * Can we deliver this request from the cache?
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * deliver the content by installing the CACHE_OUT filter.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * check whether we're allowed to try cache it
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * add CACHE_SAVE filter
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * By default, the cache handler runs in the quick handler, bypassing
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * virtually all server processing and offering the cache its optimal
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * performance. In this mode, the cache bolts onto the front of the
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * server, and behaves as a discrete RFC2616 caching proxy
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * implementation.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Under certain circumstances, an admin might want to run the cache as
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * a normal handler instead of a quick handler, allowing the cache to
bdbf4f169e4d5d00b0616df19f7a55debb407f78Pavel Březina * run after the authorisation hooks, or by allowing fine control over
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * the placement of the cache in the filter chain. This option comes at
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * a performance penalty, and should only be used to achieve specific
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * caching goals where the admin understands what they are doing.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic int cache_quick_handler(request_rec *r, int lookup)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny const char *auth;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* Delay initialization until we know we are handling a GET */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* only run if the quick handler is enabled */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * Which cache module (if any) should handle this request?
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (!(providers = ap_cache_get_providers(r, conf, r->parsed_uri))) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* make space for the per request config */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
ef2455b63380ecd17bea94270ceaabe15dcf6456Jakub Hrozek /* store away the per request config where the API can find it */
ef2455b63380ecd17bea94270ceaabe15dcf6456Jakub Hrozek apr_pool_userdata_setn(cache, MOD_CACHE_REQUEST_REC, NULL, r->pool);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* save away the possible providers */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * Are we allowed to serve cached info at all?
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* find certain cache controlling headers */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov auth = apr_table_get(r->headers_in, "Authorization");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* First things first - does the request allow us to return
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * cached information at all? If not, just decline the request.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Try to serve this request from the cache.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * If no existing cache file (DECLINED)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * add cache_save filter
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * If cached file (OK)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * clear filter stack
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * add cache_out filter
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* try to obtain a cache lock at this point. if we succeed,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * we are the first to try and cache this url. if we fail,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * it means someone else is already trying to cache this
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * url, and we should just let the request through to the
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * backend without any attempt to cache. this stops
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * duplicated simultaneous attempts to cache an entity.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Add cache_save filter to cache this request. Choose
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * the correct filter by checking if we are a subrequest
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "Adding CACHE_SAVE_SUBREQ filter for %s",
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_add_output_filter_handle(cache_save_subreq_filter_handle,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_add_output_filter_handle(cache_save_filter_handle,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "Adding CACHE_REMOVE_URL filter for %s",
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* Add cache_remove_url filter to this request to remove a
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov * stale cache entry if needed. Also put the current cache
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov * request rec in the filter context, as the request that
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * is available later during running the filter may be
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * different due to an internal redirect.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_add_output_filter_handle(cache_remove_url_filter_handle,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek r->server, "Cache locked for url, not caching "
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
ef2455b63380ecd17bea94270ceaabe15dcf6456Jakub Hrozek "cache: error returned while checking for cached "
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* if we are a lookup, we are exiting soon one way or another; Restore
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * the headers. */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose "Restoring request headers.");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* If we are a lookup, we have to return DECLINED as we have no
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * way of knowing if we will be able to serve the content.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* Return cached status. */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* If we're a lookup, we can exit now instead of serving the content. */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* Serve up the content */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* We are in the quick handler hook, which means that no output
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * filters have been set. So lets run the insert_filter hook.
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov * Add cache_out filter to serve this request. Choose
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * the correct filter by checking if we are a subrequest
877b92e80bde510d5cd9f03dbf01e2bcf73ab072Michal Židek cache_out_handle = cache_out_subreq_filter_handle;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Remove all filters that are before the cache_out filter. This ensures
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose * that we kick off the filter stack with our cache_out filter being the
bdbf4f169e4d5d00b0616df19f7a55debb407f78Pavel Březina * first in the chain. This make sense because we want to restore things
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * in the same manner as we saved them.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * There may be filters before our cache_out filter, because
ef2455b63380ecd17bea94270ceaabe15dcf6456Jakub Hrozek * 1. We call ap_set_content_type during cache_select. This causes
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Content-Type specific filters to be added.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * 2. We call the insert_filter hook. This causes filters e.g. like
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * the ones set with SetOutputFilter to be added.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny while (next && (next->frec != cache_out_handle)) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* kick off the filter stack */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "cache: error returned while trying to return %s "
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce "cached data",
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose * If the two filter handles are present within the filter chain, replace
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * the last instance of the first filter with the last instance of the
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * second filter, and return true. If the second filter is not present at
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * all, the first filter is removed, and false is returned. If neither
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * filter is present, false is returned and this function does nothing.
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * The cache handler is functionally similar to the cache_quick_hander,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * however a number of steps that are required by the quick handler are
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * not required here, as the normal httpd processing has already handled
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * these steps.
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose /* Delay initialization until we know we are handling a GET */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* only run if the quick handler is disabled */
877b92e80bde510d5cd9f03dbf01e2bcf73ab072Michal Židek * Which cache module (if any) should handle this request?
4f118e3e6a25762f40a43e6dbefb09f44adbef32Simo Sorce if (!(providers = ap_cache_get_providers(r, conf, r->parsed_uri))) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* make space for the per request config */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* store away the per request config where the API can find it */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_pool_userdata_setn(cache, MOD_CACHE_REQUEST_REC, NULL, r->pool);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* save away the possible providers */
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * Try to serve this request from the cache.
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * If no existing cache file (DECLINED)
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * add cache_save filter
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * If cached file (OK)
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * clear filter stack
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * add cache_out filter
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose /* try to obtain a cache lock at this point. if we succeed,
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * we are the first to try and cache this url. if we fail,
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * it means someone else is already trying to cache this
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * url, and we should just let the request through to the
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * backend without any attempt to cache. this stops
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * duplicated simultaneous attempts to cache an entity.
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * Add cache_save filter to cache this request. Choose
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * the correct filter by checking if we are a subrequest
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose "Adding CACHE_SAVE_SUBREQ filter for %s",
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose cache_save_handle = cache_save_subreq_filter_handle;
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * Did the user indicate the precise location of the
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * CACHE_SAVE filter by inserting the CACHE filter as a
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * If so, we get cunning and replace CACHE with the
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * CACHE_SAVE filter. This has the effect of inserting
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * the CACHE_SAVE filter at the precise location where
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * the admin wants to cache the content. All filters that
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * lie before and after the original location of the CACHE
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * filter will remain in place.
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek "Adding CACHE_REMOVE_URL filter for %s",
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose /* Add cache_remove_url filter to this request to remove a
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov * stale cache entry if needed. Also put the current cache
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek * request rec in the filter context, as the request that
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * is available later during running the filter may be
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose * different due to an internal redirect.
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose ap_add_output_filter_handle(cache_remove_url_filter_handle,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek r->server, "Cache locked for url, not caching "
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek "cache: error returned while checking for cached "
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* Serve up the content */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * Add cache_out filter to serve this request. Choose
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * the correct filter by checking if we are a subrequest
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek cache_out_handle = cache_out_subreq_filter_handle;
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * Did the user indicate the precise location of the CACHE_OUT filter by
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * inserting the CACHE filter as a marker?
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * This has the effect of inserting the CACHE_OUT filter at the precise
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * location where the admin wants to cache the content. All filters that
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * lie *after* the original location of the CACHE filter will remain in
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek if (cache_replace_filter(r->output_filters, cache_filter_handle, cache_out_handle)) {
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek r->server, "Replacing CACHE with CACHE_OUT filter for %s",
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * Remove all filters that are before the cache_out filter. This ensures
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * that we kick off the filter stack with our cache_out filter being the
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * first in the chain. This make sense because we want to restore things
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * in the same manner as we saved them.
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * There may be filters before our cache_out filter, because
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * 1. We call ap_set_content_type during cache_select. This causes
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * Content-Type specific filters to be added.
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * 2. We call the insert_filter hook. This causes filters e.g. like
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * the ones set with SetOutputFilter to be added.
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek while (next && (next->frec != cache_out_handle)) {
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* kick off the filter stack */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek "cache: error returned while trying to return %s "
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek "cached data",
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * CACHE_OUT filter
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * ----------------
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina * Deliver cached content (headers and body) up the stack.
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozekstatic int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina cache_request_rec *cache = (cache_request_rec *)f->ctx;
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* user likely configured CACHE_OUT manually; they should use mod_cache
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina * configuration to do that */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek "CACHE/CACHE_OUT filter enabled while caching is disabled, ignoring");
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek "cache: running CACHE_OUT filter");
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* restore status of cached response */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* XXX: This exposes a bug in mem_cache, since it does not
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * restore the status into it's handle. */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek r->status = cache->handle->cache_obj->info.status;
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* recall_headers() was called in cache_select() */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek cache->provider->recall_body(cache->handle, r->pool, bb);
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* This filter is done once it has served up its content */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * Having jumped through all the hoops and decided to cache the
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * response, call store_body() for each brigade, handling the
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * case where the provider can't swallow the full brigade. In this
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * case, we write the brigade we were passed out downstream, and
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * loop around to try and cache some more until the in brigade is
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek * completely empty. As soon as the out brigade contains eos, call
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina * commit_entity() to finalise the cached element.
apr_bucket *e;
e = APR_BUCKET_NEXT(e))
if (APR_BUCKET_IS_EOS(e)) {
return rv;
request_rec *r = f->r;
char *reason;
apr_pool_t *p;
apr_bucket *e;
&cache_module);
if (!cache) {
"CACHE/CACHE_SAVE filter enabled while caching is disabled, ignoring");
p = r->pool;
return APR_SUCCESS;
if (reason) {
/* Note: mod-include clears last_modified/expires/etags - this
reason = "No Last-Modified, Etag, Expires, Cache-Control:max-age or Cache-Control:s-maxage headers";
else if (r->no_cache) {
if (reason) {
reason);
if (cl) {
char *errp;
if (!cl) {
int all_buckets_here=0;
size=0;
e = APR_BUCKET_NEXT(e))
if (APR_BUCKET_IS_EOS(e)) {
if (APR_BUCKET_IS_FLUSH(e)) {
if (!all_buckets_here) {
else if (!r->header_only) {
r->server,
char *max_age_val;
apr_int64_t x;
errno = 0;
if (errno) {
x = x * MSEC_ONE_SEC;
int status;
request_rec *r = f->r;
if (!cache) {
const char *tmppath;
if (tmppath) {
return ps;
return ps;
int flag)
conf =
&cache_module);
return NULL;
int flag)
conf =
&cache_module);
return NULL;
conf =
&cache_module);
return NULL;
int flag)
conf =
&cache_module);
return NULL;
int flag)
conf =
&cache_module);
return NULL;
const char *header)
char **new;
conf =
&cache_module);
return NULL;
const char *identifier)
char **new;
conf =
&cache_module);
return NULL;
const char *type,
const char *url)
return err;
type);
if (!url) {
if (!url) {
conf =
&cache_module);
return NULL;
return NULL;
const char *url)
return err;
conf =
&cache_module);
return NULL;
return NULL;
const char *arg)
conf =
&cache_module);
return NULL;
const char *arg)
conf =
&cache_module);
return NULL;
const char *arg)
conf =
&cache_module);
return NULL;
const char *arg)
double val;
conf =
&cache_module);
return NULL;
int flag)
conf =
&cache_module);
return NULL;
int flag)
conf =
&cache_module);
return NULL;
const char *arg)
conf =
&cache_module);
return NULL;
const char *arg)
conf =
&cache_module);
if (seconds <= 0) {
return NULL;
if (!cache_generate_key) {
return OK;
{NULL}
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,