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);
}