mod_firehose.c revision 231ca3b40df46af2a63d006ebde6b745f73c40b2
97a9a944b5887e91042b019776c41d5dd74557aferikabele/* Licensed to the Apache Software Foundation (ASF) under one or more
97a9a944b5887e91042b019776c41d5dd74557aferikabele * contributor license agreements. See the NOTICE file distributed with
97a9a944b5887e91042b019776c41d5dd74557aferikabele * this work for additional information regarding copyright ownership.
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * The ASF licenses this file to You under the Apache License, Version 2.0
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * (the "License"); you may not use this file except in compliance with
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * the License. You may obtain a copy of the License at
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 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.
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen * Originally written @ Covalent by Jim Jagielski
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Modified to support writing to non blocking pipes @ BBC by Graham Leggett
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Modifications (C) 2011 British Broadcasting Corporation
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd * A request and response sniffer for Apache v2.x. It logs
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * all filter data right before and after it goes out on the
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * wire (BUT right before SSL encoded or after SSL decoded).
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * It can produce a *huge* amount of data.
117c1f888a14e73cdd821dc6c23eb0411144a41cndtypedef enum proxy_enum
5a58787efeb02a1c3f06569d019ad81fd2efa06endtypedef struct firehose_conn_t
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *filename;
06ba4a61654b3763ad65f52283832ebf058fdf1cslivetypedef struct firehose_conf_t
06ba4a61654b3763ad65f52283832ebf058fdf1cslivetypedef struct firehose_ctx_t
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#define HEADER_LEN (sizeof(apr_uint64_t)*6 + APR_UUID_FORMATTED_LENGTH + 7)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#define HEADER_FMT "%" APR_UINT64_T_HEX_FMT " %" APR_UINT64_T_HEX_FMT " %c %s %" APR_UINT64_T_HEX_FMT CRLF
709e3a21ba73b8433462959cd56c773454b34441trawick * Add the terminating empty fragment to indicate end-of-connection.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive hdr_len = apr_snprintf(header, sizeof(header), HEADER_FMT,
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd (apr_uint64_t) 0, (apr_uint64_t) apr_time_now(), ctx->direction,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rv = apr_file_write_full(ctx->conn->file, header, hdr_len, &bytes);
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd /* ignore the error */
5a58787efeb02a1c3f06569d019ad81fd2efa06end else if (ctx->r) {
5a58787efeb02a1c3f06569d019ad81fd2efa06end "mod_firehose: could not write %" APR_UINT64_T_FMT " bytes to '%s' for '%c' connection '%s' and count '%0" APR_UINT64_T_HEX_FMT "', bytes dropped (further errors will be suppressed)",
5a58787efeb02a1c3f06569d019ad81fd2efa06end (apr_uint64_t)(hdr_len), ctx->conn->filename, ctx->conn->direction, ctx->uuid, ctx->count);
5a58787efeb02a1c3f06569d019ad81fd2efa06end "mod_firehose: could not write %" APR_UINT64_T_FMT " bytes to '%s' for '%c' connection '%s' and count '%0" APR_UINT64_T_HEX_FMT "', bytes dropped (further errors will be suppressed)",
5a58787efeb02a1c3f06569d019ad81fd2efa06end (apr_uint64_t)(hdr_len), ctx->conn->filename, ctx->conn->direction, ctx->uuid, ctx->count);
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Pump the bucket contents to the pipe.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Writes smaller than PIPE_BUF are guaranteed to be atomic when written to
5a58787efeb02a1c3f06569d019ad81fd2efa06end * pipes. As a result, we break the buckets into packets smaller than PIPE_BUF and
5a58787efeb02a1c3f06569d019ad81fd2efa06end * send each one in turn.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Each packet is marked with the UUID of the connection so that the process that
5a58787efeb02a1c3f06569d019ad81fd2efa06end * reassembles the packets can put the right packets in the right order.
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * Each packet is numbered with an incrementing counter. If a packet cannot be
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * written we drop the packet on the floor, and the counter will enable dropped
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * packets to be detected.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjungstatic apr_status_t pumpit(ap_filter_t *f, apr_bucket *b, firehose_ctx_t *ctx)
0d0ba3a410038e179b695446bb149cce6264e0abnd const char *buf;
727872d18412fc021f03969b8641810d8896820bhumbedooh while (nbytes > 0) {
0d0ba3a410038e179b695446bb149cce6264e0abnd apr_size_t body_len = nbytes < BODY_LEN ? nbytes : BODY_LEN;
5effc8b39fae5cd169d17f342bfc265705840014rbowen * Insert the chunk header, specifying the number of bytes in
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen * the chunk.
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd hdr_len = apr_snprintf(header, sizeof(header), HEADER_FMT,
else if (ctx->r) {
rv,
ctx->r,
"mod_firehose: could not write %" APR_UINT64_T_FMT " bytes to '%s' for '%c' connection '%s' and count '%0" APR_UINT64_T_HEX_FMT "', bytes dropped (further errors will be suppressed)",
(apr_uint64_t)(vec[0].iov_len + vec[1].iov_len + vec[2].iov_len), ctx->conn->filename, ctx->conn->direction, ctx->uuid, ctx->count);
rv,
ctx->c,
"mod_firehose: could not write %" APR_UINT64_T_FMT " bytes to '%s' for '%c' connection '%s' and count '%0" APR_UINT64_T_HEX_FMT "', bytes dropped (further errors will be suppressed)",
(apr_uint64_t)(vec[0].iov_len + vec[1].iov_len + vec[2].iov_len), ctx->conn->filename, ctx->conn->direction, ctx->uuid, ctx->count);
return rv;
apr_bucket *b;
return rv;
= APR_BUCKET_NEXT(b)) {
return rv;
return APR_SUCCESS;
apr_bucket *b;
return rv;
if (APR_BUCKET_IS_EOS(b)) {
return rv;
int set = 0;
ap_filter_t *f;
if (r->main) {
return DECLINED;
if (!set) {
f = f->next;
if (!set) {
f = f->next;
return OK;
conn++;
ctx->c = c;
conn++;
return OK;
void *data;
if (!data) {
return OK;
conn++;
s = s->next;
return OK;
return ptr;
void *overridesv)
return cconf;
*ptr =
if (arg2) {
#ifdef APR_FOPEN_NONBLOCK
return NULL;
| NOT_IN_LIMIT);
return err;
| NOT_IN_LIMIT);
return err;
| NOT_IN_LIMIT);
return err;
| NOT_IN_LIMIT);
return err;
| NOT_IN_LIMIT);
return err;
| NOT_IN_LIMIT);
return err;
{ NULL }
NULL,
NULL,