Commit 21039db7 authored by Yann Ylavic's avatar Yann Ylavic
Browse files

mod_ssl: bind buffered data to filter's pending data.

Otherwise they are not considered by ap_filter_input_pending() and pipelining
is not detected (MPM event times out).


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1844779 13f79535-47bb-0310-9956-ffa450edef68
parent 7e0702b1
Loading
Loading
Loading
Loading
+65 −38
Changes for modules/ssl/ssl_engine_io.c: 65 added lines, 38 removed lines.
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "ssl_private.h"
#include "mod_ssl.h"
#include "mod_ssl_openssl.h"
#include "core.h"
#include "apr_date.h"

APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, proxy_post_handshake,
@@ -320,8 +321,8 @@ static int bio_filter_out_puts(BIO *bio, const char *str)
}

typedef struct {
    int length;
    char *value;
    apr_bucket *b;
    apr_bucket_brigade *bb;
} char_buffer_t;

typedef struct {
@@ -343,39 +344,70 @@ typedef struct {
 * any of this data and we need to remember the length.
 */

static void char_buffer_consume(bio_filter_in_ctx_t *inctx, int inl)
{
    apr_bucket *b = inctx->cbuf.b;

    b->data = (char *)b->data + inl;
    b->length -= inl;

    if (!b->length) {
        APR_BUCKET_REMOVE(b);
        APR_BUCKET_INIT(b);
    }
    else if (APR_BUCKET_NEXT(b) == b) {
        /* rollbacks might get us here (inl < 0) */
        APR_BRIGADE_INSERT_HEAD(inctx->cbuf.bb, b);
    }
}

/* 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)
static int char_buffer_read(bio_filter_in_ctx_t *inctx, char *in, int inl)
{
    if (!buffer->length) {
    apr_bucket *b = inctx->cbuf.b;
    int avail = b ? b->length : 0;

    if (!avail) {
        return 0;
    }

    if (buffer->length > inl) {
        /* we have enough to fill the caller's buffer */
        memmove(in, buffer->value, inl);
        buffer->value += inl;
        buffer->length -= inl;
    }
    else {
        /* swallow remainder of the buffer */
        memmove(in, buffer->value, buffer->length);
        inl = buffer->length;
        buffer->value = NULL;
        buffer->length = 0;
    if (inl > avail) {
        inl = avail;
    }
    memmove(in, b->data, inl);
    char_buffer_consume(inctx, inl);

    return inl;
}

static int char_buffer_write(char_buffer_t *buffer, char *in, int inl)
static int char_buffer_write(bio_filter_in_ctx_t *inctx, char *in, int inl)
{
    buffer->value = in;
    buffer->length = inl;
    ap_filter_t *f = inctx->filter_ctx->pInputFilter;
    char_buffer_t *buf = &inctx->cbuf;
    apr_bucket *b = buf->b;

    if (!b) {
        buf->b = b = apr_bucket_immortal_create("", 0, f->c->bucket_alloc);
        buf->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
    }
    else {
        AP_DEBUG_ASSERT(APR_BUCKET_NEXT(b) == b);
    }

    b->data = in;
    b->length = inl;
    if (b->length) {
        /* set this at the top of the filter's pending data */
        ap_filter_reinstate_brigade(f, buf->bb, NULL);
        APR_BRIGADE_INSERT_HEAD(buf->bb, b);
        ap_filter_adopt_brigade(f, buf->bb);
    }

    return inl;
}

@@ -650,22 +682,16 @@ static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx,
                                      apr_size_t *len)
{
    apr_size_t wanted = *len;
    apr_size_t bytes = 0;
    int rc;
    int bytes, rc;

    *len = 0;

    /* If we have something leftover from last time, try that first. */
    if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) {
    if ((bytes = char_buffer_read(inctx, buf, wanted))) {
        *len = bytes;
        if (inctx->mode == AP_MODE_SPECULATIVE) {
            /* We want to rollback this read. */
            if (inctx->cbuf.length > 0) {
                inctx->cbuf.value -= bytes;
                inctx->cbuf.length += bytes;
            } else {
                char_buffer_write(&inctx->cbuf, buf, (int)bytes);
            }
            char_buffer_consume(inctx, -bytes);
            return APR_SUCCESS;
        }
        /* This could probably be *len == wanted, but be safe from stray
@@ -711,7 +737,7 @@ static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx,
            *len += rc;
            if (inctx->mode == AP_MODE_SPECULATIVE) {
                /* We want to rollback this read. */
                char_buffer_write(&inctx->cbuf, buf, rc);
                char_buffer_write(inctx, buf, rc);
            }
            return inctx->rc;
        }
@@ -839,7 +865,7 @@ static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx,
        if (status != APR_SUCCESS) {
            if (APR_STATUS_IS_EAGAIN(status) && (*len > 0)) {
                /* Save the part of the line we already got */
                char_buffer_write(&inctx->cbuf, buf, *len);
                char_buffer_write(inctx, buf, *len);
            }
            return status;
        }
@@ -863,7 +889,7 @@ static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx,
        value = buf + bytes;
        length = *len - bytes;

        char_buffer_write(&inctx->cbuf, value, length);
        char_buffer_write(inctx, value, length);

        *len = bytes;
    }
@@ -1588,17 +1614,18 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f,
    else if (inctx->mode == AP_MODE_GETLINE) {
        const char *pos;

        bucket = inctx->cbuf.b;

        /* 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;
        if (bucket && bucket->length
                && (pos = memchr(bucket->data, APR_ASCII_LF,
                                 bucket->length)) != NULL) {
            start = bucket->data;
            len = 1 + pos - start; /* +1 to include LF */
            /* Buffer contents now consumed. */
            inctx->cbuf.value += len;
            inctx->cbuf.length -= len;
            char_buffer_consume(inctx, len);
            status = APR_SUCCESS;
        }
        else {
@@ -2106,7 +2133,7 @@ static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c,
    inctx->f = filter_ctx->pInputFilter;
    inctx->rc = APR_SUCCESS;
    inctx->mode = AP_MODE_READBYTES;
    inctx->cbuf.length = 0;
    memset(&inctx->cbuf, 0, sizeof(inctx->cbuf));
    inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc);
    inctx->block = APR_BLOCK_READ;
    inctx->pool = c->pool;