bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / test / mod_bucketeer.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * mod_bucketeer.c: split buckets whenever we find a control-char
19  *
20  * Written by Ian Holsman
21  *
22  */
23
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"
33
34 static const char bucketeerFilterName[] = "BUCKETEER";
35 module AP_MODULE_DECLARE_DATA bucketeer_module;
36
37 typedef struct bucketeer_filter_config_t
38 {
39     char bucketdelimiter;
40     char passdelimiter;
41     char flushdelimiter;
42 } bucketeer_filter_config_t;
43
44
45 static void *create_bucketeer_server_config(apr_pool_t *p, server_rec *s)
46 {
47     bucketeer_filter_config_t *c = apr_pcalloc(p, sizeof *c);
48
49     c->bucketdelimiter = 0x02; /* ^B */
50     c->passdelimiter = 0x10;   /* ^P */
51     c->flushdelimiter = 0x06;  /* ^F */
52
53     return c;
54 }
55
56 typedef struct bucketeer_ctx_t
57 {
58     apr_bucket_brigade *bb;
59 } bucketeer_ctx_t;
60
61 static apr_status_t bucketeer_out_filter(ap_filter_t *f,
62                                          apr_bucket_brigade *bb)
63 {
64     apr_bucket *e;
65     request_rec *r = f->r;
66     bucketeer_ctx_t *ctx = f->ctx;
67     bucketeer_filter_config_t *c;
68
69     c = ap_get_module_config(r->server->module_config, &bucketeer_module);
70
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);
76         }
77
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");
82     }
83
84     APR_BRIGADE_FOREACH(e, bb) {
85         const char *data;
86         apr_size_t len, i, lastpos;
87
88         if (APR_BUCKET_IS_EOS(e)) {
89             APR_BUCKET_REMOVE(e);
90             APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
91
92             /* Okay, we've seen the EOS.
93              * Time to pass it along down the chain.
94              */
95             return ap_pass_brigade(f->next, ctx->bb);
96         }
97
98         if (APR_BUCKET_IS_FLUSH(e)) {     
99             /*
100              * Ignore flush buckets for the moment.. 
101              * we decide what to stream
102              */
103             continue;
104         }
105
106         if (APR_BUCKET_IS_METADATA(e)) {
107             /* metadata bucket */
108             apr_bucket *cpy;
109             apr_bucket_copy(e, &cpy);
110             APR_BRIGADE_INSERT_TAIL(ctx->bb, cpy);
111             continue;
112         }
113
114         /* read */
115         apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
116
117         if (len > 0) {
118             lastpos = 0;
119             for (i = 0; i < len; i++) {
120                 if (data[i] == c->flushdelimiter ||
121                     data[i] == c->bucketdelimiter ||
122                     data[i] == c->passdelimiter) {
123                     apr_bucket *p;
124                     if (i - lastpos > 0) {
125                         p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
126                                                                &data[lastpos],
127                                                                i - lastpos),
128                                                     i - lastpos,
129                                                     f->r->pool,
130                                                     f->c->bucket_alloc);
131                         APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
132                     }
133                     lastpos = i + 1;
134                     if (data[i] == c->flushdelimiter) {
135                         p = apr_bucket_flush_create(f->c->bucket_alloc);
136                         APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
137                     }
138                     if (data[i] == c->flushdelimiter ||
139                         data[i] == c->passdelimiter) {
140                         ap_pass_brigade(f->next, ctx->bb);
141                        /* apr_brigade_cleanup(ctx->bb);*/
142                     }
143                 }                       
144             }
145             /* XXX: really should append this to the next 'real' bucket */
146             if (lastpos < i) {
147                 apr_bucket *p;
148                 p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
149                                                        &data[lastpos],
150                                                        i - lastpos),
151                                            i - lastpos,
152                                            f->r->pool,
153                                            f->c->bucket_alloc);
154                 lastpos = i;
155                 APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
156             }
157         }     
158     }
159
160     return APR_SUCCESS;
161 }
162
163 static void register_hooks(apr_pool_t * p)
164 {
165     ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
166                               NULL, AP_FTYPE_RESOURCE-1);
167 }
168
169 static const command_rec bucketeer_filter_cmds[] = {
170     {NULL}
171 };
172
173 module AP_MODULE_DECLARE_DATA bucketeer_module = {
174     STANDARD20_MODULE_STUFF,
175     NULL,
176     NULL,
177     create_bucketeer_server_config,
178     NULL,
179     bucketeer_filter_cmds,
180     register_hooks
181 };