On 10/03/2009 01:47 AM, [email protected] wrote:
> Author: minfrin
> Date: Fri Oct 2 23:47:37 2009
> New Revision: 821202
>
> URL: http://svn.apache.org/viewvc?rev=821202&view=rev
> Log:
> mod_cache: Introduce the option to run the cache from within the
> normal request handler, and to allow fine grained control over
> where in the filter chain content is cached.
>
> Modified:
> httpd/httpd/trunk/CHANGES
> httpd/httpd/trunk/docs/manual/mod/mod_cache.xml
> httpd/httpd/trunk/modules/cache/mod_cache.c
> httpd/httpd/trunk/modules/cache/mod_cache.h
>
Modified: httpd/httpd/trunk/modules/cache/mod_cache.c
> URL:
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/cache/mod_cache.c?rev=821202&r1=821201&r2=821202&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/cache/mod_cache.c (original)
> +++ httpd/httpd/trunk/modules/cache/mod_cache.c Fri Oct 2 23:47:37 2009
> @@ -271,6 +290,245 @@
> return OK;
> }
>
> +/**
> + * If the two filter handles are present within the filter chain, replace
> + * the last instance of the first filter with the last instance of the
> + * second filter, and return true. If the second filter is not present at
> + * all, the first filter is removed, and false is returned. If neither
> + * filter is present, false is returned and this function does nothing.
> + */
> +static int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
> + ap_filter_rec_t *to) {
> + ap_filter_t *ffrom = NULL, *fto = NULL;
> + while (next) {
> + if (next->frec == from && !next->ctx) {
> + ffrom = next;
> + }
> + if (next->frec == to && !next->ctx) {
> + fto = next;
> + }
> + next = next->next;
> + }
> + if (ffrom && fto) {
> + ffrom->frec = fto->frec;
> + ffrom->ctx = fto->ctx;
> + ap_remove_output_filter(fto);
> + return 1;
> + }
> + if (fto) {
> + ap_remove_output_filter(fto);
> + }
> + return 0;
> +}
> +
> +/**
> + * The cache handler is functionally similar to the cache_quick_hander,
> + * however a number of steps that are required by the quick handler are
> + * not required here, as the normal httpd processing has already handled
> + * these steps.
> + */
> +static int cache_handler(request_rec *r)
> +{
> + apr_status_t rv;
> + const char *auth;
> + cache_provider_list *providers;
> + cache_request_rec *cache;
> + apr_bucket_brigade *out;
> + ap_filter_t *next;
> + ap_filter_rec_t *cache_out_handle;
> + ap_filter_rec_t *cache_save_handle;
> + cache_server_conf *conf;
> +
> + /* Delay initialization until we know we are handling a GET */
> + if (r->method_number != M_GET) {
> + return DECLINED;
> + }
> +
> + conf = (cache_server_conf *)
> ap_get_module_config(r->server->module_config,
> + &cache_module);
> +
> + /* only run if the quick handler is disabled */
> + if (conf->quick) {
> + return DECLINED;
> + }
> +
> + /*
> + * Which cache module (if any) should handle this request?
> + */
> + if (!(providers = ap_cache_get_providers(r, conf, r->parsed_uri))) {
> + return DECLINED;
> + }
> +
> + /* make space for the per request config */
> + cache = (cache_request_rec *) ap_get_module_config(r->request_config,
> + &cache_module);
> + if (!cache) {
> + cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
> + ap_set_module_config(r->request_config, &cache_module, cache);
> + }
> +
> + /* save away the possible providers */
> + cache->providers = providers;
> +
> + /*
> + * Try to serve this request from the cache.
> + *
> + * If no existing cache file (DECLINED)
> + * add cache_save filter
> + * If cached file (OK)
> + * clear filter stack
> + * add cache_out filter
> + * return OK
> + */
> + rv = cache_select(r);
> + if (rv != OK) {
> + if (rv == DECLINED) {
> +
> + /* try to obtain a cache lock at this point. if we succeed,
> + * we are the first to try and cache this url. if we fail,
> + * it means someone else is already trying to cache this
> + * url, and we should just let the request through to the
> + * backend without any attempt to cache. this stops
> + * duplicated simultaneous attempts to cache an entity.
> + */
> + rv = ap_cache_try_lock(conf, r, NULL);
> + if (APR_SUCCESS == rv) {
> +
> + /*
> + * Add cache_save filter to cache this request. Choose
> + * the correct filter by checking if we are a subrequest
> + * or not.
> + */
> + if (r->main) {
> + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
> + r->server,
> + "Adding CACHE_SAVE_SUBREQ filter for %s",
> + r->uri);
> + cache_save_handle = cache_save_subreq_filter_handle;
> + }
> + else {
> + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
> + r->server, "Adding CACHE_SAVE filter for %s",
> + r->uri);
> + cache_save_handle = cache_save_filter_handle;
> + }
> + ap_add_output_filter_handle(cache_save_handle,
> + NULL, r, r->connection);
> +
> + /*
> + * Did the user indicate the precise location of the
> + * CACHE_SAVE filter by inserting the CACHE filter as a
> + * marker?
> + *
> + * If so, we get cunning and replace CACHE with the
> + * CACHE_SAVE filter. This has the effect of inserting
> + * the CACHE_SAVE filter at the precise location where
> + * the admin wants to cache the content. All filters that
> + * lie before and after the original location of the CACHE
> + * filter will remain in place.
> + */
> + if (cache_replace_filter(r->output_filters,
> + cache_filter_handle, cache_save_handle)) {
> + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
> + r->server, "Replacing CACHE with CACHE_SAVE "
> + "filter for %s", r->uri);
> + }
> +
> + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
> + "Adding CACHE_REMOVE_URL filter for %s",
> + r->uri);
> +
> + /* Add cache_remove_url filter to this request to remove a
> + * stale cache entry if needed. Also put the current cache
> + * request rec in the filter context, as the request that
> + * is available later during running the filter may be
> + * different due to an internal redirect.
> + */
> + cache->remove_url_filter =
> +
> ap_add_output_filter_handle(cache_remove_url_filter_handle,
> + cache, r, r->connection);
> +
> + }
> + else {
> + ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
> + r->server, "Cache locked for url, not caching "
> + "response: %s", r->uri);
> + }
> + }
> + else {
> + /* error */
> + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
> + "cache: error returned while checking for cached "
> + "file by %s cache", cache->provider_name);
> + }
> + return DECLINED;
> + }
Hm, why don't we do the ap_meets_conditions test here like in the quick handler
rv = ap_meets_conditions(r);
if (rv != OK) {
/* Return cached status. */
return rv;
}
> +
> + /* Serve up the content */
> +
> + /*
> + * Add cache_out filter to serve this request. Choose
> + * the correct filter by checking if we are a subrequest
> + * or not.
> + */
> + if (r->main) {
> + cache_out_handle = cache_out_subreq_filter_handle;
> + }
> + else {
> + cache_out_handle = cache_out_filter_handle;
> + }
> + ap_add_output_filter_handle(cache_out_handle, NULL, r, r->connection);
> +
Plus we have one new warning:
mod_cache.c: In function 'cache_handler':
mod_cache.c:333: warning: unused variable 'auth'
Regards
RĂ¼diger