View | Details | Raw Unified | Return to bug 57045
Collapse All | Expand All

(-)a/mod_dumpio.c (-250 lines)
Lines 1-250 Link Here
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
 * Originally written @ Covalent by Jim Jagielski
19
 */
20
21
/*
22
 * mod_dumpio.c:
23
 *  Think of this as a filter sniffer for Apache 2.x. It logs
24
 *  all filter data right before and after it goes out on the
25
 *  wire (BUT right before SSL encoded or after SSL decoded).
26
 *  It can produce a *huge* amount of data.
27
 */
28
29
30
#include "httpd.h"
31
#include "http_connection.h"
32
#include "http_config.h"
33
#include "http_core.h"
34
#include "http_log.h"
35
#include "apr_strings.h"
36
37
module AP_MODULE_DECLARE_DATA dumpio_module ;
38
39
typedef struct dumpio_conf_t {
40
    int enable_input;
41
    int enable_output;
42
} dumpio_conf_t;
43
44
/* consider up to 80 additional characters, and factor the longest
45
 * line length of all \xNN sequences; log_error cannot record more
46
 * than MAX_STRING_LEN characters.
47
 */
48
#define dumpio_MAX_STRING_LEN (MAX_STRING_LEN / 4 - 80)
49
50
/*
51
 * Workhorse function: simply log to the current error_log
52
 * info about the data in the bucket as well as the data itself
53
 */
54
static void dumpit(ap_filter_t *f, apr_bucket *b, dumpio_conf_t *ptr)
55
{
56
    conn_rec *c = f->c;
57
58
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
59
                  "mod_dumpio:  %s (%s-%s): %" APR_SIZE_T_FMT " bytes",
60
                  f->frec->name,
61
                  (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
62
                  b->type->name,
63
                  b->length) ;
64
65
    if (!(APR_BUCKET_IS_METADATA(b)))
66
    {
67
#if APR_CHARSET_EBCDIC
68
        char xlatebuf[dumpio_MAX_STRING_LEN + 1];
69
#endif
70
        const char *buf;
71
        apr_size_t nbytes;
72
        apr_status_t rv = apr_bucket_read(b, &buf, &nbytes, APR_BLOCK_READ);
73
74
        if (rv == APR_SUCCESS)
75
        {
76
            while (nbytes)
77
            {
78
                apr_size_t logbytes = nbytes;
79
                if (logbytes > dumpio_MAX_STRING_LEN)
80
                    logbytes = dumpio_MAX_STRING_LEN;
81
                nbytes -= logbytes;
82
83
#if APR_CHARSET_EBCDIC
84
                memcpy(xlatebuf, buf, logbytes);
85
                ap_xlate_proto_from_ascii(xlatebuf, logbytes);
86
                xlatebuf[logbytes] = '\0';
87
                ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
88
                              "mod_dumpio:  %s (%s-%s): %s", f->frec->name,
89
                              (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
90
                              b->type->name, xlatebuf);
91
#else
92
                /* XXX: Seriously flawed; we do not pay attention to embedded
93
                 * \0's in the request body, these should be escaped; however,
94
                 * the logging function already performs a significant amount
95
                 * of escaping, and so any escaping would be double-escaped.
96
                 * The coding solution is to throw away the current logic
97
                 * within ap_log_error, and introduce new vformatter %-escapes
98
                 * for escaping text, and for binary text (fixed len strings).
99
                 */
100
                ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
101
                              "mod_dumpio:  %s (%s-%s): %.*s", f->frec->name,
102
                              (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
103
                              b->type->name, (int)logbytes, buf);
104
#endif
105
                buf += logbytes;
106
            }
107
        }
108
        else {
109
            ap_log_cerror(APLOG_MARK, APLOG_TRACE7, rv, c,
110
                          "mod_dumpio:  %s (%s-%s): %s", f->frec->name,
111
                          (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
112
                          b->type->name, "error reading data");
113
        }
114
    }
115
}
116
117
#define whichmode( mode ) \
118
 ( (( mode ) == AP_MODE_READBYTES) ? "readbytes" : \
119
   (( mode ) == AP_MODE_GETLINE) ? "getline" : \
120
   (( mode ) == AP_MODE_EATCRLF) ? "eatcrlf" : \
121
   (( mode ) == AP_MODE_SPECULATIVE) ? "speculative" : \
122
   (( mode ) == AP_MODE_EXHAUSTIVE) ? "exhaustive" : \
123
   (( mode ) == AP_MODE_INIT) ? "init" : "unknown" \
124
 )
125
126
static int dumpio_input_filter (ap_filter_t *f, apr_bucket_brigade *bb,
127
    ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
128
{
129
130
    apr_bucket *b;
131
    apr_status_t ret;
132
    conn_rec *c = f->c;
133
    dumpio_conf_t *ptr = f->ctx;
134
135
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
136
                  "mod_dumpio: %s [%s-%s] %" APR_OFF_T_FMT " readbytes",
137
                  f->frec->name,
138
                  whichmode(mode),
139
                  ((block) == APR_BLOCK_READ) ? "blocking" : "nonblocking",
140
                  readbytes);
141
142
    ret = ap_get_brigade(f->next, bb, mode, block, readbytes);
143
144
    if (ret == APR_SUCCESS) {
145
        for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
146
          dumpit(f, b, ptr);
147
        }
148
    }
149
    else {
150
        ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
151
                      "mod_dumpio: %s - %d", f->frec->name, ret) ;
152
        return ret;
153
    }
154
155
    return APR_SUCCESS ;
156
}
157
158
static int dumpio_output_filter (ap_filter_t *f, apr_bucket_brigade *bb)
159
{
160
    apr_bucket *b;
161
    conn_rec *c = f->c;
162
    dumpio_conf_t *ptr = f->ctx;
163
164
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c, "mod_dumpio: %s", f->frec->name);
165
166
    for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
167
        /*
168
         * If we ever see an EOS, make sure to FLUSH.
169
         */
170
        if (APR_BUCKET_IS_EOS(b)) {
171
            apr_bucket *flush = apr_bucket_flush_create(f->c->bucket_alloc);
172
            APR_BUCKET_INSERT_BEFORE(b, flush);
173
        }
174
        dumpit(f, b, ptr);
175
    }
176
177
    return ap_pass_brigade(f->next, bb) ;
178
}
179
180
static int dumpio_pre_conn(conn_rec *c, void *csd)
181
{
182
    dumpio_conf_t *ptr;
183
184
    ptr = (dumpio_conf_t *) ap_get_module_config(c->base_server->module_config,
185
                                                 &dumpio_module);
186
187
    if (ptr->enable_input)
188
        ap_add_input_filter("DUMPIO_IN", ptr, NULL, c);
189
    if (ptr->enable_output)
190
        ap_add_output_filter("DUMPIO_OUT", ptr, NULL, c);
191
    return OK;
192
}
193
194
static void dumpio_register_hooks(apr_pool_t *p)
195
{
196
/*
197
 * We know that SSL is CONNECTION + 5
198
 */
199
  ap_register_output_filter("DUMPIO_OUT", dumpio_output_filter,
200
        NULL, AP_FTYPE_CONNECTION + 3) ;
201
202
  ap_register_input_filter("DUMPIO_IN", dumpio_input_filter,
203
        NULL, AP_FTYPE_CONNECTION + 3) ;
204
205
  ap_hook_pre_connection(dumpio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
206
}
207
208
static void *dumpio_create_sconfig(apr_pool_t *p, server_rec *s)
209
{
210
    dumpio_conf_t *ptr = apr_pcalloc(p, sizeof *ptr);
211
    ptr->enable_input = 0;
212
    ptr->enable_output = 0;
213
    return ptr;
214
}
215
216
static const char *dumpio_enable_input(cmd_parms *cmd, void *dummy, int arg)
217
{
218
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
219
                                              &dumpio_module);
220
221
    ptr->enable_input = arg;
222
    return NULL;
223
}
224
225
static const char *dumpio_enable_output(cmd_parms *cmd, void *dummy, int arg)
226
{
227
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
228
                                              &dumpio_module);
229
230
    ptr->enable_output = arg;
231
    return NULL;
232
}
233
234
static const command_rec dumpio_cmds[] = {
235
    AP_INIT_FLAG("DumpIOInput", dumpio_enable_input, NULL,
236
                 RSRC_CONF, "Enable I/O Dump on Input Data"),
237
    AP_INIT_FLAG("DumpIOOutput", dumpio_enable_output, NULL,
238
                 RSRC_CONF, "Enable I/O Dump on Output Data"),
239
    { NULL }
240
};
241
242
AP_DECLARE_MODULE(dumpio) = {
243
        STANDARD20_MODULE_STUFF,
244
        NULL,                   /* create per-dir    config structures */
245
        NULL,                   /* merge  per-dir    config structures */
246
        dumpio_create_sconfig,  /* create per-server config structures */
247
        NULL,                   /* merge  per-server config structures */
248
        dumpio_cmds,            /* table of config file commands       */
249
        dumpio_register_hooks   /* register hooks                      */
250
};
(-)a/modules/debugging/mod_dumpio.c (-119 / +203 lines)
Lines 16-117 Link Here
16
16
17
/*
17
/*
18
 * Originally written @ Covalent by Jim Jagielski
18
 * Originally written @ Covalent by Jim Jagielski
19
 *
20
 * Modified October 2015 by Kurtis Rader (krader@skepticism.us) to correctly
21
 * handle null (zero) bytes so they appear in the logged output. Fixing
22
 * PR57045: https://bz.apache.org/bugzilla/show_bug.cgi?id=57045
19
 */
23
 */
20
24
21
/*
25
/*
22
 * mod_dumpio.c:
26
 * mod_dumpio.c:
23
 *  Think of this as a filter sniffer for Apache 2.x. It logs
27
 *  Think of this as a filter sniffer for Apache 2.x. It logs all filter data
24
 *  all filter data right before and after it goes out on the
28
 *  right before and after it goes out on the wire (BUT right before SSL
25
 *  wire (BUT right before SSL encoded or after SSL decoded).
29
 *  encoded or after SSL decoded). It can produce a *huge* amount of data in
26
 *  It can produce a *huge* amount of data.
30
 *  the error log.
27
 */
31
 */
28
32
33
// TODO: Switch to the ap_log_data family of functions in a future revision.
34
// Preferably one where we can justify breaking backward compatibility of our
35
// output. Even better would be to fork this code and create a new mod_dumpio2
36
// module that uses the new logging functions.
29
37
30
#include "httpd.h"
38
#include "httpd.h"
31
#include "http_connection.h"
39
#include "http_connection.h"
40
#include "http_protocol.h"
32
#include "http_config.h"
41
#include "http_config.h"
33
#include "http_core.h"
42
#include "http_core.h"
34
#include "http_log.h"
43
#include "http_log.h"
35
#include "apr_strings.h"
44
#include "apr_strings.h"
45
#include "apr_thread_proc.h"
36
46
37
module AP_MODULE_DECLARE_DATA dumpio_module ;
47
module AP_MODULE_DECLARE_DATA dumpio_module;
38
48
39
typedef struct dumpio_conf_t {
49
typedef struct dumpio_conf_t {
40
    int enable_input;
50
    int enable_input;
41
    int enable_output;
51
    int enable_output;
42
} dumpio_conf_t;
52
} dumpio_conf_t;
43
53
44
/* consider up to 80 additional characters, and factor the longest
54
// Function ap_log_cerror cannot record more than MAX_STRING_LEN characters.
45
 * line length of all \xNN sequences; log_error cannot record more
55
// Excluding the IP address and port number the message prefix is ~130 chars
46
 * than MAX_STRING_LEN characters.
56
// long. The longest IPv6 address:port pair is 46 chars (IPv4 is 21 chars). Add
47
 */
57
// a fudge factor of 100 characters to help ensure we don't attempt to log more
48
#define dumpio_MAX_STRING_LEN (MAX_STRING_LEN / 4 - 80)
58
// data than can be written in case the length of the message prefix is longer
59
// than we expect. Note that we take into account which bytes are printable and
60
// those that might be expanded to a hex encoded sequence (\xNN) when
61
// determining if we've exceeded the following limit.
62
#define DUMPIO_MAX_DATA_LEN (MAX_STRING_LEN - 130 - 46 - 100)
63
64
// The dumpbuf* functions are the workhorses of this module. Log the data in
65
// the bucket to the current error log. It is needed to correctly handle null
66
// (i.e., zero) bytes in the data we want to log. It allows us to encode 0x00
67
// and 0xff bytes into sequences of 0xff 0x01 (\xff\x01) and 0xff 0x02
68
// (\xff\x02) respectively. This is necessary because the ap_log_cerror
69
// function and friends stop processing data (i.e., logging it) when a zero
70
// byte is seen because they only handle null terminated strings.
71
typedef struct {
72
    unsigned char buf[DUMPIO_MAX_DATA_LEN];
73
    int idx;
74
    int space_left;
75
} encoded_data_t;
76
77
// Initialize the data structures so we can begin logging data we receive.
78
static void dumpbuf_init(encoded_data_t *encoded_data)
79
{
80
    encoded_data->space_left = DUMPIO_MAX_DATA_LEN;
81
    encoded_data->idx = 0;
82
}
49
83
50
/*
84
// Log any data we've buffered since the most recent call to dumpbuf.
51
 * Workhorse function: simply log to the current error_log
85
static void dumpbuf_end(encoded_data_t *encoded_data, const ap_filter_t *f,
52
 * info about the data in the bucket as well as the data itself
86
                        const char *bucket_type)
53
 */
54
static void dumpit(ap_filter_t *f, apr_bucket *b, dumpio_conf_t *ptr)
55
{
87
{
56
    conn_rec *c = f->c;
88
    if (encoded_data->idx) {
89
        ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c,
90
                      "mod_dumpio:  %s (%s-%s): %.*s", f->frec->name,
91
                      "data", bucket_type, encoded_data->idx,
92
                      encoded_data->buf);
93
    }
94
}
57
95
58
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
96
// Dump the buffer to the error log in a form that allows reconstructing the
59
                  "mod_dumpio:  %s (%s-%s): %" APR_SIZE_T_FMT " bytes",
97
// original data.
60
                  f->frec->name,
98
static void dumpbuf(encoded_data_t *encoded_data, ap_filter_t *f,
61
                  (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
99
                    const char *bucket_type, unsigned char *input_buf,
62
                  b->type->name,
100
                    apr_size_t nbytes)
63
                  b->length) ;
101
{
64
102
    for (unsigned char *c = input_buf; c < input_buf + nbytes; ++c) {
65
    if (!(APR_BUCKET_IS_METADATA(b)))
103
        if (encoded_data->space_left < 8) {
66
    {
104
            ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c,
67
#if APR_CHARSET_EBCDIC
105
                          "mod_dumpio:  %s (%s-%s): %.*s", f->frec->name,
68
        char xlatebuf[dumpio_MAX_STRING_LEN + 1];
106
                          "data", bucket_type, encoded_data->idx,
69
#endif
107
                          encoded_data->buf);
70
        const char *buf;
108
            dumpbuf_init(encoded_data);
71
        apr_size_t nbytes;
109
        }
72
        apr_status_t rv = apr_bucket_read(b, &buf, &nbytes, APR_BLOCK_READ);
110
73
111
        // We could use isprint() but we don't want the overhead. Also, on OS X
74
        if (rv == APR_SUCCESS)
112
        // isprint() appears to treat non ASCII printable values as printable.
75
        {
113
        // This probably has something to do with Unicode and is another reason
76
            while (nbytes)
114
        // to not use isprint().
77
            {
115
        if (*c >= 0x20 && *c <= 0x7e) { // this range needs one char in the log
78
                apr_size_t logbytes = nbytes;
116
            encoded_data->buf[encoded_data->idx++] = *c;
79
                if (logbytes > dumpio_MAX_STRING_LEN)
117
            encoded_data->space_left -= 1;
80
                    logbytes = dumpio_MAX_STRING_LEN;
118
        }
81
                nbytes -= logbytes;
119
        else if (*c == 0) {
82
120
            encoded_data->buf[encoded_data->idx++] = 0xff;
83
#if APR_CHARSET_EBCDIC
121
            encoded_data->buf[encoded_data->idx++] = 0x01;
84
                memcpy(xlatebuf, buf, logbytes);
122
            encoded_data->space_left -= 8;
85
                ap_xlate_proto_from_ascii(xlatebuf, logbytes);
123
        }
86
                xlatebuf[logbytes] = '\0';
124
        else if (*c == 0xff) {
87
                ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
125
            encoded_data->buf[encoded_data->idx++] = 0xff;
88
                              "mod_dumpio:  %s (%s-%s): %s", f->frec->name,
126
            encoded_data->buf[encoded_data->idx++] = 0x02;
89
                              (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
127
            encoded_data->space_left -= 8;
90
                              b->type->name, xlatebuf);
91
#else
92
                /* XXX: Seriously flawed; we do not pay attention to embedded
93
                 * \0's in the request body, these should be escaped; however,
94
                 * the logging function already performs a significant amount
95
                 * of escaping, and so any escaping would be double-escaped.
96
                 * The coding solution is to throw away the current logic
97
                 * within ap_log_error, and introduce new vformatter %-escapes
98
                 * for escaping text, and for binary text (fixed len strings).
99
                 */
100
                ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
101
                              "mod_dumpio:  %s (%s-%s): %.*s", f->frec->name,
102
                              (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
103
                              b->type->name, (int)logbytes, buf);
104
#endif
105
                buf += logbytes;
106
            }
107
        }
128
        }
108
        else {
129
        else {
109
            ap_log_cerror(APLOG_MARK, APLOG_TRACE7, rv, c,
130
            // It isn't worth it to special-case the few control chars, such
110
                          "mod_dumpio:  %s (%s-%s): %s", f->frec->name,
131
            // as \t, that get encoded into two characters. Assume they all
111
                          (APR_BUCKET_IS_METADATA(b)) ? "metadata" : "data",
132
            // get encoded into a four char \xNN sequence.
112
                          b->type->name, "error reading data");
133
            encoded_data->buf[encoded_data->idx++] = *c;
134
            encoded_data->space_left -= 4;
135
        }
136
    }
137
}
138
139
// Log info about the data in the bucket as well as the data itself to the
140
// current error log.
141
static void dumpit(encoded_data_t *encoded_data, ap_filter_t *f, apr_bucket *b,
142
                   dumpio_conf_t *ptr)
143
{
144
    int is_metadata = APR_BUCKET_IS_METADATA(b);
145
146
    // I've commented this out because in the normal course of events it
147
    // doesn't tell us anything we need to know and takes measurable time to
148
    // execute and wastes space in the log file. In my testing adding this log
149
    // message increases the log file size by 2%. Uncomment it if you're
150
    // debugging this module.
151
    //
152
    // ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c,
153
    //               "mod_dumpio:  %s (%s-%s): %" APR_SIZE_T_FMT " bytes",
154
    //               f->frec->name, is_metadata ? "metadata" : "data",
155
    //               b->type->name, b->length);
156
    if (is_metadata) {
157
        return;
158
    }
159
160
    apr_size_t nbytes;
161
    unsigned char *input_buf;
162
    apr_status_t rv = apr_bucket_read(b, (const char **)&input_buf, &nbytes,
163
        APR_BLOCK_READ);
164
    if (rv != APR_SUCCESS) {
165
        ap_log_cerror(APLOG_MARK, APLOG_TRACE7, rv, f->c,
166
                      "mod_dumpio:  %s (%s-%s): %s", f->frec->name,
167
                      "data", b->type->name, "error reading data");
168
        return;
169
    }
170
171
#if !APR_CHARSET_EBCDIC
172
    // The common case: ASCII charset.
173
    dumpbuf(encoded_data, f, b->type->name, input_buf, nbytes);
174
#else
175
    // The less common case: EBCDIC charset. This obviously screws up any
176
    // binary data in the buffer such as a zip archive in a POST request. But
177
    // people running on an IBM mainframe probably don't care since the
178
    // original data is almost certainly unusable in their environment. It's
179
    // better that we make the incoming and ougoing ASCII text easily readable
180
    // in the error log on systems using EBCDIC.
181
    unsigned char xlatebuf[MAX_STRING_LEN];
182
    while (nbytes) {
183
        apr_size_t logbytes = nbytes;
184
        if (logbytes > MAX_STRING_LEN) {
185
            logbytes = MAX_STRING_LEN;
113
        }
186
        }
187
        memcpy(xlatebuf, input_buf, logbytes);
188
        ap_xlate_proto_from_ascii(xlatebuf, logbytes);
189
        dumpbuf(encoded_data, f, b->type->name, xlatebuf, logbytes);
190
        nbytes -= logbytes
114
    }
191
    }
192
#endif
115
}
193
}
116
194
117
#define whichmode( mode ) \
195
#define whichmode( mode ) \
Lines 123-208 static void dumpit(ap_filter_t *f, apr_bucket *b, dumpio_conf_t *ptr) Link Here
123
   (( mode ) == AP_MODE_INIT) ? "init" : "unknown" \
201
   (( mode ) == AP_MODE_INIT) ? "init" : "unknown" \
124
 )
202
 )
125
203
126
static int dumpio_input_filter (ap_filter_t *f, apr_bucket_brigade *bb,
204
static int dumpio_input_filter(
127
    ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
205
        ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode,
206
        apr_read_type_e block, apr_off_t readbytes)
128
{
207
{
129
130
    apr_bucket *b;
208
    apr_bucket *b;
131
    apr_status_t ret;
209
    apr_status_t ret;
132
    conn_rec *c = f->c;
133
    dumpio_conf_t *ptr = f->ctx;
210
    dumpio_conf_t *ptr = f->ctx;
134
211
135
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
212
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c,
136
                  "mod_dumpio: %s [%s-%s] %" APR_OFF_T_FMT " readbytes",
213
                  "mod_dumpio: %s [%s-%s] %" APR_OFF_T_FMT " readbytes",
137
                  f->frec->name,
214
                  f->frec->name, whichmode(mode),
138
                  whichmode(mode),
215
                  (block == APR_BLOCK_READ) ? "blocking" : "nonblocking",
139
                  ((block) == APR_BLOCK_READ) ? "blocking" : "nonblocking",
140
                  readbytes);
216
                  readbytes);
141
217
142
    ret = ap_get_brigade(f->next, bb, mode, block, readbytes);
218
    ret = ap_get_brigade(f->next, bb, mode, block, readbytes);
143
219
    if (ret != APR_SUCCESS) {
144
    if (ret == APR_SUCCESS) {
220
        ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c,
145
        for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
221
                      "mod_dumpio: %s - %d", f->frec->name, ret);
146
          dumpit(f, b, ptr);
147
        }
148
    }
149
    else {
150
        ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
151
                      "mod_dumpio: %s - %d", f->frec->name, ret) ;
152
        return ret;
222
        return ret;
153
    }
223
    }
154
224
155
    return APR_SUCCESS ;
225
    encoded_data_t encoded_data;
226
    dumpbuf_init(&encoded_data);
227
    apr_bucket *first_b = APR_BRIGADE_FIRST(bb);
228
    apr_bucket *sentinel_b = APR_BRIGADE_SENTINEL(bb);
229
    for (b = first_b; b != sentinel_b; b = APR_BUCKET_NEXT(b)) {
230
        dumpit(&encoded_data, f, b, ptr);
231
    }
232
    dumpbuf_end(&encoded_data, f, first_b->type->name);
233
    return APR_SUCCESS;
156
}
234
}
157
235
158
static int dumpio_output_filter (ap_filter_t *f, apr_bucket_brigade *bb)
236
static int dumpio_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
159
{
237
{
160
    apr_bucket *b;
238
    apr_bucket *b;
161
    conn_rec *c = f->c;
162
    dumpio_conf_t *ptr = f->ctx;
239
    dumpio_conf_t *ptr = f->ctx;
163
240
164
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c, "mod_dumpio: %s", f->frec->name);
241
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, f->c, "mod_dumpio: %s",
242
                  f->frec->name);
165
243
166
    for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
244
    encoded_data_t encoded_data;
167
        /*
245
    dumpbuf_init(&encoded_data);
168
         * If we ever see an EOS, make sure to FLUSH.
246
    apr_bucket *first_b = APR_BRIGADE_FIRST(bb);
169
         */
247
    apr_bucket *sentinel_b = APR_BRIGADE_SENTINEL(bb);
170
        if (APR_BUCKET_IS_EOS(b)) {
248
    for (b = first_b; b != sentinel_b; b = APR_BUCKET_NEXT(b)) {
249
        if (APR_BUCKET_IS_EOS(b)) { // if we ever see an EOS, make sure to FLUSH
171
            apr_bucket *flush = apr_bucket_flush_create(f->c->bucket_alloc);
250
            apr_bucket *flush = apr_bucket_flush_create(f->c->bucket_alloc);
172
            APR_BUCKET_INSERT_BEFORE(b, flush);
251
            APR_BUCKET_INSERT_BEFORE(b, flush);
173
        }
252
        }
174
        dumpit(f, b, ptr);
253
        dumpit(&encoded_data, f, b, ptr);
175
    }
254
    }
255
    dumpbuf_end(&encoded_data, f, first_b->type->name);
176
256
177
    return ap_pass_brigade(f->next, bb) ;
257
    return ap_pass_brigade(f->next, bb);
178
}
258
}
179
259
180
static int dumpio_pre_conn(conn_rec *c, void *csd)
260
static int dumpio_pre_conn(conn_rec *c, void *csd)
181
{
261
{
182
    dumpio_conf_t *ptr;
262
    dumpio_conf_t *ptr = (dumpio_conf_t *)ap_get_module_config(
183
263
            c->base_server->module_config, &dumpio_module);
184
    ptr = (dumpio_conf_t *) ap_get_module_config(c->base_server->module_config,
185
                                                 &dumpio_module);
186
264
187
    if (ptr->enable_input)
265
    if (ptr->enable_input)
188
        ap_add_input_filter("DUMPIO_IN", ptr, NULL, c);
266
        ap_add_input_filter("DUMPIO_IN", ptr, NULL, c);
189
    if (ptr->enable_output)
267
    if (ptr->enable_output)
190
        ap_add_output_filter("DUMPIO_OUT", ptr, NULL, c);
268
        ap_add_output_filter("DUMPIO_OUT", ptr, NULL, c);
269
191
    return OK;
270
    return OK;
192
}
271
}
193
272
194
static void dumpio_register_hooks(apr_pool_t *p)
273
static void pre_read_request(request_rec *r, conn_rec *c)
195
{
274
{
196
/*
275
    ap_log_cerror(APLOG_MARK, APLOG_TRACE7, 0, c,
197
 * We know that SSL is CONNECTION + 5
276
                  "mod_dumpio: new request");
198
 */
277
}
199
  ap_register_output_filter("DUMPIO_OUT", dumpio_output_filter,
200
        NULL, AP_FTYPE_CONNECTION + 3) ;
201
202
  ap_register_input_filter("DUMPIO_IN", dumpio_input_filter,
203
        NULL, AP_FTYPE_CONNECTION + 3) ;
204
278
205
  ap_hook_pre_connection(dumpio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
279
static void dumpio_register_hooks(apr_pool_t *p)
280
{
281
    // We know that the SSL code inserts itself at AP_FTYPE_CONNECTION + 5 and
282
    // AP_FTYPE_CONNECTION + 4 (see the ssl_io_filter_register() function in
283
    // modules/ssl/ssl_engine_io.c). We want to be inserted just ahead of that
284
    // module so we use "+ 3" to ensure we're called just before the SSL filter
285
    // but hopefully after anything else that might alter the data.
286
    ap_register_output_filter("DUMPIO_OUT", dumpio_output_filter,
287
        NULL, AP_FTYPE_CONNECTION + 3);
288
    ap_register_input_filter("DUMPIO_IN", dumpio_input_filter,
289
        NULL, AP_FTYPE_CONNECTION + 3);
290
    ap_hook_pre_connection(dumpio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
291
    ap_hook_pre_read_request(pre_read_request, NULL, NULL, APR_HOOK_MIDDLE);
206
}
292
}
207
293
208
static void *dumpio_create_sconfig(apr_pool_t *p, server_rec *s)
294
static void *dumpio_create_sconfig(apr_pool_t *p, server_rec *s)
Lines 217-223 static const char *dumpio_enable_input(cmd_parms *cmd, void *dummy, int arg) Link Here
217
{
303
{
218
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
304
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
219
                                              &dumpio_module);
305
                                              &dumpio_module);
220
221
    ptr->enable_input = arg;
306
    ptr->enable_input = arg;
222
    return NULL;
307
    return NULL;
223
}
308
}
Lines 226-232 static const char *dumpio_enable_output(cmd_parms *cmd, void *dummy, int arg) Link Here
226
{
311
{
227
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
312
    dumpio_conf_t *ptr = ap_get_module_config(cmd->server->module_config,
228
                                              &dumpio_module);
313
                                              &dumpio_module);
229
230
    ptr->enable_output = arg;
314
    ptr->enable_output = arg;
231
    return NULL;
315
    return NULL;
232
}
316
}
Lines 241-250 static const command_rec dumpio_cmds[] = { Link Here
241
325
242
AP_DECLARE_MODULE(dumpio) = {
326
AP_DECLARE_MODULE(dumpio) = {
243
        STANDARD20_MODULE_STUFF,
327
        STANDARD20_MODULE_STUFF,
244
        NULL,                   /* create per-dir    config structures */
328
        NULL,                   // create per-dir    config structures
245
        NULL,                   /* merge  per-dir    config structures */
329
        NULL,                   // merge  per-dir    config structures
246
        dumpio_create_sconfig,  /* create per-server config structures */
330
        dumpio_create_sconfig,  // create per-server config structures
247
        NULL,                   /* merge  per-server config structures */
331
        NULL,                   // merge  per-server config structures
248
        dumpio_cmds,            /* table of config file commands       */
332
        dumpio_cmds,            // table of config file commands
249
        dumpio_register_hooks   /* register hooks                      */
333
        dumpio_register_hooks   // register hooks
250
};
334
};

Return to bug 57045