removed some of the debug logging and added author details
[httpd-crcsyncproxy.git] / modules / debugging / mod_bucketeer.c
blobff6f5ebd49c824cba188b91e42e6c612b115ac5d
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * mod_bucketeer.c: split buckets whenever we find a control-char
20 * Written by Ian Holsman
24 #include "httpd.h"
25 #include "http_config.h"
26 #include "http_log.h"
27 #include "apr_strings.h"
28 #include "apr_general.h"
29 #include "util_filter.h"
30 #include "apr_buckets.h"
31 #include "http_request.h"
32 #include "http_protocol.h"
34 static const char bucketeerFilterName[] = "BUCKETEER";
35 module AP_MODULE_DECLARE_DATA bucketeer_module;
37 typedef struct bucketeer_filter_config_t
39 char bucketdelimiter;
40 char passdelimiter;
41 char flushdelimiter;
42 } bucketeer_filter_config_t;
45 static void *create_bucketeer_server_config(apr_pool_t *p, server_rec *s)
47 bucketeer_filter_config_t *c = apr_pcalloc(p, sizeof *c);
49 c->bucketdelimiter = 0x02; /* ^B */
50 c->passdelimiter = 0x10; /* ^P */
51 c->flushdelimiter = 0x06; /* ^F */
53 return c;
56 typedef struct bucketeer_ctx_t
58 apr_bucket_brigade *bb;
59 } bucketeer_ctx_t;
61 static apr_status_t bucketeer_out_filter(ap_filter_t *f,
62 apr_bucket_brigade *bb)
64 apr_bucket *e;
65 request_rec *r = f->r;
66 bucketeer_ctx_t *ctx = f->ctx;
67 bucketeer_filter_config_t *c;
69 c = ap_get_module_config(r->server->module_config, &bucketeer_module);
71 /* If have a context, it means we've done this before successfully. */
72 if (!ctx) {
73 if (!r->content_type || strncmp(r->content_type, "text/", 5)) {
74 ap_remove_output_filter(f);
75 return ap_pass_brigade(f->next, bb);
78 /* We're cool with filtering this. */
79 ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
80 ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
81 apr_table_unset(f->r->headers_out, "Content-Length");
84 for (e = APR_BRIGADE_FIRST(bb);
85 e != APR_BRIGADE_SENTINEL(bb);
86 e = APR_BUCKET_NEXT(e))
88 const char *data;
89 apr_size_t len, i, lastpos;
91 if (APR_BUCKET_IS_EOS(e)) {
92 APR_BUCKET_REMOVE(e);
93 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
95 /* Okay, we've seen the EOS.
96 * Time to pass it along down the chain.
98 return ap_pass_brigade(f->next, ctx->bb);
101 if (APR_BUCKET_IS_FLUSH(e)) {
103 * Ignore flush buckets for the moment..
104 * we decide what to stream
106 continue;
109 if (APR_BUCKET_IS_METADATA(e)) {
110 /* metadata bucket */
111 apr_bucket *cpy;
112 apr_bucket_copy(e, &cpy);
113 APR_BRIGADE_INSERT_TAIL(ctx->bb, cpy);
114 continue;
117 /* read */
118 apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
120 if (len > 0) {
121 lastpos = 0;
122 for (i = 0; i < len; i++) {
123 if (data[i] == c->flushdelimiter ||
124 data[i] == c->bucketdelimiter ||
125 data[i] == c->passdelimiter) {
126 apr_bucket *p;
127 if (i - lastpos > 0) {
128 p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
129 &data[lastpos],
130 i - lastpos),
131 i - lastpos,
132 f->r->pool,
133 f->c->bucket_alloc);
134 APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
136 lastpos = i + 1;
137 if (data[i] == c->flushdelimiter) {
138 p = apr_bucket_flush_create(f->c->bucket_alloc);
139 APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
141 if (data[i] == c->passdelimiter) {
142 apr_status_t rv;
144 rv = ap_pass_brigade(f->next, ctx->bb);
145 if (rv) {
146 return rv;
151 /* XXX: really should append this to the next 'real' bucket */
152 if (lastpos < i) {
153 apr_bucket *p;
154 p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
155 &data[lastpos],
156 i - lastpos),
157 i - lastpos,
158 f->r->pool,
159 f->c->bucket_alloc);
160 lastpos = i;
161 APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
166 return APR_SUCCESS;
169 static void register_hooks(apr_pool_t * p)
171 ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
172 NULL, AP_FTYPE_RESOURCE-1);
175 static const command_rec bucketeer_filter_cmds[] = {
176 {NULL}
179 module AP_MODULE_DECLARE_DATA bucketeer_module = {
180 STANDARD20_MODULE_STUFF,
181 NULL,
182 NULL,
183 create_bucketeer_server_config,
184 NULL,
185 bucketeer_filter_cmds,
186 register_hooks