You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2009/10/03 01:47:38 UTC
svn commit: r821202 - in /httpd/httpd/trunk: CHANGES
docs/manual/mod/mod_cache.xml modules/cache/mod_cache.c
modules/cache/mod_cache.h
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/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=821202&r1=821201&r2=821202&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Fri Oct 2 23:47:37 2009
@@ -10,6 +10,10 @@
mod_proxy_ftp: NULL pointer dereference on error paths.
[Stefan Fritsch <sf fritsch.de>, Joe Orton]
+ *) 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. [Graham Leggett]
+
*) core: Treat timeout reading request as 408 error, not 400.
Log 408 errors in access log as was done in Apache 1.3.x.
PR 39785 [Nobutaka Mantani <nobutaka nobutaka.org>,
Modified: httpd/httpd/trunk/docs/manual/mod/mod_cache.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_cache.xml?rev=821202&r1=821201&r2=821202&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_cache.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_cache.xml Fri Oct 2 23:47:37 2009
@@ -29,12 +29,13 @@
<identifier>cache_module</identifier>
<summary>
- <note type="warning">This module should be used with care and
- can be used to circumvent <directive
+ <note type="warning">This module should be used with care, as when the
+ <directive module="mod_cache">CacheQuickHandler</directive> directive is
+ in its default value of <strong>on</strong>, the <directive
module="mod_authz_host">Allow</directive> and <directive
- module="mod_authz_host">Deny</directive> directives. You
- should not enable caching for any content to which you wish
- to limit access by client host name, address or environment
+ module="mod_authz_host">Deny</directive> directives will be circumvented.
+ You should not enable quick handler caching for any content to which you
+ wish to limit access by client host name, address or environment
variable.</note>
<p><module>mod_cache</module> implements an <a
@@ -160,6 +161,71 @@
</section>
</section>
+<section id="finecontrol"><title>Fine Control with the CACHE Filter</title>
+ <p>Under the default mode of cache operation, the cache runs as a quick handler,
+ short circuiting the majority of server processing and offering the highest
+ cache performance available.</p>
+
+ <p>In this mode, the cache <strong>bolts onto</strong> the front of the server,
+ acting as if a free standing RFC2616 caching proxy had been placed in front of
+ the server.</p>
+
+ <p>While this mode offers the best performance, the administrator may find that
+ under certain circumstances they may want to perform further processing on the
+ request after the request is cached, such as to inject personalisation into the
+ cached page, or to apply authorisation restrictions to the content. Under these
+ circumstances, an administrator is often forced to place independent reverse
+ proxy servers either behind or in front of the caching server to achieve this.</p>
+
+ <p>To solve this problem the <directive module="mod_cache">CacheQuickHandler
+ </directive> directive can be set to <strong>off</strong>, and the server will
+ process all phases normally handled by a non cached request, including the
+ <strong>authentication and authorisation</strong> phases.</p>
+
+ <p>In addition, the administrator may optionally specify the <strong>precise point
+ within the filter chain</strong> where caching is to take place by adding the
+ <strong>CACHE</strong> filter to the output filter chain.</p>
+
+ <p>For example, to cache content before applying compression to the response,
+ place the <strong>CACHE</strong> filter before the <strong>DEFLATE</strong>
+ filter as in the example below:</p>
+
+ <example>
+ # Cache content before optional compression<br />
+ CacheQuickHandler off<br />
+ AddOutputFilterByType CACHE;DEFLATE text/plain<br /><br />
+ </example>
+
+ <p>Another option is to have content cached before personalisation is applied
+ by <module>mod_include</module> (or another content processing filter). In this
+ example templates containing tags understood by
+ <module>mod_include</module> are cached before being parsed:</p>
+
+ <example>
+ # Cache content before mod_include and mod_deflate<br />
+ CacheQuickHandler off<br />
+ AddOutputFilterByType CACHE;INCLUDES;DEFLATE text/html<br /><br />
+ </example>
+
+ <p>You may place the <strong>CACHE</strong> filter anywhere you wish within the
+ filter chain. In this example, content is cached after being parsed by
+ <module>mod_include</module>, but before being processed by
+ <module>mod_deflate</module>:</p>
+
+ <example>
+ # Cache content between mod_include and mod_deflate<br />
+ CacheQuickHandler off<br />
+ AddOutputFilterByType INCLUDES;CACHE;DEFLATE text/html<br /><br />
+ </example>
+
+ <note type="warning"><title>Warning:</title>If the location of the
+ <strong>CACHE</strong> filter in the filter chain is changed for any reason,
+ you may need to <strong>flush your cache</strong> to ensure that your data
+ served remains consistent. <module>mod_cache</module> is not in a position
+ to enforce this for you.</note>
+
+</section>
+
<directivesynopsis>
<name>CacheEnable</name>
<description>Enable caching of specified URLs using a specified storage
@@ -598,7 +664,7 @@
</usage>
</directivesynopsis>
-
+
<directivesynopsis>
<name>CacheLockMaxAge</name>
<description>Set the maximum possible age of a cache lock.</description>
@@ -618,5 +684,50 @@
</usage>
</directivesynopsis>
+
+<directivesynopsis>
+ <name>CacheQuickHandler</name>
+ <description>Run the cache from the quick handler.</description>
+ <syntax>CacheQuickHandler <var>on|off</var></syntax>
+ <default>CacheQuickHandler on</default>
+ <contextlist><context>server config</context><context>virtual host</context>
+ </contextlist>
+
+ <usage>
+ <p>The <directive module="mod_cache">CacheQuickHandler</directive> directive
+ controls the phase in which the cache is handled.</p>
+
+ <p>In the default enabled configuration, the cache operates within the quick
+ handler phase. This phase short circuits the majority of server processing,
+ and represents the most performant mode of operation for a typical server.
+ The cache <strong>bolts onto</strong> the front of the server, and the
+ majority of server processing is avoided.</p>
+
+ <p>When disabled, the cache operates as a normal handler, and is subject to
+ the full set of phases when handling a server request. While this mode is
+ slower than the default, it allows the cache to be used in cases where full
+ processing is required, such as when content is subject to authorisation.</p>
+
+ <example>
+ # Run cache as a normal handler<br />
+ CacheQuickHandler off<br /><br />
+ </example>
+
+ <p>It is also possible, when the quick handler is disabled, for the
+ administrator to choose the precise location within the filter chain where
+ caching is to be performed, by adding the <strong>CACHE</strong> filter to
+ the chain.</p>
+
+ <example>
+ # Cache content before mod_include and mod_deflate<br />
+ CacheQuickHandler off<br />
+ AddOutputFilterByType CACHE;INCLUDES;DEFLATE text/html<br /><br />
+ </example>
+
+ <p>If the CACHE filter is specified more than once, the last instance will
+ apply.</p>
+
+ </usage>
+</directivesynopsis>
</modulesynopsis>
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
@@ -25,6 +25,7 @@
/* Handles for cache filters, resolved at startup to eliminate
* a name-to-function mapping on each request
*/
+static ap_filter_rec_t *cache_filter_handle;
static ap_filter_rec_t *cache_save_filter_handle;
static ap_filter_rec_t *cache_save_subreq_filter_handle;
static ap_filter_rec_t *cache_out_filter_handle;
@@ -44,18 +45,31 @@
* add CACHE_SAVE filter
* If No:
* oh well.
+ *
+ * By default, the cache handler runs in the quick handler, bypassing
+ * virtually all server processing and offering the cache its optimal
+ * performance. In this mode, the cache bolts onto the front of the
+ * server, and behaves as a discrete RFC2616 caching proxy
+ * implementation.
+ *
+ * Under certain circumstances, an admin might want to run the cache as
+ * a normal handler instead of a quick handler, allowing the cache to
+ * run after the authorisation hooks, or by allowing fine control over
+ * the placement of the cache in the filter chain. This option comes at
+ * a performance penalty, and should only be used to achieve specific
+ * caching goals where the admin understands what they are doing.
*/
-static int cache_url_handler(request_rec *r, int lookup)
+static int cache_quick_handler(request_rec *r, int lookup)
{
apr_status_t rv;
const char *auth;
cache_provider_list *providers;
cache_request_rec *cache;
- cache_server_conf *conf;
apr_bucket_brigade *out;
ap_filter_t *next;
ap_filter_rec_t *cache_out_handle;
+ cache_server_conf *conf;
/* Delay initialization until we know we are handling a GET */
if (r->method_number != M_GET) {
@@ -65,6 +79,11 @@
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
&cache_module);
+ /* only run if the quick handler is enabled */
+ if (!conf->quick) {
+ return DECLINED;
+ }
+
/*
* Which cache module (if any) should handle this request?
*/
@@ -151,7 +170,7 @@
/* 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 maybe
+ * is available later during running the filter may be
* different due to an internal redirect.
*/
cache->remove_url_filter =
@@ -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;
+ }
+
+ /* 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);
+
+ /*
+ * Did the user indicate the precise location of the CACHE_OUT filter by
+ * inserting the CACHE filter as a marker?
+ *
+ * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
+ * This has the effect of inserting the CACHE_OUT filter at the precise
+ * location where the admin wants to cache the content. All filters that
+ * lie *after* the original location of the CACHE filter will remain in
+ * place.
+ */
+ if (cache_replace_filter(r->output_filters, cache_filter_handle, cache_out_handle)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
+ r->server, "Replacing CACHE with CACHE_OUT filter for %s",
+ r->uri);
+ }
+
+ /*
+ * Remove all filters that are before the cache_out filter. This ensures
+ * that we kick off the filter stack with our cache_out filter being the
+ * first in the chain. This make sense because we want to restore things
+ * in the same manner as we saved them.
+ * There may be filters before our cache_out filter, because
+ *
+ * 1. We call ap_set_content_type during cache_select. This causes
+ * Content-Type specific filters to be added.
+ * 2. We call the insert_filter hook. This causes filters e.g. like
+ * the ones set with SetOutputFilter to be added.
+ */
+ next = r->output_filters;
+ while (next && (next->frec != cache_out_handle)) {
+ ap_remove_output_filter(next);
+ next = next->next;
+ }
+
+ /* kick off the filter stack */
+ out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ rv = ap_pass_brigade(r->output_filters, out);
+ if (rv != APR_SUCCESS) {
+ if (rv != AP_FILTER_ERROR) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+ "cache: error returned while trying to return %s "
+ "cached data",
+ cache->provider_name);
+ }
+ return rv;
+ }
+
+ return OK;
+}
+
/*
* CACHE_OUT filter
* ----------------
@@ -492,7 +750,7 @@
}
else {
- /* proactively remove the lock as soon as we see the eos bucket */
+ /* proactively remove the lock as soon as we see the eos bucket */
ap_cache_remove_lock(conf, r, cache->handle ?
(char *)cache->handle->cache_obj->key : NULL, in);
@@ -1031,7 +1289,7 @@
/*
* CACHE_REMOVE_URL filter
- * ---------------
+ * -----------------------
*
* This filter gets added in the quick handler every time the CACHE_SAVE filter
* gets inserted. Its purpose is to remove a confirmed stale cache entry from
@@ -1078,6 +1336,33 @@
return ap_pass_brigade(f->next, in);
}
+/*
+ * CACHE filter
+ * ------------
+ *
+ * This filter can be optionally inserted into the filter chain by the admin as
+ * a marker representing the precise location within the filter chain where
+ * caching is to be performed.
+ *
+ * When the filter chain is set up in the non-quick version of the URL handler,
+ * the CACHE filter is replaced by the CACHE_OUT or CACHE_SAVE filter,
+ * effectively inserting the caching filters at the point indicated by the
+ * admin. The CACHE filter is then removed.
+ *
+ * This allows caching to be performed before the content is passed to the
+ * INCLUDES filter, or to a filter that might perform transformations unique
+ * to the specific request and that would otherwise be non-cacheable.
+ */
+static int cache_filter(ap_filter_t *f, apr_bucket_brigade *in)
+{
+ /* we are just a marker, so let's just remove ourselves */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, f->r->server,
+ "cache: CACHE filter was added twice, or was added in quick "
+ "handler mode and will be ignored.");
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, in);
+}
+
/* -------------------------------------------------------------- */
/* Setup configurable data */
@@ -1115,6 +1400,9 @@
/* flag indicating that query-string should be ignored when caching */
ps->ignorequerystring = 0;
ps->ignorequerystring_set = 0;
+ /* by default, run in the quick handler */
+ ps->quick = 1;
+ ps->quick_set = 0;
/* array of identifiers that should not be used for key calculation */
ps->ignore_session_id = apr_array_make(p, 10, sizeof(char *));
ps->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_UNSET;
@@ -1191,8 +1479,28 @@
(overrides->lockmaxage_set == 0)
? base->lockmaxage
: overrides->lockmaxage;
+ ps->quick =
+ (overrides->quick_set == 0)
+ ? base->quick
+ : overrides->quick;
return ps;
}
+
+static const char *set_cache_quick_handler(cmd_parms *parms, void *dummy,
+ int flag)
+{
+ cache_server_conf *conf;
+
+ conf =
+ (cache_server_conf *)ap_get_module_config(parms->server->module_config
+,
+ &cache_module);
+ conf->quick = flag;
+ conf->quick_set = 1;
+ return NULL;
+
+}
+
static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy,
int flag)
{
@@ -1508,6 +1816,9 @@
"The minimum time in seconds to cache a document"),
AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF,
"The default time in seconds to cache a document"),
+ AP_INIT_FLAG("CacheQuickHandler", set_cache_quick_handler, NULL,
+ RSRC_CONF,
+ "Run the cache in the quick handler, default on"),
AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
RSRC_CONF,
"Ignore Responses where there is no Last Modified Header"),
@@ -1548,8 +1859,10 @@
static void register_hooks(apr_pool_t *p)
{
/* cache initializer */
+ /* cache quick handler */
+ ap_hook_quick_handler(cache_quick_handler, NULL, NULL, APR_HOOK_FIRST);
/* cache handler */
- ap_hook_quick_handler(cache_url_handler, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_REALLY_FIRST);
/* cache filters
* XXX The cache filters need to run right after the handlers and before
* any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
@@ -1563,6 +1876,18 @@
* to be run by subrequest
*/
/*
+ * CACHE is placed into the filter chain at an admin specified location,
+ * and when the cache_handler is run, the CACHE filter is swapped with
+ * the CACHE_OUT filter, or CACHE_SAVE filter as appropriate. This has
+ * the effect of offering optional fine control of where the cache is
+ * inserted into the filter chain.
+ */
+ cache_filter_handle =
+ ap_register_output_filter("CACHE",
+ cache_filter,
+ NULL,
+ AP_FTYPE_RESOURCE);
+ /*
* CACHE_SAVE must go into the filter chain after a possible DEFLATE
* filter to ensure that the compressed content is stored.
* Incrementing filter type by 1 ensures his happens.
Modified: httpd/httpd/trunk/modules/cache/mod_cache.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/cache/mod_cache.h?rev=821202&r1=821201&r2=821202&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/cache/mod_cache.h (original)
+++ httpd/httpd/trunk/modules/cache/mod_cache.h Fri Oct 2 23:47:37 2009
@@ -172,6 +172,9 @@
int lockpath_set;
apr_time_t lockmaxage;
int lockmaxage_set;
+ /** run within the quick handler */
+ int quick;
+ int quick_set;
} cache_server_conf;
/* cache info information */
Re: svn commit: r821202 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_cache.xml
modules/cache/mod_cache.c modules/cache/mod_cache.h
Posted by Graham Leggett <mi...@sharp.fm>.
Ruediger Pluem wrote:
> 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;
> }
This code path is a normal handler, we don't need to.
ap_meets_conditions() is already done by the core.
> Plus we have one new warning:
>
> mod_cache.c: In function 'cache_handler':
> mod_cache.c:333: warning: unused variable 'auth'
Fixed in 821301.
Regards,
Graham
--
Re: svn commit: r821202 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_cache.xml
modules/cache/mod_cache.c modules/cache/mod_cache.h
Posted by Ruediger Pluem <rp...@apache.org>.
On 10/03/2009 01:47 AM, minfrin@apache.org 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