mod_bucketeer.c revision 368b36c5dbc201e30733aed9a3fd43742c67d11a
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele/* Copyright 2002-2004 The Apache Software Foundation
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele *
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele * Licensed under the Apache License, Version 2.0 (the "License");
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele * you may not use this file except in compliance with the License.
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele * You may obtain a copy of the License at
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele *
5a58787efeb02a1c3f06569d019ad81fd2efa06end * http://www.apache.org/licenses/LICENSE-2.0
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Unless required by applicable law or agreed to in writing, software
5a58787efeb02a1c3f06569d019ad81fd2efa06end * distributed under the License is distributed on an "AS IS" BASIS,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 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.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen */
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end/*
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * mod_bucketeer.c: split buckets whenever we find a control-char
3f08db06526d6901aa08c110b5bc7dde6bc39905nd *
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Written by Ian Holsman
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
5a58787efeb02a1c3f06569d019ad81fd2efa06end */
3f08db06526d6901aa08c110b5bc7dde6bc39905nd
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd#include "httpd.h"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd#include "http_config.h"
5e740829c3448285963d3882530669f0112cf690gryzor#include "http_log.h"
aee1f193a276866212922ae5072e3014db28582frpluem#include "apr_strings.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "apr_general.h"
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd#include "util_filter.h"
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd#include "apr_buckets.h"
aee1f193a276866212922ae5072e3014db28582frpluem#include "http_request.h"
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele#include "http_protocol.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic const char bucketeerFilterName[] = "BUCKETEER";
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slivemodule AP_MODULE_DECLARE_DATA bucketeer_module;
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06endtypedef struct bucketeer_filter_config_t
5a58787efeb02a1c3f06569d019ad81fd2efa06end{
5a58787efeb02a1c3f06569d019ad81fd2efa06end char bucketdelimiter;
5a58787efeb02a1c3f06569d019ad81fd2efa06end char passdelimiter;
5a58787efeb02a1c3f06569d019ad81fd2efa06end char flushdelimiter;
df321386f1d9ed17a3e5e6468807996a12890d50gryzor} bucketeer_filter_config_t;
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic void *create_bucketeer_server_config(apr_pool_t *p, server_rec *s)
bd43fc31993cfc191e744a9490481f4294894099covener{
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh bucketeer_filter_config_t *c = apr_pcalloc(p, sizeof *c);
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end c->bucketdelimiter = 0x02; /* ^B */
5a58787efeb02a1c3f06569d019ad81fd2efa06end c->passdelimiter = 0x10; /* ^P */
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive c->flushdelimiter = 0x06; /* ^F */
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive return c;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive}
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slivetypedef struct bucketeer_ctx_t
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive{
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive apr_bucket_brigade *bb;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive} bucketeer_ctx_t;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slivestatic apr_status_t bucketeer_out_filter(ap_filter_t *f,
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive apr_bucket_brigade *bb)
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive{
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive apr_bucket *e;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive request_rec *r = f->r;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive bucketeer_ctx_t *ctx = f->ctx;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive bucketeer_filter_config_t *c;
5d7e5de2da57434c8e68c8fa49cbf6d70ee0f817slive
5a58787efeb02a1c3f06569d019ad81fd2efa06end c = ap_get_module_config(r->server->module_config, &bucketeer_module);
5a58787efeb02a1c3f06569d019ad81fd2efa06end
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive /* If have a context, it means we've done this before successfully. */
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (!ctx) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (!r->content_type || strncmp(r->content_type, "text/", 5)) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive ap_remove_output_filter(f);
06d77ae37da42a6f8bbea25b7d7f8b6629245629slive return ap_pass_brigade(f->next, bb);
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive }
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive /* We're cool with filtering this. */
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
c6f41bc69d643835804e7e831776d3d46c6f5962slive apr_table_unset(f->r->headers_out, "Content-Length");
c6f41bc69d643835804e7e831776d3d46c6f5962slive }
c6f41bc69d643835804e7e831776d3d46c6f5962slive
c6f41bc69d643835804e7e831776d3d46c6f5962slive for (e = APR_BRIGADE_FIRST(bb);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem e != APR_BRIGADE_SENTINEL(bb);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem e = APR_BUCKET_NEXT(e))
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive const char *data;
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive apr_size_t len, i, lastpos;
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (APR_BUCKET_IS_EOS(e)) {
263168fdb45221efa79580de89bdde883b7561f7sf APR_BUCKET_REMOVE(e);
263168fdb45221efa79580de89bdde883b7561f7sf APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
263168fdb45221efa79580de89bdde883b7561f7sf
263168fdb45221efa79580de89bdde883b7561f7sf /* Okay, we've seen the EOS.
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive * Time to pass it along down the chain.
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem return ap_pass_brigade(f->next, ctx->bb);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem }
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem if (APR_BUCKET_IS_FLUSH(e)) {
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem /*
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem * Ignore flush buckets for the moment..
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem * we decide what to stream
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem continue;
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem }
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem if (APR_BUCKET_IS_METADATA(e)) {
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem /* metadata bucket */
c6f41bc69d643835804e7e831776d3d46c6f5962slive apr_bucket *cpy;
aee1f193a276866212922ae5072e3014db28582frpluem apr_bucket_copy(e, &cpy);
c6f41bc69d643835804e7e831776d3d46c6f5962slive APR_BRIGADE_INSERT_TAIL(ctx->bb, cpy);
c6f41bc69d643835804e7e831776d3d46c6f5962slive continue;
06d77ae37da42a6f8bbea25b7d7f8b6629245629slive }
c6f41bc69d643835804e7e831776d3d46c6f5962slive
c6f41bc69d643835804e7e831776d3d46c6f5962slive /* read */
c6f41bc69d643835804e7e831776d3d46c6f5962slive apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
c6f41bc69d643835804e7e831776d3d46c6f5962slive
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (len > 0) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive lastpos = 0;
c6f41bc69d643835804e7e831776d3d46c6f5962slive for (i = 0; i < len; i++) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (data[i] == c->flushdelimiter ||
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive data[i] == c->bucketdelimiter ||
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive data[i] == c->passdelimiter) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive apr_bucket *p;
ffb01336be79c64046b636e59fa8ddca8ec029edsf if (i - lastpos > 0) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive &data[lastpos],
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive i - lastpos),
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive i - lastpos,
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive f->r->pool,
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive f->c->bucket_alloc);
4ee3ac9c23e31f43d39414f4072f1b1456e43ff8igalic APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem }
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive lastpos = i + 1;
4ee3ac9c23e31f43d39414f4072f1b1456e43ff8igalic if (data[i] == c->flushdelimiter) {
aee1f193a276866212922ae5072e3014db28582frpluem p = apr_bucket_flush_create(f->c->bucket_alloc);
4ee3ac9c23e31f43d39414f4072f1b1456e43ff8igalic APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
4ee3ac9c23e31f43d39414f4072f1b1456e43ff8igalic }
4ee3ac9c23e31f43d39414f4072f1b1456e43ff8igalic if (data[i] == c->flushdelimiter ||
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive data[i] == c->passdelimiter) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive ap_pass_brigade(f->next, ctx->bb);
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive /* apr_brigade_cleanup(ctx->bb);*/
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive }
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive }
aee1f193a276866212922ae5072e3014db28582frpluem }
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive /* XXX: really should append this to the next 'real' bucket */
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive if (lastpos < i) {
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive apr_bucket *p;
aa8cf57195dfb7fa3d0baedf81f8be377946cea8slive p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
5a58787efeb02a1c3f06569d019ad81fd2efa06end &data[lastpos],
aee1f193a276866212922ae5072e3014db28582frpluem i - lastpos),
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele i - lastpos,
aee1f193a276866212922ae5072e3014db28582frpluem f->r->pool,
aee1f193a276866212922ae5072e3014db28582frpluem f->c->bucket_alloc);
650ba5bfc49e73bf370f3cff32d3cdca004a2861rbowen lastpos = i;
aee1f193a276866212922ae5072e3014db28582frpluem APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
aee1f193a276866212922ae5072e3014db28582frpluem }
aee1f193a276866212922ae5072e3014db28582frpluem }
aee1f193a276866212922ae5072e3014db28582frpluem }
aee1f193a276866212922ae5072e3014db28582frpluem
aee1f193a276866212922ae5072e3014db28582frpluem return APR_SUCCESS;
aee1f193a276866212922ae5072e3014db28582frpluem}
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabelestatic void register_hooks(apr_pool_t * p)
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele{
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele NULL, AP_FTYPE_RESOURCE-1);
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele}
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabelestatic const command_rec bucketeer_filter_cmds[] = {
aee1f193a276866212922ae5072e3014db28582frpluem {NULL}
aee1f193a276866212922ae5072e3014db28582frpluem};
aee1f193a276866212922ae5072e3014db28582frpluem
aee1f193a276866212922ae5072e3014db28582frpluemmodule AP_MODULE_DECLARE_DATA bucketeer_module = {
aee1f193a276866212922ae5072e3014db28582frpluem STANDARD20_MODULE_STUFF,
aee1f193a276866212922ae5072e3014db28582frpluem NULL,
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele NULL,
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele create_bucketeer_server_config,
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele NULL,
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele bucketeer_filter_cmds,
4ab980a06412fd86f52a6d054fb7e26de155c530erikabele register_hooks
ea49840bfe8467a7d7bd4db27b1d4880a85511aberikabele};
aee1f193a276866212922ae5072e3014db28582frpluem