As Matthias L. found out, the problems with POST requests in conjunction with
per-directory/location SSL renegotiations is that the pending POST request
body in the SSL BIO caused problems for the handshake. I've today spended four
hours in the morning and hacked together an experimental patch which does the
following: before the SSL handshake for renegotiations is performed it sucks
in all received data from the SSL BIO. Then the handshake is performed and
when Apache's BUFF code wants to read more from the BIO SSL we are aware of
the pre-sucked data. With this patch I was able to get a form working which
POSTs its data to a CGI (I was also to reproduce the I/O error problem before,
of course).
Matthias, can you try this out, too? I'm still not convinced whether this is
the correct way (perhaps we can also maipulate the SSL BIO or whatever), but
it at least is a solution. I've less time these days and weeks, so I would
appreciate when you investigate more for us - starting from this first cut of
a solution. Thanks.
Greetings,
Ralf S. Engelschall
[EMAIL PROTECTED]
www.engelschall.com
Index: include/buff.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/include/buff.h,v
retrieving revision 1.6
diff -u -r1.6 buff.h
--- include/buff.h 1999/01/10 11:07:22 1.6
+++ include/buff.h 1999/07/26 09:26:06
@@ -227,6 +227,10 @@
/* enable non-blocking operations */
API_EXPORT(int) ap_bnonblock(BUFF *fb, int direction);
+/* enable blocking operations */
+API_EXPORT(int) ap_bblock(BUFF *fb, int direction);
+/* check for blocking mode */
+API_EXPORT(int) ap_bisblock(BUFF *fb, int direction);
/* and get an fd to select() on */
API_EXPORT(int) ap_bfileno(BUFF *fb, int direction);
Index: main/buff.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/main/buff.c,v
retrieving revision 1.14
diff -u -r1.14 buff.c
--- main/buff.c 1999/03/21 12:00:11 1.14
+++ main/buff.c 1999/07/26 09:25:30
@@ -580,6 +580,44 @@
#endif
}
+API_EXPORT(int) ap_bblock(BUFF *fb, int direction)
+{
+ int fd;
+ int mode;
+
+ fd = (direction == B_RD) ? fb->fd_in : fb->fd;
+ mode = fcntl(fd, F_GETFL, NULL);
+#if defined(O_NONBLOCK)
+ return fcntl(fd, F_SETFL, mode&~(O_NONBLOCK));
+#elif defined(O_NDELAY)
+ return fcntl(fd, F_SETFL, mode&~(O_NDELAY));
+#elif defined(FNDELAY)
+ return fcntl(fd, F_SETFL, mode&~(FNDELAY));
+#else
+ /* XXXX: this breaks things, but an alternative isn't obvious...*/
+ return 0;
+#endif
+}
+
+API_EXPORT(int) ap_bisblock(BUFF *fb, int direction)
+{
+ int fd;
+ int mode;
+
+ fd = (direction == B_RD) ? fb->fd_in : fb->fd;
+ mode = fcntl(fd, F_GETFL, NULL);
+#if defined(O_NONBLOCK)
+ return (mode & O_NONBLOCK) ? FALSE : TRUE;
+#elif defined(O_NDELAY)
+ return (mode & O_NDELAY) ? FALSE : TRUE;
+#elif defined(FNDELAY)
+ return (mode & FNDELAY) ? FALSE : TRUE;
+#else
+ /* XXXX: this breaks things, but an alternative isn't obvious...*/
+ return FALSE;
+#endif
+}
+
API_EXPORT(int) ap_bfileno(BUFF *fb, int direction)
{
return (direction == B_RD) ? fb->fd_in : fb->fd;
Index: modules/ssl/mod_ssl.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/mod_ssl.h,v
retrieving revision 1.108
diff -u -r1.108 mod_ssl.h
--- modules/ssl/mod_ssl.h 1999/07/25 11:24:13 1.108
+++ modules/ssl/mod_ssl.h 1999/07/26 08:02:23
@@ -715,6 +715,7 @@
void ssl_io_register(void);
void ssl_io_unregister(void);
long ssl_io_data_cb(BIO *, int, const char *, int, long, long);
+void ssl_io_suck(SSL *);
/* PRNG */
int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t);
Index: modules/ssl/ssl_engine_io.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_io.c,v
retrieving revision 1.23
diff -u -r1.23 ssl_engine_io.c
--- modules/ssl/ssl_engine_io.c 1999/05/04 07:58:53 1.23
+++ modules/ssl/ssl_engine_io.c 1999/07/26 09:53:23
@@ -64,6 +64,138 @@
-- Unknown */
#include "mod_ssl.h"
+/* _________________________________________________________________
+**
+** I/O Sucking
+** _________________________________________________________________
+*/
+
+static char *suck_buf = NULL;
+static int suck_len = 0;
+
+static char *suck_ptr = NULL;
+static int suck_pend = 0;
+
+int ssl_io_suck_in(SSL *ssl, int n);
+int ssl_io_suck_read(SSL *ssl, char *buf, int len);
+
+void ssl_io_suck(SSL *ssl)
+{
+ conn_rec *c;
+ BUFF *b;
+ int wasblocking;
+
+ c = (conn_rec *)SSL_get_app_data(ssl);
+ b = c->client;
+
+ /* set socket to non-blocking mode */
+ wasblocking = ap_bisblock(b, B_RD);
+ ap_bnonblock(b, B_RD);
+
+ /* suck in data by chunks of 4KB */
+ while (ssl_io_suck_in(ssl, 4096) > 0) ;
+
+ /* restore socket operation mode */
+ if (wasblocking)
+ ap_bblock(b, B_RD);
+ return;
+}
+
+int ssl_io_suck_in(SSL *ssl, int n)
+{
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ int rc;
+
+ if (suck_buf == NULL) {
+ /* the first time: start with a fresh buffer */
+ suck_len = (n > 1024 ? n : 1024);
+ suck_buf = malloc(suck_len);
+ suck_ptr = suck_buf;
+ suck_pend = 0;
+ rc = SSL_read(ssl, suck_buf, suck_len);
+ ssl_log(c->server, SSL_LOG_TRACE, "%d = SSL_read(0, %d)", rc, suck_len);
+ if (rc >= 0) {
+ suck_pend = rc;
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: sucking %d/%d bytes into fresh buffer (%d: %d/%d)",
+ suck_pend, n, suck_len, 0, suck_pend);
+ }
+ return rc;
+ }
+ else if ((suck_buf+suck_len) - (suck_ptr+suck_pend) >= n) {
+ /* fill more data into existing buffer */
+ rc = SSL_read(ssl, suck_ptr+suck_pend, n);
+ ssl_log(c->server, SSL_LOG_TRACE, "%d = SSL_read(%d, %d)", rc, suck_pend, n);
+ if (rc >= 0) {
+ suck_pend += rc;
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: sucking %d/%d additional bytes to end of buffer (%d:
+%d/%d)",
+ rc, n, suck_len, suck_ptr-suck_buf, suck_ptr-suck_buf+suck_pend);
+ }
+ return rc;
+ }
+ else {
+ /* resize buffer and fill in additional data */
+ suck_len += n - ((suck_buf+suck_len) - (suck_ptr+suck_pend));
+ suck_buf = realloc(suck_buf, suck_len);
+ rc = SSL_read(ssl, suck_ptr+suck_pend, n);
+ ssl_log(c->server, SSL_LOG_TRACE, "%d = SSL_read(%d, %d)", rc, suck_pend, n);
+ if (rc >= 0) {
+ suck_pend += rc;
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: sucking %d/%d bytes while expanding buffer (%d:
+%d/%d)",
+ rc, n, suck_len, suck_ptr-suck_buf, suck_ptr-suck_buf+suck_pend);
+ }
+ return rc;
+ }
+}
+
+int ssl_io_suck_read(SSL *ssl, char *buf, int len)
+{
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ int rv;
+
+ ssl_log(c->server, SSL_LOG_TRACE, "ssl_io_suck_read(%d)", len);
+
+ if (suck_pend >= len) {
+ /* more data than requestd */
+ memcpy(buf, suck_ptr, len);
+ suck_ptr += len;
+ suck_pend -= len;
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: reading %d bytes from suck buffer", len);
+ ssl_log(c->server, SSL_LOG_TRACE, "%d = my_SSL_read()", len);
+ if (suck_pend == 0)
+ suck_ptr = suck_buf;
+ return len;
+ }
+ else if (suck_pend > 0) {
+ /* less data than requested */
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: reading remaining %d bytes from suck buffer", suck_pend);
+ memcpy(buf, suck_ptr, suck_pend);
+ buf += suck_pend;
+ len -= suck_pend;
+ rv = suck_pend;
+ suck_ptr = suck_buf;
+ suck_pend = 0;
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: reading additional %d bytes from SSL stream", len);
+ return rv;
+ }
+ else {
+ /* nothing pre-sucked, so do standard operation */
+ rv = SSL_read(ssl, buf, len);
+ if (rv >= 0)
+ ssl_log(c->server, SSL_LOG_TRACE,
+ "SSL I/O: reading %d bytes from SSL stream", rv);
+ ssl_log(c->server, SSL_LOG_TRACE, "%d = my_SSL_read()", rv);
+ return rv;
+ }
+}
+
+/* override SSL_read in following code */
+#define SSL_read ssl_io_suck_read
/* _________________________________________________________________
**
Index: modules/ssl/ssl_engine_kernel.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_kernel.c,v
retrieving revision 1.101
diff -u -r1.101 ssl_engine_kernel.c
--- modules/ssl/ssl_engine_kernel.c 1999/07/26 07:42:35 1.101
+++ modules/ssl/ssl_engine_kernel.c 1999/07/26 08:02:42
@@ -938,6 +938,7 @@
SSL_set_session_id_context(ssl, (unsigned char *)&(r->main),
sizeof(r->main));
else
SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r));
+ ssl_io_suck(ssl);
SSL_renegotiate(ssl);
SSL_do_handshake(ssl);
if (SSL_get_state(ssl) != SSL_ST_OK) {
______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl) www.modssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]