For quite a while (>1.5 years I think) www.apache.org has run with a patch to APR which saves a certain amount of data read from the client. It is then used for debugging in the case of a segfault. Having access to the actual data and in what segments it was returned to Apache helped fix some bugs pretty quickly.
I've cleaned up that patch a bit in hopes of showing how the functionality could be added to APR. In this new patch, the saving of data is turned on by the app via a socket option rather than always enabled as in the www.apache.org patch.
Is anybody for/against putting something like this in APR?
It would be nice to enable the app to change the parameters (how many buffers to save, how much of each buffer to save). I guess those could be separate options in the future, with the current constants "20" and "1024" simply the defaults.
It would also be nice to allow the app to retrieve the list of saved input buffers, though it is still useful even without that feature.
Index: include/apr_network_io.h
===================================================================
RCS file: /home/cvs/apr/include/apr_network_io.h,v
retrieving revision 1.136
diff -u -r1.136 apr_network_io.h
--- include/apr_network_io.h 1 Jan 2003 00:01:45 -0000 1.136
+++ include/apr_network_io.h 20 Feb 2003 17:53:17 -0000
@@ -133,6 +133,9 @@
#define APR_IPV6_V6ONLY 16384 /**< Don't accept IPv4 connections on an
* IPv6 listening socket.
*/
+#define APR_SO_SAVE_INPUT 32768 /**< Maintain a copy of data read from the
+ * network.
+ */
/** @} */
Index: include/arch/unix/apr_arch_networkio.h
===================================================================
RCS file: /home/cvs/apr/include/arch/unix/apr_arch_networkio.h,v
retrieving revision 1.1
diff -u -r1.1 apr_arch_networkio.h
--- include/arch/unix/apr_arch_networkio.h 6 Jan 2003 23:44:26 -0000
1.1
+++ include/arch/unix/apr_arch_networkio.h 20 Feb 2003 17:53:17 -0000
@@ -111,6 +111,9 @@
#if APR_HAVE_SYS_SENDFILE_H
#include <sys/sendfile.h>
#endif
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
/* End System Headers */
#ifndef HAVE_POLLIN
@@ -122,6 +125,14 @@
#define POLLNVAL 32
#endif
+typedef struct apr_net_input_buffer_t apr_net_input_buffer_t;
+struct apr_net_input_buffer_t {
+ struct apr_net_input_buffer_t *prev;
+ apr_int32_t saved_len;
+ apr_int32_t actual_len;
+ char data[1]; /* actual data starts here */
+};
+
struct apr_socket_t {
apr_pool_t *cntxt;
int socketdes;
@@ -138,6 +149,8 @@
int remote_addr_unknown;
apr_int32_t netmask;
apr_int32_t inherit;
+ apr_int32_t num_input_buffers;
+ apr_net_input_buffer_t *input_buffers;
};
const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size);
Index: network_io/unix/sendrecv.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.95
diff -u -r1.95 sendrecv.c
--- network_io/unix/sendrecv.c 7 Jan 2003 00:52:56 -0000 1.95
+++ network_io/unix/sendrecv.c 20 Feb 2003 17:53:17 -0000
@@ -141,6 +141,21 @@
sock->netmask |= APR_INCOMPLETE_READ;
}
(*len) = rv;
+ if (sock->netmask & APR_SO_SAVE_INPUT) {
+ if (sock->num_input_buffers < 20) {
+ apr_size_t bytes_to_save = (*len > 1024) ? 1024 : *len;
+ apr_net_input_buffer_t *new =
+ apr_palloc(sock->cntxt,
+ offsetof(struct apr_net_input_buffer_t,
+ data) + bytes_to_save);
+
+ new->saved_len = bytes_to_save;
+ new->actual_len = *len;
+ new->prev = sock->input_buffers;
+ sock->input_buffers = new;
+ ++sock->num_input_buffers;
+ }
+ }
if (rv == 0) {
return APR_EOF;
}
Index: network_io/unix/sockopt.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sockopt.c,v
retrieving revision 1.66
diff -u -r1.66 sockopt.c
--- network_io/unix/sockopt.c 7 Feb 2003 20:34:27 -0000 1.66
+++ network_io/unix/sockopt.c 20 Feb 2003 17:53:17 -0000
@@ -325,6 +325,9 @@
return APR_ENOTIMPL;
#endif
break;
+ case APR_SO_SAVE_INPUT:
+ apr_set_option(&sock->netmask, APR_SO_SAVE_INPUT, on);
+ break;
default:
return APR_EINVAL;
}
