On Mon, Jul 26, 1999, Ralf S. Engelschall wrote:

> 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.

Ok, I couldn't resist and have tried a second attempt, because the first
attempt was not aware of HTTP chunking and other side-effects. Now I do a
really tricky thing: I read the client body through Apache's standard API
which is chunking-aware, but instead of processing the data it's just pushed
into a suck-buffer attached to the request_rec. Later when mod_cgi again wants
to read the client body it is served by the data in the suck buffer. This now
works again fine for my test scripts and should be now a 98% correct solution
(while the first patch was justa 50% solution). Nevertheless it need review
and wider testing. So, forget my first patch from this morning and instead
test the appended patch.

Thanks.
                                       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 13:17:25
@@ -182,6 +182,8 @@
 
 #ifndef CHARSET_EBCDIC
 
+#define ap_bpeekc(fb)   ( ((fb)->incnt == 0) ? EOF : *((fb)->inptr) )
+
 #define ap_bgetc(fb)   ( ((fb)->incnt == 0) ? ap_bfilbuf(fb) : \
                    ((fb)->incnt--, *((fb)->inptr++)) )
 
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 11:30:25
@@ -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(request_rec *, 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 13:24:36
@@ -64,6 +64,154 @@
                                             -- Unknown    */
 #include "mod_ssl.h"
 
+/*  _________________________________________________________________
+**
+**  I/O Request Body Sucking and Re-Injection
+**  _________________________________________________________________
+*/
+
+#ifdef SSL_EXPERIMENTAL
+
+struct ssl_io_suck_st {
+    BOOL  active;
+    char *bufptr;
+    int   buflen;
+    char *pendptr;
+    int   pendlen;
+};
+
+/* prepare request_rec structure for input sucking */
+static void ssl_io_suck_start(request_rec *r)
+{
+    struct ssl_io_suck_st *ss;
+
+    ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+    if (ss == NULL) {
+        ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));
+        ap_ctx_set(r->ctx, "ssl::io::suck", ss);
+        ss->buflen  = 8192;
+        ss->bufptr  = ap_palloc(r->pool, ss->buflen);
+    }
+    ss->pendptr = ss->bufptr;
+    ss->pendlen = 0;
+    ss->active = FALSE;
+    return;
+}
+
+/* record a sucked input chunk */
+static void ssl_io_suck_record(request_rec *r, char *buf, int len)
+{
+    struct ssl_io_suck_st *ss;
+    
+    if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+        return;
+    if (((ss->bufptr+ss->buflen)-(ss->pendptr+ss->pendlen)) < len) {
+        /* "expand" buffer */
+        int newlen;
+        char *newptr;
+        if (ss->buflen < len)
+            newlen = ss->buflen * 2;
+        else
+            newlen = ss->buflen + len;
+        newptr = ap_palloc(r->pool, newlen);
+        memcpy(newptr, ss->bufptr, ss->buflen);
+        ss->bufptr = newptr;
+        ss->buflen = newlen;
+    }
+    memcpy(ss->pendptr+ss->pendlen, buf, len);
+    ss->pendlen += len;
+    ssl_log(r->server, SSL_LOG_TRACE, 
+            "SSL I/O: stored %d bytes into suck buffer (size: %d bytes)", len, 
+ss->buflen);
+    return;
+}
+
+/* finish request_rec after input sucking */
+static void ssl_io_suck_end(request_rec *r)
+{
+    struct ssl_io_suck_st *ss;
+    
+    if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+        return;
+    ss->active = TRUE;
+    r->read_body    = REQUEST_NO_BODY;
+    r->read_length  = 0;
+    r->read_chunked = 0;
+    r->remaining    = 0;
+    ap_bsetflag(r->connection->client, B_CHUNK, 0);
+    return;
+}
+
+void ssl_io_suck(request_rec *r, SSL *ssl)
+{
+    int rc;
+    int len;
+    char *buf;
+    int buflen;
+
+    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
+        if (ap_should_client_block(r)) {
+            /* read client request block */
+            buflen = HUGE_STRING_LEN;
+            buf = ap_palloc(r->pool, buflen);
+            ap_hard_timeout("SSL I/O request body pre-sucking", r);
+            ssl_io_suck_start(r);
+            while ((len = ap_get_client_block(r, buf, buflen)) > 0)
+                ssl_io_suck_record(r, buf, len);
+            ssl_io_suck_end(r);
+            ap_kill_timeout(r);
+            /* remove possibly trailing CR LF which Apache usually handles later */
+            if (ap_bpeekc(r->connection->client) == CR)
+                (void)ap_bgetc(r->connection->client);
+            if (ap_bpeekc(r->connection->client) == LF)
+                (void)ap_bgetc(r->connection->client);
+        }
+    }
+    return;
+}
+    
+/* the SSL_read replacement routine */
+static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
+{
+    ap_ctx *actx;
+    struct ssl_io_suck_st *ss;
+    request_rec *r;
+    conn_rec *c;
+    int rv;
+
+    c = (conn_rec *)SSL_get_app_data(ssl);
+    ssl_log(c->server, SSL_LOG_TRACE, "SSL I/O: read request for %d bytes", len);
+    rv = -1;
+    actx = (ap_ctx *)SSL_get_app_data2(ssl);
+    r    = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
+    if (r != NULL) {
+        ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+        if (ss != NULL) {
+            if (ss->active && ss->pendlen > 0) {
+                /* ok, there is pre-sucked data */
+                len = (ss->pendlen > len ? len : ss->pendlen);
+                memcpy(buf, ss->pendptr, len);
+                ss->pendptr += len;
+                ss->pendlen -= len;
+                ssl_log(c->server, SSL_LOG_TRACE, 
+                        "SSL I/O: read response from suck buffer: %d bytes", len);
+                rv = len;
+            }
+        }
+    }
+    if (rv == -1) {
+        rv = SSL_read(ssl, buf, len);
+        if (rv >= 0)
+            ssl_log(c->server, SSL_LOG_TRACE, 
+                    "SSL I/O: read response from SSL stream: %d bytes", rv);
+    }
+    ssl_log(c->server, SSL_LOG_TRACE, "SSL I/O: read response: %d", rv);
+    return rv;
+}
+
+/* override SSL_read in the following code... */
+#define SSL_read ssl_io_suck_read
+
+#endif /* SSL_EXPERIMENTAL */
 
 /*  _________________________________________________________________
 **
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 11:00:31
@@ -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(r, 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]

Reply via email to