Blob Blame History Raw

https://issues.apache.org/bugzilla/show_bug.cgi?id=45444

http://svn.apache.org/viewvc?rev=683280&view=rev
http://svn.apache.org/viewvc?rev=683283&view=rev

diff -up httpd-2.2.16/modules/ssl/ssl_engine_io.c.pr45444 httpd-2.2.16/modules/ssl/ssl_engine_io.c
--- httpd-2.2.16/modules/ssl/ssl_engine_io.c.pr45444	2010-03-01 21:27:17.000000000 +0000
+++ httpd-2.2.16/modules/ssl/ssl_engine_io.c	2010-08-17 13:40:29.065628677 +0100
@@ -344,6 +344,13 @@ typedef struct {
  * this char_buffer api might seem silly, but we don't need to copy
  * any of this data and we need to remember the length.
  */
+
+/* Copy up to INL bytes from the char_buffer BUFFER into IN.  Note
+ * that due to the strange way this API is designed/used, the
+ * char_buffer object is used to cache a segment of inctx->buffer, and
+ * then this function called to copy (part of) that segment to the
+ * beginning of inctx->buffer.  So the segments to copy cannot be
+ * presumed to be non-overlapping, and memmove must be used. */
 static int char_buffer_read(char_buffer_t *buffer, char *in, int inl)
 {
     if (!buffer->length) {
@@ -352,13 +359,13 @@ static int char_buffer_read(char_buffer_
 
     if (buffer->length > inl) {
         /* we have have enough to fill the caller's buffer */
-        memcpy(in, buffer->value, inl);
+        memmove(in, buffer->value, inl);
         buffer->value += inl;
         buffer->length -= inl;
     }
     else {
         /* swallow remainder of the buffer */
-        memcpy(in, buffer->value, buffer->length);
+        memmove(in, buffer->value, buffer->length);
         inl = buffer->length;
         buffer->value = NULL;
         buffer->length = 0;
@@ -722,6 +729,9 @@ static apr_status_t ssl_io_input_read(bi
     return inctx->rc;
 }
 
+/* Read a line of input from the SSL input layer into buffer BUF of
+ * length *LEN; updating *len to reflect the length of the line
+ * including the LF character. */
 static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx,
                                          char *buf,
                                          apr_size_t *len)
@@ -1315,8 +1325,8 @@ static apr_status_t ssl_io_filter_input(
 {
     apr_status_t status;
     bio_filter_in_ctx_t *inctx = f->ctx;
-
-    apr_size_t len = sizeof(inctx->buffer);
+    const char *start = inctx->buffer; /* start of block to return */
+    apr_size_t len = sizeof(inctx->buffer); /* length of block to return */
     int is_init = (mode == AP_MODE_INIT);
 
     if (f->c->aborted) {
@@ -1368,7 +1378,25 @@ static apr_status_t ssl_io_filter_input(
         status = ssl_io_input_read(inctx, inctx->buffer, &len);
     }
     else if (inctx->mode == AP_MODE_GETLINE) {
-        status = ssl_io_input_getline(inctx, inctx->buffer, &len);
+        const char *pos;
+
+        /* Satisfy the read directly out of the buffer if possible;
+         * invoking ssl_io_input_getline will mean the entire buffer
+         * is copied once (unnecessarily) for each GETLINE call. */
+        if (inctx->cbuf.length 
+            && (pos = memchr(inctx->cbuf.value, APR_ASCII_LF, 
+                             inctx->cbuf.length)) != NULL) {
+            start = inctx->cbuf.value;
+            len = 1 + pos - start; /* +1 to include LF */
+            /* Buffer contents now consumed. */
+            inctx->cbuf.value += len;
+            inctx->cbuf.length -= len;
+            status = APR_SUCCESS;
+        }
+        else {
+            /* Otherwise fall back to the hard way. */
+            status = ssl_io_input_getline(inctx, inctx->buffer, &len);
+        }
     }
     else {
         /* We have no idea what you are talking about, so return an error. */
@@ -1390,7 +1418,7 @@ static apr_status_t ssl_io_filter_input(
     /* Create a transient bucket out of the decrypted data. */
     if (len > 0) {
         apr_bucket *bucket =
-            apr_bucket_transient_create(inctx->buffer, len, f->c->bucket_alloc);
+            apr_bucket_transient_create(start, len, f->c->bucket_alloc);
         APR_BRIGADE_INSERT_TAIL(bb, bucket);
     }