mod_policy.c revision fc251eb7714d158c2952bc2ddbbcfb9169098212
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/* Licensed to the Apache Software Foundation (ASF) under one or more
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * contributor license agreements. See the NOTICE file distributed with
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * this work for additional information regarding copyright ownership.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * The ASF licenses this file to You under the Apache License, Version 2.0
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * (the "License"); you may not use this file except in compliance with
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * the License. You may obtain a copy of the License at
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Unless required by applicable law or agreed to in writing, software
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * distributed under the License is distributed on an "AS IS" BASIS,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * See the License for the specific language governing permissions and
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * limitations under the License.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Originally written @ BBC by Graham Leggett
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * (C) 2011 British Broadcasting Corporation
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * mod_policy.c --- Enforce specific policies on outgoing requests, logging
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * or rejecting requests as appropriate.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * To enable, add the corresponding filters like so:
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * SetOutputFilter POLICY_TYPE,POLICY_LENGTH
e1e8390280254f7f0580d701e583f670643d4f3fnilgun policy_log, /* log the violation as a warning, but let it through */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun policy_enforce /* log the violation as an error, and decline */
e1e8390280254f7f0580d701e583f670643d4f3fnilguntypedef struct policy_conf
e1e8390280254f7f0580d701e583f670643d4f3fnilgun int policy; /* whether the filters should do anything at all */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *environment; /* optional name of the subprocess environment variable that
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * controls whether the policies are enforced.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *environment_log; /* value to trigger logging only */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *environment_ignore; /* value to suspend policy enforcement */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun apr_array_header_t *type_matches; /* content type default patterns to match */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *type_url;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *length_url;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun apr_array_header_t *vary_matches; /* Vary default patterns to match */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *vary_url;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *maxage_url;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *version;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Does the value of a flagpole override the original value?
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic int check_enabled(request_rec *r, policy_conf *conf,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (conf && result != policy_ignore && conf->environment) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *value = apr_table_get(r->subprocess_env, conf->environment);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun /* downgrade enforce to log? */
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (conf->environment_log && !strcmp(value, conf->environment_log)) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun /* downgrade enforce and log to ignore? */
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic void handle_policy(request_rec *r, policy_result result,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun const char *message, const char *url, apr_bucket_brigade *bb,
2704de98885368683621b01c8f8f4e4b01557611takashi "mod_policy: violation: %s, uri: %s",
2704de98885368683621b01c8f8f4e4b01557611takashi apr_table_addn(r->headers_out, "Warning", apr_psprintf(r->pool,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun "mod_policy: violation, rejecting request: %s, uri: %s",
e1e8390280254f7f0580d701e583f670643d4f3fnilgun apr_table_addn(r->err_headers_out, "Warning", apr_psprintf(r->pool,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun "299 %s \"Rejected: %s\"", ap_get_server_name(r), message));
case policy_ignore: {
if (f->r->content_type) {
if (end) {
fail = 0;
fail = 0;
if (fail) {
f->r->pool,
request_rec *r = f->r;
request_rec *r = f->r;
|| r->header_only
handle_policy(r, result, "Keepalive should be possible (supply Content-Length or HTTP/1.1 Transfer-Encoding)",
char *last;
while (token) {
* in http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.
if (etag) {
fail = 0;
fail = 0;
if (fail) {
if (lastmodified) {
fail = 0;
if (fail) {
if (fail) {
NULL);
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26. Over and above the
f->r->pool,
request_rec *r = f->r;
int fail = 0;
char *last;
if (pragma_header) {
while (token) {
if (cc_header) {
while (token) {
switch (token[0]) {
if (fail) {
request_rec *r = f->r;
const char *cc_header;
const char *expires_header;
const char *date_header;
char *last;
int max_age = 0;
int s_maxage = 0;
if (cc_header) {
while (token) {
switch (token[0]) {
if (s_maxage) {
f->r->pool,
if (max_age) {
f->r->pool,
f->r->pool,
f->r->pool,
f->r->pool,
handle_policy(r, result, "Response has no explicit freshness lifetime (s-maxage, max-age or Expires/Date)",
switch (proto_num) {
request_rec *r = f->r;
return (void *) new;
return new;
return NULL;
return NULL;
return NULL;
const char *type)
if (type) {
const char **match_ptr;
return NULL;
return NULL;
return NULL;
const char *vary)
if (vary) {
const char **match_ptr;
return NULL;
const char *action)
const char *url)
return NULL;
const char *action)
const char *url)
return NULL;
return NULL;
return NULL;
static const char *set_version(cmd_parms *cmd, void *dconf, const char *action, const char *version)
return NULL;
static const command_rec
policy_cmds[] =
| ACCESS_CONF,
NULL,
"Action to take (enforce, ignore, log) if a conditional request was not honoured. Defaults to 'log'."),
NULL,
"Environment variable to control policy enforcement, followed by the variable value for logging only, and the value for policy suspension."),
NULL,
NULL,
NULL,
"Action to take (enforce, ignore, log), followed by one or more valid content types containing optional wildcards ? and *"),
| ACCESS_CONF,
NULL,
"Action to take (enforce, ignore, log), followed by one or more headers containing optional wildcards ? and * that are NOT to appear in a Vary header"),
| ACCESS_CONF,
NULL,
"Action to take (enforce, ignore, log) if Last-Modified or Etag is missing or invalid. Defaults to 'log'."),
NULL,
NULL,
"Action to take (enforce, ignore, log) if a response has an effective maxage less than the age provided. Defaults to 'log'."),
NULL,
"Action to take (enforce, ignore, log) if a response has an HTTP version less than the version provided. Defaults to 'log HTTP/0.9'."),
{ NULL } };