/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#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"
#include "ap_expr.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 {
const char **types;
/** The filter that implements this provider */
/** The next provider in the list */
};
/** we need provider_ctx to save ctx values set by providers in filter_init */
struct provider_ctx {
void *ctx;
};
typedef struct {
void *fctx;
} harness_ctx;
typedef struct mod_filter_chain {
const char *fname;
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;
}
}
{
int err;
"Chaining of FilterProviders not supported");
return HTTP_INTERNAL_SERVER_ERROR;
}
else 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;
}
{
int match = 0;
request_rec *r = f->r;
#ifndef NO_PROTOCOL
unsigned int proto_flags;
#endif
/* Check registered providers in order */
if (err) {
"Error evaluating filter dispatch condition: %s",
err);
match = 0;
}
"Expression condition for '%s' %s",
}
else if (r->content_type) {
"Content-Type '%s' ...", r->content_type);
while (*type) {
/* Handle 'content-type;charset=...' correctly */
"... matched '%s'", *type);
match = 1;
break;
}
else {
"... did not match '%s'", *type);
}
type++;
}
"Content-Type condition for '%s' %s",
}
else {
"Content-Type condition for '%s' did not match: "
}
if (match) {
/* 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) {
"Cache-Control");
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;
}
{
#ifndef NO_PROTOCOL
const char *cachecontrol;
#endif
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
{
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;
}
{
const char *c;
/* 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 (expr) {
if (err) {
"Error parsing FilterProvider expression:", err,
NULL);
}
}
else {
}
return NULL;
}
const char *expr)
{
}
{
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 */
/** IG: Add a NULL provider to the beginning so that
* we can ensure that we'll empty everything before
* this when doing config merges later */
break;
case '=': /* initialise chain with this arg */
/** IG: Prepend a NULL provider to the beginning as above */
break;
default: /* add to end */
q->next = p;
}
else {
}
break;
}
return NULL;
}
{
const char *rv;
const char *fname;
int seen_name = 0;
/* construct fname from name */
/* check whether this is already registered, in which case
* it's already in the filter chain
*/
seen_name = 1;
}
/* If it's the first time through, add to filterchain */
}
return rv;
}
{
/* back compatibility, need to parse multiple components in filter name */
char *pname;
char *name;
const char **types;
if (argc < 2)
return "AddOutputFilterByType requires at least two arguments";
}
return rv;
}
const char *level)
{
if (!frec) {
}
return NULL;
}
{
mod_filter_chain *p;
#ifndef NO_PROTOCOL
#endif
/** IG: Now that we've merged to the final config, go one last time
* through the chain, and prune out the NULL filters */
}
"Unknown filter %s not added", p->fname);
continue;
}
#ifndef NO_PROTOCOL
ranges = 0;
}
#endif
}
return;
}
{
}
{
return cfg;
}
{
mod_filter_chain *p;
base->live_filters);
}
else if (savelink) {
}
else {
}
}
/** Filter out merged chain resets */
}
else if (savelink) {
}
else {
}
}
}
}
else {
}
return conf;
}
"filter-name [filter-type]"),
"filter-name provider-name match-expression"),
"list of filter names with optional [+-=!@]"),
"filter-name debug-level"),
"output filter name followed by one or more content-types"),
#ifndef NO_PROTOCOL
"filter-name [provider-name] protocol-args"),
#endif
{ NULL }
};
NULL,
NULL,
};