I'm aware that some people might not like this due to the fact that it's inserting yet another default filter, but here it is, just for completeness.
Bojan
diff -u --recursive --new-file httpd-2.0-vanilla/include/ap_mmn.h httpd-2.0/include/ap_mmn.h --- httpd-2.0-vanilla/include/ap_mmn.h Wed Sep 4 14:12:20 2002 +++ httpd-2.0/include/ap_mmn.h Mon Oct 14 11:47:46 2002 @@ -111,12 +111,13 @@ * 20020625 (2.0.40-dev) Changed conn_rec->keepalive to an enumeration * 20020628 (2.0.40-dev) Added filter_init to filter registration functions * 20020903 (2.0.41-dev) APR's error constants changed + * 20021014 (2.0.44-dev) conn_rec gets bytes_in and bytes_out fields */ #define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */ #ifndef MODULE_MAGIC_NUMBER_MAJOR -#define MODULE_MAGIC_NUMBER_MAJOR 20020903 +#define MODULE_MAGIC_NUMBER_MAJOR 20021014 #endif #define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */ diff -u --recursive --new-file httpd-2.0-vanilla/include/httpd.h httpd-2.0/include/httpd.h --- httpd-2.0-vanilla/include/httpd.h Sat Oct 12 02:12:28 2002 +++ httpd-2.0/include/httpd.h Mon Oct 14 11:47:46 2002 @@ -1018,6 +1018,10 @@ void *sbh; /** The bucket allocator to use for all bucket/brigade creations */ struct apr_bucket_alloc_t *bucket_alloc; + /** Input bytes on this connection */ + apr_off_t bytes_in; + /** Output bytes on this connection */ + apr_off_t bytes_out; }; /* Per-vhost config... */ diff -u --recursive --new-file httpd-2.0-vanilla/modules/loggers/mod_logio.c httpd-2.0/modules/loggers/mod_logio.c --- httpd-2.0-vanilla/modules/loggers/mod_logio.c Sat Sep 28 14:18:35 2002 +++ httpd-2.0/modules/loggers/mod_logio.c Mon Oct 14 14:56:09 2002 @@ -84,35 +84,18 @@ module AP_MODULE_DECLARE_DATA logio_module; -static const char logio_filter_name[] = "LOG_INPUT_OUTPUT"; - -/* - * Logging of input and output config... - */ - -typedef struct logio_config_t { - apr_off_t bytes_in; - apr_off_t bytes_out; -} logio_config_t; - /* * Format items... */ static const char *log_bytes_in(request_rec *r, char *a) { - logio_config_t *cf = ap_get_module_config(r->connection->conn_config, - &logio_module); - - return apr_off_t_toa(r->pool, cf->bytes_in); + return apr_off_t_toa(r->pool, r->connection->bytes_in); } static const char *log_bytes_out(request_rec *r, char *a) { - logio_config_t *cf = ap_get_module_config(r->connection->conn_config, - &logio_module); - - return apr_off_t_toa(r->pool, cf->bytes_out); + return apr_off_t_toa(r->pool, r->connection->bytes_out); } /* @@ -121,71 +104,15 @@ static int logio_transaction(request_rec *r) { - logio_config_t *cf = ap_get_module_config(r->connection->conn_config, - &logio_module); - - cf->bytes_in = cf->bytes_out = 0; + r->connection->bytes_in = r->connection->bytes_out = 0; return OK; } /* - * Logging of input and output filters... - */ - -static apr_status_t logio_out_filter(ap_filter_t *f, - apr_bucket_brigade *bb) { - apr_off_t length; - logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module); - - if (!cf) { /* Create config */ - cf = apr_pcalloc(f->c->pool, sizeof(*cf)); - ap_set_module_config(f->c->conn_config, &logio_module, cf); - } - - apr_brigade_length (bb, 0, &length); - - if (length > 0) - cf->bytes_out += length; - - return ap_pass_brigade(f->next, bb); -} - -static apr_status_t logio_in_filter(ap_filter_t *f, - apr_bucket_brigade *bb, - ap_input_mode_t mode, - apr_read_type_e block, - apr_off_t readbytes) { - apr_off_t length; - apr_status_t status; - logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module); - - status = ap_get_brigade(f->next, bb, mode, block, readbytes); - - if (!cf) { /* Create config */ - cf = apr_pcalloc(f->c->pool, sizeof(*cf)); - ap_set_module_config(f->c->conn_config, &logio_module, cf); - } - - apr_brigade_length (bb, 0, &length); - - if (length > 0) - cf->bytes_in += length; - - return status; -} - -/* * The hooks... */ -static int logio_pre_conn(conn_rec *c) { - ap_add_input_filter(logio_filter_name, NULL, NULL, c); - ap_add_output_filter(logio_filter_name, NULL, NULL, c); - - return OK; -} - static int logio_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) { static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; @@ -204,14 +131,8 @@ { static const char *pre[] = { "mod_log_config.c", NULL }; - ap_hook_pre_connection(logio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_pre_config(logio_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); ap_hook_log_transaction(logio_transaction, pre, NULL, APR_HOOK_MIDDLE); - - ap_register_input_filter(logio_filter_name, logio_in_filter, NULL, - AP_FTYPE_NETWORK - 1); - ap_register_output_filter(logio_filter_name, logio_out_filter, NULL, - AP_FTYPE_NETWORK - 1); } module AP_MODULE_DECLARE_DATA logio_module = diff -u --recursive --new-file httpd-2.0-vanilla/server/core.c httpd-2.0/server/core.c --- httpd-2.0-vanilla/server/core.c Mon Oct 14 08:12:34 2002 +++ httpd-2.0/server/core.c Mon Oct 14 14:54:48 2002 @@ -125,6 +125,7 @@ AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle; AP_DECLARE_DATA ap_filter_rec_t *ap_net_time_filter_handle; AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle; +AP_DECLARE_DATA ap_filter_rec_t *ap_core_in_cnt_filter_handle; static void *create_core_dir_config(apr_pool_t *a, char *dir) { @@ -2709,6 +2710,7 @@ apr_off_t file_offset, apr_size_t file_bytes_left, apr_size_t total_bytes_left, + apr_size_t *bytes_sent, apr_int32_t flags) { apr_status_t rv; @@ -2720,11 +2722,15 @@ == APR_SUCCESS) && timeout > 0); /* socket must be in timeout mode */ + /* Reset the bytes_sent field */ + *bytes_sent = 0; + do { apr_size_t tmplen = file_bytes_left; rv = apr_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen, flags); + *bytes_sent += tmplen; total_bytes_left -= tmplen; if (!total_bytes_left || rv != APR_SUCCESS) { return rv; /* normal case & error exit */ @@ -3605,6 +3611,25 @@ return rv; } +/* Input filter for counting of number of input bytes */ +static apr_status_t core_in_cnt_filter(ap_filter_t *f, + apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t readbytes) { + apr_off_t length; + apr_status_t status; + + status = ap_get_brigade(f->next, bb, mode, block, readbytes); + + apr_brigade_length (bb, 0, &length); + + if (length > 0) + f->c->bytes_in += length; + + return status; +} + /* Default filter. This filter should almost always be used. Its only job * is to send the headers if they haven't already been sent, and then send * the actual data. @@ -3872,6 +3897,7 @@ if (fd) { apr_hdtr_t hdtr; + apr_size_t bytes_sent; #if APR_HAS_SENDFILE apr_int32_t flags = 0; #endif @@ -3900,9 +3926,14 @@ sending from */ flen, /* length of file */ nbytes + flen, /* total length including - headers */ + headers */ + &bytes_sent, /* how many bytes were + sent */ flags); /* apr_sendfile flags */ + if (bytes_sent > 0) + c->bytes_out += bytes_sent; + /* If apr_sendfile() returns APR_ENOTIMPL, call emulate_sendfile(). * emulate_sendfile() is useful to enable the same Apache binary * distribution to support Windows NT/2000 (supports TransmitFile) @@ -3911,19 +3942,24 @@ if (rv == APR_ENOTIMPL) #endif { - apr_size_t unused_bytes_sent; rv = emulate_sendfile(net, fd, &hdtr, foffset, flen, - &unused_bytes_sent); + &bytes_sent); + + if (bytes_sent > 0) + c->bytes_out += bytes_sent; } fd = NULL; } else { - apr_size_t unused_bytes_sent; + apr_size_t bytes_sent; rv = writev_it_all(net->client_socket, vec, nvec, - nbytes, &unused_bytes_sent); + nbytes, &bytes_sent); + + if (bytes_sent > 0) + c->bytes_out += bytes_sent; } apr_brigade_destroy(b); @@ -4118,6 +4154,7 @@ ap_set_module_config(net->c->conn_config, &core_module, csd); ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c); + ap_add_input_filter_handle(ap_core_in_cnt_filter_handle, net, NULL, net->c); ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c); return DONE; } @@ -4156,6 +4193,9 @@ ap_core_input_filter_handle = ap_register_input_filter("CORE_IN", core_input_filter, NULL, AP_FTYPE_NETWORK); + ap_core_in_cnt_filter_handle = + ap_register_input_filter("CORE_IN_CNT", core_in_cnt_filter, + NULL, AP_FTYPE_NETWORK - 1); ap_net_time_filter_handle = ap_register_input_filter("NET_TIME", net_time_filter, NULL, AP_FTYPE_PROTOCOL);