Hello, My apologies in advance for the crosspost, I'm not sure which group should handle this.
I am running httpd 2.0.40 on Linux 2.5.24 (compiled with gcc 3.1). I have noticed a problem where httpd is unable to determine the content-length of a POST message and aborts prior to calling the specified CGI script. The problem is being reported in the apr code, but I don't know if that's where the trouble is starting. Unfortunately, I do not know the apache source code at all and as such am not in a good position to debug it. If you are a serious developer and cannot reproduce it on your machine, I will set up an account for you on my machine if you are interested in fixing the problem. Here's the gist of the problem: - I have a test CGI in the /cgi-bin/ directory. The CGI works normally if it is referenced directly from a URL. This problem occurs with any CGI. Here is the code for my dummy CGI that I'm using for the test. It resides in /cgi-bin/foo : /* FILE: /cgi-bin/foo -- START */ #include <stdio.h> int main( void ) { fprintf( stdout, "Content-type: text/plain\n\n" ); fprintf( stdout, "Hello, World!\n" ); return 0; } /* FILE: /cgi-bin/foo -- END */ - Initially I discovered this problem trying to post data from an HTML form, but here is what I've reduced the POST request to that will still demonstrate the problem: POST /cgi-bin/foo HTTP/1.1 Host: foo.com Content-type: application/x-www-form-urlencoded Content-length: 36 Submit=Submit&hiddenField=hiddenData * please note that there is nothing special about the data, my choice of a hiddenField form element is arbitrary, the problem (I don't believe) is related to the form data). * - When I take this data and type it in line-by-line over a telnet connection, everything works fine and the "foo" CGI is called. When I send the data in one packet (or very close time-wise), httpd closes the TCP connection and reports the following in the log: [<time>] [error] [client <addr>] (104)Connection reset by peer: ap_content_length_filter: apr_bucket_read() failed Note that tcpdump shows that it is the server that is resetting the connection, *not* the client, even though the message given is "connection reset by peer". The critical thing seems to be whether or not the actual content is sent independently of the header. Here is some code that causes this behavior to happen every time on my machine. Note the sleep( 1 ) call in the code. If this line *is* present, the CGI is invoked and everything is hunky-dory. If the sleep line is commented out and the server fails with the above error. Here is the sample code, please contact me directly by reply email if you need some help reproducing this or if I can help. If you fix it, please send me a patch :) I'm sorry I can't help more, but it would take me a long time to familiarize myself with the apache code to a point where I could successfully debug this and unfortunately I'm engaged on another project. Thank you, Brian Doyle Balance Software, Inc. /* FILE: cgi_post_test.c -- START */ #include <arpa/inet.h> #include <netinet/in.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> int connect_to_www_server( char *ip_address, int *sockfd ); char packet1[] = "POST /cgi-bin/foo HTTP/1.1\r\n" \ "Host: foo.com\r\n" \ "Content-type: application/x-www-form-urlencoded\r\n" \ "Content-length: 36\r\n" \ "\r\n"; char packet2[] = "Submit=Submit&hiddenField=hiddenData\r\n"; int main(int argc, char **argv) { char buf[ 4096 ]; int sockfd, n, err = 0; if ( argc != 2 ) { fprintf( stdout, "usage: %s <IP address of web server>\n", argv[ 0 ] ); err = 1; } if ( ! err ) err = connect_to_www_server( argv[ 1 ], &sockfd ); if ( ! err && write( sockfd, packet1, strlen( packet1 ) ) < 0 ) err = 1; /* With the sleep( 1 ) line intact below, the /cgi-bin/foo script is executed and "Hello, World!" is returned. If the sleep( 1 ) call is commented out, the /cgi-bin/foo script is *NOT* invoked, and apache returns the following error: [Thu Aug 29 14:59:51 2002] [error] [client 10.0.0.10] (104)Connection reset by peer: ap_content_length_filter: apr_bucket_read() failed */ sleep( 1 ); if ( ! err && write( sockfd, packet2, strlen( packet2 ) ) < 0 ) err = 1; while ( ! err && ( n = read( sockfd, buf, 4095 ) ) > 0 ) { buf[ n ] = 0; fprintf( stdout, "%s", buf ); } if ( err ) fprintf( stderr, "an error occurred\n" ); return err; } int connect_to_www_server( char *ip_address, int *sockfd ) { struct sockaddr_in server; int err = 0; if ( ( *sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) err = 1; if ( ! err ) { bzero( &server, sizeof(server) ); server.sin_family = AF_INET; server.sin_port = htons( 80 ); /* www */ if ( inet_pton( AF_INET, ip_address, &server.sin_addr) <= 0 ) { err = 1; } } if ( ! err ) { if ( connect( *sockfd, (struct sockaddr *) &server, sizeof(server) ) < 0 ) { err = 1; } } return err; } /* FILE: cgi_post_test.c -- END */