Changes with Apache 2.0.40
+ *) Add a filter_init parameter to the filter registration functions
+ so that a filter can execute arbitrary code before the handlers
+ are invoked. This resolves a problem where mod_include requests
+ would incorrectly return a 304. [Justin Erenkrantz]
+
*) Fix a long-standing bug in 2.0, CGI scripts were being called
with relative paths instead of absolute paths. Apache 1.3 used
absolute paths for everything except for SuExec, this brings back
* 20020602 (2.0.37-dev) Bucket API change (metadata buckets)
* 20020612 (2.0.38-dev) Changed server_rec->[keep_alive_]timeout to apr time
* 20020625 (2.0.40-dev) Changed conn_rec->keepalive to an enumeration
+ * 20020628 (2.0.40-dev) Added filter_init to filter registration functions
*/
#define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20020625
+#define MODULE_MAGIC_NUMBER_MAJOR 20020628
#endif
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
* for setting the association between a name for a filter and its
* associated callback (and other information).
*
+ * If the initialization function argument passed to the registration
+ * functions is non-NULL, it will be called iff the filter is in the input
+ * or output filter chains and before any data is generated to allow the
+ * filter to prepare for processing.
+ *
* The *bucket structure (and all those referenced by ->next and ->prev)
* should be considered "const". The filter is allowed to modify the
* next/prev to insert/remove/replace elements in the bucket list, but
* the types and values of the individual buckets should not be altered.
*
- * The return value of a filter should be an APR status value.
+ * For the input and output filters, the return value of a filter should be
+ * an APR status value. For the init function, the return value should
+ * be an HTTP error code or OK if it was successful.
*
* @ingroup filter
* @{
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes);
+typedef int (*ap_init_filter_func)(ap_filter_t *f);
typedef union ap_filter_func {
ap_out_filter_func out_func;
const char *name;
/** The function to call when this filter is invoked. */
ap_filter_func filter_func;
+ /** The function to call before the handlers are invoked. */
+ ap_init_filter_func filter_init_func;
/** The type of filter, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION.
* An AP_FTYPE_CONTENT filter modifies the data based on information
* found in the content. An AP_FTYPE_CONNECTION filter modifies the
* requests get an exact copy of the main requests filter chain.
*/
struct ap_filter_t {
- /** The internal representation of this filter. This includes
- * the filter's name, type, and the actual function pointer.
+ /** The internal representation of this filter. This includes
+ * the filter's name, type, and the actual function pointer.
*/
ap_filter_rec_t *frec;
*/
AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
ap_in_filter_func filter_func,
+ ap_init_filter_func filter_init,
ap_filter_type ftype);
/**
* This function is used to register an output filter with the system.
*/
AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
ap_out_filter_func filter_func,
+ ap_init_filter_func filter_init,
ap_filter_type ftype);
/**
*/
ap_register_output_filter("CACHE_IN",
cache_in_filter,
+ NULL,
AP_FTYPE_CONTENT_SET);
/* CACHE_OUT must go into the filter chain before SUBREQ_CORE to
* handle subrequsts. Decrementing filter type by 1 ensures this
*/
ap_register_output_filter("CACHE_OUT",
cache_out_filter,
+ NULL,
AP_FTYPE_CONTENT_SET-1);
ap_register_output_filter("CACHE_CONDITIONAL",
cache_conditional_filter,
+ NULL,
AP_FTYPE_CONTENT_SET);
ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
}
static void CaseFilterRegisterHooks(apr_pool_t *p)
{
ap_hook_insert_filter(CaseFilterInsertFilter,NULL,NULL,APR_HOOK_MIDDLE);
- ap_register_output_filter(s_szCaseFilterName,CaseFilterOutFilter,
+ ap_register_output_filter(s_szCaseFilterName,CaseFilterOutFilter,NULL,
AP_FTYPE_RESOURCE);
}
{
ap_hook_insert_filter(CaseFilterInInsertFilter, NULL, NULL,
APR_HOOK_MIDDLE);
- ap_register_input_filter(s_szCaseFilterName, CaseFilterInFilter,
+ ap_register_input_filter(s_szCaseFilterName, CaseFilterInFilter, NULL,
AP_FTYPE_RESOURCE);
}
{
ap_hook_fixups(find_code_page, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_insert_filter(xlate_insert_filter, NULL, NULL, APR_HOOK_REALLY_LAST);
- ap_register_output_filter(XLATEOUT_FILTER_NAME, xlate_out_filter,
+ ap_register_output_filter(XLATEOUT_FILTER_NAME, xlate_out_filter, NULL,
AP_FTYPE_RESOURCE);
- ap_register_input_filter(XLATEIN_FILTER_NAME, xlate_in_filter,
+ ap_register_input_filter(XLATEIN_FILTER_NAME, xlate_in_filter, NULL,
AP_FTYPE_RESOURCE);
}
*/
if (filter->mode == OUTPUT_FILTER) {
/* XXX need a way to ensure uniqueness among all filters */
- ap_register_output_filter(filter->name, ef_output_filter, AP_FTYPE_RESOURCE);
+ ap_register_output_filter(filter->name, ef_output_filter, NULL, AP_FTYPE_RESOURCE);
}
#if 0 /* no input filters yet */
else if (filter->mode == INPUT_FILTER) {
/* XXX need a way to ensure uniqueness among all filters */
- ap_register_input_filter(filter->name, ef_input_filter, AP_FTYPE_RESOURCE);
+ ap_register_input_filter(filter->name, ef_input_filter, NULL, AP_FTYPE_RESOURCE);
}
#endif
else {
static void register_hooks(apr_pool_t *p)
{
- ap_register_output_filter(deflateFilterName, deflate_out_filter,
+ ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
AP_FTYPE_CONTENT_SET);
- ap_register_input_filter(deflateFilterName, deflate_in_filter,
+ ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
AP_FTYPE_CONTENT_SET);
}
return NULL;
}
+static int includes_setup(ap_filter_t *f)
+{
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(f->r->per_dir_config,
+ &include_module);
+
+ /* When our xbithack value isn't set to full or our platform isn't
+ * providing group-level protection bits or our group-level bits do not
+ * have group-execite on, we will set the no_local_copy value to 1 so
+ * that we will not send 304s.
+ */
+ if ((*conf->xbithack != xbithack_full)
+ || !(f->r->finfo.valid & APR_FINFO_GPROT)
+ || !(f->r->finfo.protection & APR_GEXECUTE)) {
+ f->r->no_local_copy = 1;
+ }
+
+ return OK;
+}
+
static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
{
request_rec *r = f->r;
APR_REGISTER_OPTIONAL_FN(ap_register_include_handler);
ap_hook_post_config(include_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
ap_hook_fixups(include_fixup, NULL, NULL, APR_HOOK_LAST);
- ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_RESOURCE);
+ ap_register_output_filter("INCLUDES", includes_filter, includes_setup,
+ AP_FTYPE_RESOURCE);
}
module AP_MODULE_DECLARE_DATA include_module =
ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
ap_http_input_filter_handle =
ap_register_input_filter("HTTP_IN", ap_http_filter,
- AP_FTYPE_PROTOCOL);
+ NULL, AP_FTYPE_PROTOCOL);
ap_http_header_filter_handle =
ap_register_output_filter("HTTP_HEADER", ap_http_header_filter,
- AP_FTYPE_PROTOCOL);
+ NULL, AP_FTYPE_PROTOCOL);
ap_chunk_filter_handle =
- ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
+ ap_register_output_filter("CHUNK", chunk_filter,
+ NULL, AP_FTYPE_TRANSCODE);
ap_byterange_filter_handle =
ap_register_output_filter("BYTERANGE", ap_byterange_filter,
- AP_FTYPE_PROTOCOL);
+ NULL, AP_FTYPE_PROTOCOL);
ap_method_registry_init(p);
}
ap_hook_pre_config(header_pre_config,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_insert_filter(ap_headers_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
- ap_register_output_filter("FIXUP_HEADERS_OUT", ap_headers_output_filter, AP_FTYPE_CONTENT_SET);
+ ap_register_output_filter("FIXUP_HEADERS_OUT", ap_headers_output_filter,
+ NULL, AP_FTYPE_CONTENT_SET);
}
module AP_MODULE_DECLARE_DATA headers_module =
proxy_hook_scheme_handler(ap_proxy_ftp_handler, NULL, NULL, APR_HOOK_MIDDLE);
proxy_hook_canon_handler(ap_proxy_ftp_canon, NULL, NULL, APR_HOOK_MIDDLE);
/* filters */
- ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter, AP_FTYPE_RESOURCE);
+ ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter,
+ NULL, AP_FTYPE_RESOURCE);
}
module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
void ssl_io_filter_register(apr_pool_t *p)
{
- ap_register_input_filter (ssl_io_filter, ssl_io_filter_Input, AP_FTYPE_CONNECTION + 5);
- ap_register_output_filter (ssl_io_filter, ssl_io_filter_Output, AP_FTYPE_CONNECTION + 5);
+ ap_register_input_filter (ssl_io_filter, ssl_io_filter_Input, NULL, AP_FTYPE_CONNECTION + 5);
+ ap_register_output_filter (ssl_io_filter, ssl_io_filter_Output, NULL, AP_FTYPE_CONNECTION + 5);
return;
}
static void register_hooks(apr_pool_t * p)
{
ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
- AP_FTYPE_RESOURCE-1);
+ NULL, AP_FTYPE_RESOURCE-1);
}
static const command_rec bucketeer_filter_cmds[] = {
return create_empty_config(p);
}
+static int ap_invoke_filter_init(ap_filter_t *filters)
+{
+ while (filters) {
+ if (filters->frec->filter_init_func) {
+ int result = filters->frec->filter_init_func(filters);
+ if (result != OK) {
+ return result;
+ }
+ }
+ filters = filters->next;
+ }
+ return OK;
+}
+
AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
{
const char *handler;
*/
ap_run_insert_filter(r);
+ /* Before continuing, allow each filter that is in the two chains to
+ * run their init function to let them do any magic before we could
+ * start generating data.
+ */
+ result = ap_invoke_filter_init(r->input_filters);
+ if (result != OK) {
+ return result;
+ }
+ result = ap_invoke_filter_init(r->output_filters);
+ if (result != OK) {
+ return result;
+ }
+
if (!r->handler) {
handler = r->content_type ? r->content_type : ap_default_type(r);
if ((p=ap_strchr_c(handler, ';')) != NULL) {
ap_core_input_filter_handle =
ap_register_input_filter("CORE_IN", core_input_filter,
- AP_FTYPE_NETWORK);
+ NULL, AP_FTYPE_NETWORK);
ap_net_time_filter_handle =
ap_register_input_filter("NET_TIME", net_time_filter,
- AP_FTYPE_PROTOCOL);
+ NULL, AP_FTYPE_PROTOCOL);
ap_content_length_filter_handle =
ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
- AP_FTYPE_PROTOCOL);
+ NULL, AP_FTYPE_PROTOCOL);
ap_core_output_filter_handle =
ap_register_output_filter("CORE", core_output_filter,
- AP_FTYPE_NETWORK);
+ NULL, AP_FTYPE_NETWORK);
ap_subreq_core_filter_handle =
ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
- AP_FTYPE_CONTENT_SET);
- ap_old_write_func = ap_register_output_filter("OLD_WRITE",
- ap_old_write_filter, AP_FTYPE_RESOURCE - 10);
+ NULL, AP_FTYPE_CONTENT_SET);
+ ap_old_write_func =
+ ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
+ NULL, AP_FTYPE_RESOURCE - 10);
}
AP_DECLARE_DATA module core_module = {
static ap_filter_rec_t *register_filter(const char *name,
ap_filter_func filter_func,
+ ap_init_filter_func filter_init,
ap_filter_type ftype,
filter_trie_node **reg_filter_set)
{
frec->name = normalized_name;
}
frec->filter_func = filter_func;
+ frec->filter_init_func = filter_init;
frec->ftype = ftype;
apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup,
AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
ap_in_filter_func filter_func,
+ ap_init_filter_func filter_init,
ap_filter_type ftype)
{
ap_filter_func f;
f.in_func = filter_func;
- return register_filter(name, f, ftype, ®istered_input_filters);
+ return register_filter(name, f, filter_init, ftype,
+ ®istered_input_filters);
}
AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
ap_out_filter_func filter_func,
+ ap_init_filter_func filter_init,
ap_filter_type ftype)
{
ap_filter_func f;
f.out_func = filter_func;
- return register_filter(name, f, ftype, ®istered_output_filters);
+ return register_filter(name, f, filter_init, ftype,
+ ®istered_output_filters);
}
static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,