mod_filter.c revision 7bffd59eadbb9e58f17fd29655fce6509fc1bb36
/* Copyright 2004-2005 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Originally contributed by Nick Kew <nick webthing.com>
*
* At the time of writing, this is designed primarily for use with
* httpd 2.2, but is also back-compatible with 2.0. It is likely
* that the 2.0 and 2.2 versions may diverge in future, as additional
* capabilities for 2.2 are added, including updates to util_filter.
*
* 21/9/04: Unifying data structures with util_filter.
* From now on, until and unless we backport, mod_filter requires
* util_filter.h from CVS or httpd-2.1+ to compile.
* There's a minimal patch for httpd-2.0 users maintained by Nick
* to compile mod_filter at http://www.apache.org/~niq/
*/
#define APR_WANT_STRFUNC
#include "apr_want.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_hash.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_log.h"
#include "util_filter.h"
/**
* @brief is a filter provider, as defined and implemented by mod_filter.
*
* The struct is a linked list, with dispatch criteria
* defined for each filter. The provider implementation itself is a
* (2.0-compatible) ap_filter_rec_t* frec.
*/
struct ap_filter_provider_t {
/** How to match this provider to filter dispatch criterion */
enum {
} match_type;
/** negation on match_type */
int not;
/** The dispatch match itself - union member depends on match_type */
union {
const char *string;
int number;
} match;
/** The filter that implements this provider */
/** The next provider in the list */
/** Dispatch criteria for filter providers */
enum {
} dispatch;
/** Match value for filter providers */
const char* value;
};
/** we need provider_ctx to save ctx values set by providers in filter_init */
typedef struct provider_ctx provider_ctx;
struct provider_ctx {
void *ctx;
};
typedef struct {
void *fctx;
} harness_ctx;
typedef struct mod_filter_chain {
const char *fname;
struct mod_filter_chain *next;
typedef struct {
typedef struct {
const char* range ;
} mod_filter_ctx ;
{
apr_bucket *b;
switch (debug) {
case 0: /* normal, operational use */
return;
case 1: /* mod_diagnostics level */
for (b = APR_BRIGADE_FIRST(bb);
b != APR_BRIGADE_SENTINEL(bb);
b = APR_BUCKET_NEXT(b)) {
"%s: type: %s, length: %" APR_SIZE_T_FMT,
b->length);
}
break;
}
}
static int filter_init(ap_filter_t *f)
{
int err;
if (p->frec->filter_init_func) {
return err; /* if anyone errors out here, so do we */
}
/* the filter init function set a ctx - we need to record it */
}
}
}
return OK;
}
{
char *str1;
int match;
unsigned int proto_flags;
request_rec *r = f->r;
/* Check registered providers in order */
match = 1;
case REQUEST_HEADERS:
break;
case RESPONSE_HEADERS:
break;
case SUBPROCESS_ENV:
break;
case CONTENT_TYPE:
str = r->content_type;
break;
case HANDLER:
break;
}
/* treat nulls so we don't have to check every strcmp individually
* Not sure if there's anything better to do with them
*/
if (!str) {
match = 0;
}
}
match = 0;
}
else {
/* Now we have no nulls, so we can do string and regexp matching */
switch (provider->match_type) {
case STRING_MATCH:
match = 0;
}
break;
case STRING_CONTAINS:
match = 0;
}
break;
case REGEX_MATCH:
== AP_REG_NOMATCH) {
match = 0;
}
break;
case INT_EQ:
match = 0;
}
break;
case INT_LT:
match = 0;
}
break;
case INT_LE:
match = 0;
}
break;
case INT_GT:
match = 0;
}
break;
case INT_GE:
match = 0;
}
break;
case DEFINED: /* we already handled this:-) */
break;
}
}
/* condition matches this provider */
#ifndef NO_PROTOCOL
/* check protocol
*
* FIXME:
* This is a quick hack and almost certainly buggy.
* The idea is that by putting this in mod_filter, we relieve
* filter implementations of the burden of fixing up HTTP headers
* for cases that are routinely affected by filters.
*
* Default is ALWAYS to do nothing, so as not to tread on the
* toes of filters which want to do it themselves.
*
*/
/* some specific things can't happen in a proxy */
if (r->proxyreq) {
if (proto_flags & AP_FILTER_PROTO_NO_PROXY) {
/* can't use this provider; try next */
continue;
}
if (proto_flags & AP_FILTER_PROTO_TRANSFORM) {
if (str) {
/* can't use this provider; try next */
continue;
}
}
apr_psprintf(r->pool,
"214 %s Transformation applied",
r->hostname));
}
}
/* things that are invalidated if the filter transforms content */
if (proto_flags & AP_FILTER_PROTO_CHANGE) {
if (proto_flags & AP_FILTER_PROTO_CHANGE_LENGTH) {
}
}
/* no-cache is for a filter that has different effect per-hit */
if (proto_flags & AP_FILTER_PROTO_NO_CACHE) {
}
if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) {
}
/* restore range header we saved earlier */
}
#endif
}
}
return 1;
}
}
/* No provider matched */
return 0;
}
{
const char *cachecontrol;
char *str;
if (f->r->status != 200) {
}
/* look up a handler function if we haven't already set it */
#ifndef NO_PROTOCOL
if (f->r->proxyreq) {
}
"Cache-Control");
if (cachecontrol) {
}
}
}
}
#endif
if (!filter_lookup(f, filter)) {
}
}
/* call the content filter with its own context, then restore our
* context
*/
return ret;
}
#ifndef NO_PROTOCOL
{
static const char *sep = ";, \t";
char *arg;
char *tok = 0;
unsigned int flags = 0;
if (!filter) {
return "FilterProtocol: No such filter";
}
/* Fixup the args: it's really pname that's optional */
}
else {
/* Find provider */
break;
}
}
if (!provider) {
return "FilterProtocol: No such provider for this filter";
}
}
/* Now set flags from our args */
}
}
}
}
}
}
}
if (pname) {
}
else {
}
return NULL;
}
#endif
const char *place)
{
if (place) {
}
}
}
}
}
return NULL;
}
{
int flags;
const char *rxend;
const char *c;
char *str;
const char *eq;
/* insist on exactly four arguments */
return "usage: FilterProvider filter provider condition match" ;
}
/* fname has been declared with DeclareFilter, so we can look it up */
/* or if provider is mod_filter itself, we can also look it up */
if (!frec) {
if ( c ) {
return c;
}
}
if (!frec) {
}
/* if provider has been registered, we can look it up */
if (!provider_frec) {
}
if (!provider_frec) {
}
if (*match == '!') {
++match;
}
else {
}
switch (*match++) {
case '<':
if (*match == '=') {
++match;
}
else {
}
break;
case '>':
if (*match == '=') {
++match;
}
else {
}
break;
case '=':
break;
case '/':
if (!rxend) {
return "Bad regexp syntax";
}
for (c = rxend+1; *c; ++c) {
switch (*c) {
}
}
flags);
break;
case '*':
break;
case '$':
break;
default:
break;
}
/* determine what a filter will dispatch this provider on */
if (eq) {
}
}
}
else {
return "FilterProvider: unrecognized dispatch table";
}
}
else {
}
else {
}
}
}
return NULL;
}
{
mod_filter_chain *p;
mod_filter_chain *q;
switch (arg[0]) {
case '+': /* add to end of chain */
q->next = p;
}
else {
}
break;
case '@': /* add to start of chain */
break;
case '-': /* remove from chain */
}
}
}
else {
}
}
break;
case '!': /* Empty the chain */
break;
case '=': /* initialise chain with this arg */
break;
default: /* add to end */
q->next = p;
}
else {
}
break;
}
return NULL;
}
const char *level)
{
if (!frec) {
}
return NULL;
}
static void filter_insert(request_rec *r)
{
mod_filter_chain *p;
#ifndef NO_PROTOCOL
int ranges = 1;
#endif
#ifndef NO_PROTOCOL
ranges = 0;
}
#endif
}
return;
}
{
}
{
return cfg;
}
{
mod_filter_chain *savelink = 0;
mod_filter_chain *p;
base->live_filters);
if (savelink) {
}
else {
}
}
}
}
}
else {
}
return conf;
}
static const command_rec filter_cmds[] = {
"filter-name [, filter-type]"),
/** we don't have a TAKE4, so we have to use RAW_ARGS */
"filter-name, provider-name, dispatch--criterion, dispatch-match"),
"list of filter names with optional [+-=!@]"),
"Debug level"),
#ifndef NO_PROTOCOL
"filter-name [provider-name] protocol-args"),
#endif
{ NULL }
};
NULL,
NULL,
};