mod_bucketeer.c revision e2f3f3a981b845a0f26efacbe145659a63240944
6ae232055d4d8a97267517c5e50074c2c819941and/* Licensed to the Apache Software Foundation (ASF) under one or more
6ae232055d4d8a97267517c5e50074c2c819941and * contributor license agreements. See the NOTICE file distributed with
6ae232055d4d8a97267517c5e50074c2c819941and * this work for additional information regarding copyright ownership.
6ae232055d4d8a97267517c5e50074c2c819941and * The ASF licenses this file to You under the Apache License, Version 2.0
6ae232055d4d8a97267517c5e50074c2c819941and * (the "License"); you may not use this file except in compliance with
6ae232055d4d8a97267517c5e50074c2c819941and * the License. You may obtain a copy of the License at
6ae232055d4d8a97267517c5e50074c2c819941and *
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * http://www.apache.org/licenses/LICENSE-2.0
6ae232055d4d8a97267517c5e50074c2c819941and *
6ae232055d4d8a97267517c5e50074c2c819941and * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
2e545ce2450a9953665f701bb05350f0d3f26275nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
6ae232055d4d8a97267517c5e50074c2c819941and */
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and/*
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * mod_bucketeer.c: split buckets whenever we find a control-char
3f08db06526d6901aa08c110b5bc7dde6bc39905nd *
6ae232055d4d8a97267517c5e50074c2c819941and * Written by Ian Holsman
6ae232055d4d8a97267517c5e50074c2c819941and *
6ae232055d4d8a97267517c5e50074c2c819941and */
b43f840409794ed298e8634f6284741f193b6c4ftakashi
6ae232055d4d8a97267517c5e50074c2c819941and#include "httpd.h"
6ae232055d4d8a97267517c5e50074c2c819941and#include "http_config.h"
6ae232055d4d8a97267517c5e50074c2c819941and#include "http_log.h"
b43f840409794ed298e8634f6284741f193b6c4ftakashi#include "apr_strings.h"
45d66a3a49ac14b7f18cd4d733c1947801b55172sf#include "apr_general.h"
6ae232055d4d8a97267517c5e50074c2c819941and#include "util_filter.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "apr_buckets.h"
6ae232055d4d8a97267517c5e50074c2c819941and#include "http_request.h"
6ae232055d4d8a97267517c5e50074c2c819941and#include "http_protocol.h"
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941andstatic const char bucketeerFilterName[] = "BUCKETEER";
6ae232055d4d8a97267517c5e50074c2c819941andmodule AP_MODULE_DECLARE_DATA bucketeer_module;
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941andtypedef struct bucketeer_filter_config_t
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi{
6ae232055d4d8a97267517c5e50074c2c819941and char bucketdelimiter;
6ae232055d4d8a97267517c5e50074c2c819941and char passdelimiter;
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi char flushdelimiter;
6ae232055d4d8a97267517c5e50074c2c819941and} bucketeer_filter_config_t;
6ae232055d4d8a97267517c5e50074c2c819941and
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi
6ae232055d4d8a97267517c5e50074c2c819941andstatic void *create_bucketeer_server_config(apr_pool_t *p, server_rec *s)
6ae232055d4d8a97267517c5e50074c2c819941and{
6ae232055d4d8a97267517c5e50074c2c819941and bucketeer_filter_config_t *c = apr_pcalloc(p, sizeof *c);
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and c->bucketdelimiter = 0x02; /* ^B */
6ae232055d4d8a97267517c5e50074c2c819941and c->passdelimiter = 0x10; /* ^P */
6ae232055d4d8a97267517c5e50074c2c819941and c->flushdelimiter = 0x06; /* ^F */
6ae232055d4d8a97267517c5e50074c2c819941and
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi return c;
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi}
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi
1d980e5489836e977ba59b419e27b0ec875c4bd3takashitypedef struct bucketeer_ctx_t
6ae232055d4d8a97267517c5e50074c2c819941and{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar apr_bucket_brigade *bb;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar} bucketeer_ctx_t;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic apr_status_t bucketeer_out_filter(ap_filter_t *f,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar apr_bucket_brigade *bb)
6ae232055d4d8a97267517c5e50074c2c819941and{
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket *e;
6ae232055d4d8a97267517c5e50074c2c819941and request_rec *r = f->r;
6ae232055d4d8a97267517c5e50074c2c819941and bucketeer_ctx_t *ctx = f->ctx;
6ae232055d4d8a97267517c5e50074c2c819941and bucketeer_filter_config_t *c;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
6ae232055d4d8a97267517c5e50074c2c819941and c = ap_get_module_config(r->server->module_config, &bucketeer_module);
6ae232055d4d8a97267517c5e50074c2c819941and
6a3ab831a34f470b077294a173f24fcf1e5f0a3ctakashi /* If have a context, it means we've done this before successfully. */
6ae232055d4d8a97267517c5e50074c2c819941and if (!ctx) {
6ae232055d4d8a97267517c5e50074c2c819941and if (!r->content_type || strncmp(r->content_type, "text/", 5)) {
6ae232055d4d8a97267517c5e50074c2c819941and ap_remove_output_filter(f);
6a3ab831a34f470b077294a173f24fcf1e5f0a3ctakashi return ap_pass_brigade(f->next, bb);
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh }
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and /* We're cool with filtering this. */
6ae232055d4d8a97267517c5e50074c2c819941and ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
6a3ab831a34f470b077294a173f24fcf1e5f0a3ctakashi ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
6ae232055d4d8a97267517c5e50074c2c819941and apr_table_unset(f->r->headers_out, "Content-Length");
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and for (e = APR_BRIGADE_FIRST(bb);
6ae232055d4d8a97267517c5e50074c2c819941and e != APR_BRIGADE_SENTINEL(bb);
6ae232055d4d8a97267517c5e50074c2c819941and e = APR_BUCKET_NEXT(e))
6ae232055d4d8a97267517c5e50074c2c819941and {
6ae232055d4d8a97267517c5e50074c2c819941and const char *data;
6ae232055d4d8a97267517c5e50074c2c819941and apr_size_t len, i, lastpos;
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and if (APR_BUCKET_IS_EOS(e)) {
6ae232055d4d8a97267517c5e50074c2c819941and APR_BUCKET_REMOVE(e);
6ae232055d4d8a97267517c5e50074c2c819941and APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and /* Okay, we've seen the EOS.
6ae232055d4d8a97267517c5e50074c2c819941and * Time to pass it along down the chain.
6ae232055d4d8a97267517c5e50074c2c819941and */
6ae232055d4d8a97267517c5e50074c2c819941and return ap_pass_brigade(f->next, ctx->bb);
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and if (APR_BUCKET_IS_FLUSH(e)) {
6ae232055d4d8a97267517c5e50074c2c819941and /*
6ae232055d4d8a97267517c5e50074c2c819941and * Ignore flush buckets for the moment..
6ae232055d4d8a97267517c5e50074c2c819941and * we decide what to stream
6ae232055d4d8a97267517c5e50074c2c819941and */
6ae232055d4d8a97267517c5e50074c2c819941and continue;
6ae232055d4d8a97267517c5e50074c2c819941and }
6a3ab831a34f470b077294a173f24fcf1e5f0a3ctakashi
6ae232055d4d8a97267517c5e50074c2c819941and if (APR_BUCKET_IS_METADATA(e)) {
6ae232055d4d8a97267517c5e50074c2c819941and /* metadata bucket */
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket *cpy;
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket_copy(e, &cpy);
6ae232055d4d8a97267517c5e50074c2c819941and APR_BRIGADE_INSERT_TAIL(ctx->bb, cpy);
6ae232055d4d8a97267517c5e50074c2c819941and continue;
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and /* read */
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and if (len > 0) {
6ae232055d4d8a97267517c5e50074c2c819941and lastpos = 0;
6ae232055d4d8a97267517c5e50074c2c819941and for (i = 0; i < len; i++) {
6ae232055d4d8a97267517c5e50074c2c819941and if (data[i] == c->flushdelimiter ||
6ae232055d4d8a97267517c5e50074c2c819941and data[i] == c->bucketdelimiter ||
6ae232055d4d8a97267517c5e50074c2c819941and data[i] == c->passdelimiter) {
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket *p;
6a3ab831a34f470b077294a173f24fcf1e5f0a3ctakashi if (i - lastpos > 0) {
6ae232055d4d8a97267517c5e50074c2c819941and p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
6ae232055d4d8a97267517c5e50074c2c819941and &data[lastpos],
6ae232055d4d8a97267517c5e50074c2c819941and i - lastpos),
6ae232055d4d8a97267517c5e50074c2c819941and i - lastpos,
6ae232055d4d8a97267517c5e50074c2c819941and f->r->pool,
6ae232055d4d8a97267517c5e50074c2c819941and f->c->bucket_alloc);
6ae232055d4d8a97267517c5e50074c2c819941and APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and lastpos = i + 1;
6ae232055d4d8a97267517c5e50074c2c819941and if (data[i] == c->flushdelimiter) {
6ae232055d4d8a97267517c5e50074c2c819941and p = apr_bucket_flush_create(f->c->bucket_alloc);
6ae232055d4d8a97267517c5e50074c2c819941and APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and if (data[i] == c->passdelimiter) {
6ae232055d4d8a97267517c5e50074c2c819941and apr_status_t rv;
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and rv = ap_pass_brigade(f->next, ctx->bb);
6ae232055d4d8a97267517c5e50074c2c819941and if (rv) {
6ae232055d4d8a97267517c5e50074c2c819941and return rv;
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and /* XXX: really should append this to the next 'real' bucket */
6ae232055d4d8a97267517c5e50074c2c819941and if (lastpos < i) {
6ae232055d4d8a97267517c5e50074c2c819941and apr_bucket *p;
6ae232055d4d8a97267517c5e50074c2c819941and p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
6ae232055d4d8a97267517c5e50074c2c819941and &data[lastpos],
6ae232055d4d8a97267517c5e50074c2c819941and i - lastpos),
6ae232055d4d8a97267517c5e50074c2c819941and i - lastpos,
6ae232055d4d8a97267517c5e50074c2c819941and f->r->pool,
6ae232055d4d8a97267517c5e50074c2c819941and f->c->bucket_alloc);
6ae232055d4d8a97267517c5e50074c2c819941and lastpos = i;
6ae232055d4d8a97267517c5e50074c2c819941and APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and }
6ae232055d4d8a97267517c5e50074c2c819941and
6ae232055d4d8a97267517c5e50074c2c819941and return APR_SUCCESS;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic void register_hooks(apr_pool_t * p)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar NULL, AP_FTYPE_RESOURCE-1);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic const command_rec bucketeer_filter_cmds[] = {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar {NULL}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar};
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarAP_DECLARE_MODULE(bucketeer) = {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar STANDARD20_MODULE_STUFF,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar NULL,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar NULL,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar create_bucketeer_server_config,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar NULL,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar bucketeer_filter_cmds,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar register_hooks
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar};
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar