~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/debug/mod_bucketeer.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
    for (e = APR_BRIGADE_FIRST(bb);
 
85
         e != APR_BRIGADE_SENTINEL(bb);
 
86
         e = APR_BUCKET_NEXT(e))
 
87
    {
 
88
        const char *data;
 
89
        apr_size_t len, i, lastpos;
 
90
 
 
91
        if (APR_BUCKET_IS_EOS(e)) {
 
92
            APR_BUCKET_REMOVE(e);
 
93
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
 
94
 
 
95
            /* Okay, we've seen the EOS.
 
96
             * Time to pass it along down the chain.
 
97
             */
 
98
            return ap_pass_brigade(f->next, ctx->bb);
 
99
        }
 
100
 
 
101
        if (APR_BUCKET_IS_FLUSH(e)) {
 
102
            /*
 
103
             * Ignore flush buckets for the moment..
 
104
             * we decide what to stream
 
105
             */
 
106
            continue;
 
107
        }
 
108
 
 
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;
 
115
        }
 
116
 
 
117
        /* read */
 
118
        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
 
119
 
 
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);
 
135
                    }
 
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);
 
140
                    }
 
141
                    if (data[i] == c->flushdelimiter ||
 
142
                        data[i] == c->passdelimiter) {
 
143
                        ap_pass_brigade(f->next, ctx->bb);
 
144
                       /* apr_brigade_cleanup(ctx->bb);*/
 
145
                    }
 
146
                }
 
147
            }
 
148
            /* XXX: really should append this to the next 'real' bucket */
 
149
            if (lastpos < i) {
 
150
                apr_bucket *p;
 
151
                p = apr_bucket_pool_create(apr_pmemdup(f->r->pool,
 
152
                                                       &data[lastpos],
 
153
                                                       i - lastpos),
 
154
                                           i - lastpos,
 
155
                                           f->r->pool,
 
156
                                           f->c->bucket_alloc);
 
157
                lastpos = i;
 
158
                APR_BRIGADE_INSERT_TAIL(ctx->bb, p);
 
159
            }
 
160
        }
 
161
    }
 
162
 
 
163
    return APR_SUCCESS;
 
164
}
 
165
 
 
166
static void register_hooks(apr_pool_t * p)
 
167
{
 
168
    ap_register_output_filter(bucketeerFilterName, bucketeer_out_filter,
 
169
                              NULL, AP_FTYPE_RESOURCE-1);
 
170
}
 
171
 
 
172
static const command_rec bucketeer_filter_cmds[] = {
 
173
    {NULL}
 
174
};
 
175
 
 
176
module AP_MODULE_DECLARE_DATA bucketeer_module = {
 
177
    STANDARD20_MODULE_STUFF,
 
178
    NULL,
 
179
    NULL,
 
180
    create_bucketeer_server_config,
 
181
    NULL,
 
182
    bucketeer_filter_cmds,
 
183
    register_hooks
 
184
};