Commit 0c6f2c36 authored by Stefan Eissing's avatar Stefan Eissing
Browse files

mod_proxy_wstunnel, mod_proxy_connect: Use the correct pool and allocator

     lifetime when sending brigades and buckets down the filter chain

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1732266 13f79535-47bb-0310-9956-ffa450edef68
parent d4446cd8
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -458,6 +458,9 @@
 *                          Added ap_parse_token_list_strict() to httpd.h
 * 20120211.52 (2.4.17-dev) Add master conn_rec* member in conn_rec.
 * 20120211.53 (2.4.19-dev) Add epxr_hander to core_dir_config.
 * 20120211.54 (2.4.19-dev) Add ap_proxy_buckets_lifetime_transform and
 *                          ap_proxy_transfer_between_connections to
 *                          mod_proxy.h
 */

#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -465,7 +468,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
#endif
#define MODULE_MAGIC_NUMBER_MINOR 53                   /* 0...n */
#define MODULE_MAGIC_NUMBER_MINOR 54                   /* 0...n */

/**
 * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
+56 −0
Original line number Diff line number Diff line
@@ -1042,6 +1042,62 @@ PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme);
 */
PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url);

/*
 * Transform buckets from one bucket allocator to another one by creating a
 * transient bucket for each data bucket and let it use the data read from
 * the old bucket. Metabuckets are transformed by just recreating them.
 * Attention: Currently only the following bucket types are handled:
 *
 * All data buckets
 * FLUSH
 * EOS
 *
 * If an other bucket type is found its type is logged as a debug message
 * and APR_EGENERAL is returned.
 *
 * @param r     request_rec of the actual request. Used for logging purposes
 * @param from  the bucket brigade to take the buckets from
 * @param to    the bucket brigade to store the transformed buckets
 * @return      apr_status_t of the operation. Either APR_SUCCESS or
 *              APR_EGENERAL
 */
PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r,
                                                      apr_bucket_brigade *from,
                                                      apr_bucket_brigade *to);

/*
 * Sends all data that can be read non blocking from the input filter chain of
 * c_i and send it down the output filter chain of c_o. For reading it uses
 * the bucket brigade bb_i which should be created from the bucket allocator
 * associated with c_i. For sending through the output filter chain it uses
 * the bucket brigade bb_o which should be created from the bucket allocator
 * associated with c_o. In order to get the buckets from bb_i to bb_o
 * ap_proxy_buckets_lifetime_transform is used.
 *
 * @param r     request_rec of the actual request. Used for logging purposes
 * @param c_i   inbound connection conn_rec
 * @param c_o   outbound connection conn_rec
 * @param bb_i  bucket brigade for pulling data from the inbound connection
 * @param bb_o  bucket brigade for sending data through the outbound connection
 * @param name  string for logging from where data was pulled
 * @param sent  if not NULL will be set to 1 if data was sent through c_o
 * @param bsize maximum amount of data pulled in one iteration from c_i
 * @param after if set flush data on c_o only once after the loop
 * @return      apr_status_t of the operation. Could be any error returned from
 *              either the input filter chain of c_i or the output filter chain
 *              of c_o. APR_EPIPE if the outgoing connection was aborted.
 */
PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
                                                       request_rec *r,
                                                       conn_rec *c_i,
                                                       conn_rec *c_o,
                                                       apr_bucket_brigade *bb_i,
                                                       apr_bucket_brigade *bb_o,
                                                       const char *name,
                                                       int *sent,
                                                       apr_off_t bsize,
                                                       int after);

extern module PROXY_DECLARE_DATA proxy_module;

#endif /*MOD_PROXY_H*/
+25 −58
Original line number Diff line number Diff line
@@ -143,53 +143,6 @@ static int proxy_connect_canon(request_rec *r, char *url)
    return OK;
}

/* read available data (in blocks of CONN_BLKSZ) from c_i and copy to c_o */
static int proxy_connect_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
                                  apr_bucket_brigade *bb, char *name)
{
    int rv;
#ifdef DEBUGGING
    apr_off_t len;
#endif

    do {
        apr_brigade_cleanup(bb);
        rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
                            APR_NONBLOCK_READ, CONN_BLKSZ);
        if (rv == APR_SUCCESS) {
            if (c_o->aborted)
                return APR_EPIPE;
            if (APR_BRIGADE_EMPTY(bb))
                break;
#ifdef DEBUGGING
            len = -1;
            apr_brigade_length(bb, 0, &len);
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01016)
                          "read %" APR_OFF_T_FMT
                          " bytes from %s", len, name);
#endif
            rv = ap_pass_brigade(c_o->output_filters, bb);
            if (rv == APR_SUCCESS) {
                ap_fflush(c_o->output_filters, bb);
            }
            else {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01017)
                              "error on %s - ap_pass_brigade",
                              name);
            }
        } else if (!APR_STATUS_IS_EAGAIN(rv)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01018)
                          "error on %s - ap_get_brigade",
                          name);
        }
    } while (rv == APR_SUCCESS);

    if (APR_STATUS_IS_EAGAIN(rv)) {
        rv = APR_SUCCESS;
    }
    return rv;
}

/* CONNECT handler */
static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
                                 proxy_server_conf *conf,
@@ -205,7 +158,8 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
    conn_rec *backconn;
    int done = 0;

    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
    apr_bucket_brigade *bb_front = apr_brigade_create(p, c->bucket_alloc);
    apr_bucket_brigade *bb_back;
    apr_status_t rv;
    apr_size_t nbytes;
    char buffer[HUGE_STRING_LEN];
@@ -360,6 +314,9 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
    apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
                   backconn->local_addr->port));


    bb_back = apr_brigade_create(p, backconn->bucket_alloc);

    /* If we are connecting through a remote proxy, we need to pass
     * the CONNECT request on to it.
     */
@@ -368,24 +325,24 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
     */
        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
                      "sending the CONNECT request to the remote proxy");
        ap_fprintf(backconn->output_filters, bb,
        ap_fprintf(backconn->output_filters, bb_back,
                   "CONNECT %s HTTP/1.0" CRLF, r->uri);
        ap_fprintf(backconn->output_filters, bb,
        ap_fprintf(backconn->output_filters, bb_back,
                   "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner());
        ap_fflush(backconn->output_filters, bb);
        ap_fflush(backconn->output_filters, bb_back);
    }
    else {
        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Returning 200 OK");
        nbytes = apr_snprintf(buffer, sizeof(buffer),
                              "HTTP/1.0 200 Connection Established" CRLF);
        ap_xlate_proto_to_ascii(buffer, nbytes);
        ap_fwrite(c->output_filters, bb, buffer, nbytes);
        ap_fwrite(c->output_filters, bb_front, buffer, nbytes);
        nbytes = apr_snprintf(buffer, sizeof(buffer),
                              "Proxy-agent: %s" CRLF CRLF,
                              ap_get_server_banner());
        ap_xlate_proto_to_ascii(buffer, nbytes);
        ap_fwrite(c->output_filters, bb, buffer, nbytes);
        ap_fflush(c->output_filters, bb);
        ap_fwrite(c->output_filters, bb_front, buffer, nbytes);
        ap_fflush(c->output_filters, bb_front);
#if 0
        /* This is safer code, but it doesn't work yet.  I'm leaving it
         * here so that I can fix it later.
@@ -439,8 +396,12 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01025)
                                  "sock was readable");
#endif
                    done |= proxy_connect_transfer(r, backconn, c, bb,
                                                   "sock") != APR_SUCCESS;
                    done |= ap_proxy_transfer_between_connections(r, backconn,
                                                                  c, bb_back,
                                                                  bb_front,
                                                                  "sock", NULL,
                                                                  CONN_BLKSZ, 1)
                                                                 != APR_SUCCESS;
                }
                else if (pollevent & APR_POLLERR) {
                    ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026)
@@ -456,8 +417,14 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01027)
                                  "client was readable");
#endif
                    done |= proxy_connect_transfer(r, c, backconn, bb,
                                                   "client") != APR_SUCCESS;
                    done |= ap_proxy_transfer_between_connections(r, c,
                                                                  backconn,
                                                                  bb_front,
                                                                  bb_back,
                                                                  "client",
                                                                  NULL,
                                                                  CONN_BLKSZ, 1)
                                                                 != APR_SUCCESS;
                }
                else if (pollevent & APR_POLLERR) {
                    ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02827)
+1 −50
Original line number Diff line number Diff line
@@ -644,55 +644,6 @@ static int spool_reqbody_cl(apr_pool_t *p,
    return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1));
}

/*
 * Transform buckets from one bucket allocator to another one by creating a
 * transient bucket for each data bucket and let it use the data read from
 * the old bucket. Metabuckets are transformed by just recreating them.
 * Attention: Currently only the following bucket types are handled:
 *
 * All data buckets
 * FLUSH
 * EOS
 *
 * If an other bucket type is found its type is logged as a debug message
 * and APR_EGENERAL is returned.
 */
static apr_status_t proxy_buckets_lifetime_transform(request_rec *r,
        apr_bucket_brigade *from, apr_bucket_brigade *to)
{
    apr_bucket *e;
    apr_bucket *new;
    const char *data;
    apr_size_t bytes;
    apr_status_t rv = APR_SUCCESS;

    apr_brigade_cleanup(to);
    for (e = APR_BRIGADE_FIRST(from);
         e != APR_BRIGADE_SENTINEL(from);
         e = APR_BUCKET_NEXT(e)) {
        if (!APR_BUCKET_IS_METADATA(e)) {
            apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
            new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(to, new);
        }
        else if (APR_BUCKET_IS_FLUSH(e)) {
            new = apr_bucket_flush_create(r->connection->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(to, new);
        }
        else if (APR_BUCKET_IS_EOS(e)) {
            new = apr_bucket_eos_create(r->connection->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(to, new);
        }
        else {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964)
                          "Unhandled bucket type of type %s in"
                          " proxy_buckets_lifetime_transform", e->type->name);
            rv = APR_EGENERAL;
        }
    }
    return rv;
}

static
int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
                                   proxy_conn_rec *p_conn, proxy_worker *worker,
@@ -1779,7 +1730,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
                    }

                    /* Switch the allocator lifetime of the buckets */
                    proxy_buckets_lifetime_transform(r, bb, pass_bb);
                    ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);

                    /* found the last brigade? */
                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
+19 −60
Original line number Diff line number Diff line
@@ -89,61 +89,6 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
    return OK;
}


static apr_status_t proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
                                     apr_bucket_brigade *bb, char *name, int *sent)
{
    apr_status_t rv;
#ifdef DEBUGGING
    apr_off_t len;
#endif

    do {
        apr_brigade_cleanup(bb);
        rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
                            APR_NONBLOCK_READ, AP_IOBUFSIZE);
        if (rv == APR_SUCCESS) {
            if (c_o->aborted) {
                return APR_EPIPE;
            }
            if (APR_BRIGADE_EMPTY(bb)) {
                break;
            }
#ifdef DEBUGGING
            len = -1;
            apr_brigade_length(bb, 0, &len);
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02440)
                          "read %" APR_OFF_T_FMT
                          " bytes from %s", len, name);
#endif
            if (sent) {
                *sent = 1;
            }
            rv = ap_pass_brigade(c_o->output_filters, bb);
            if (rv == APR_SUCCESS) {
                ap_fflush(c_o->output_filters, bb);
            }
            else {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02441)
                              "error on %s - ap_pass_brigade",
                              name);
            }
        } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(02442)
                          "error on %s - ap_get_brigade",
                          name);
        }
    } while (rv == APR_SUCCESS);

    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, "wstunnel_transfer complete");

    if (APR_STATUS_IS_EAGAIN(rv)) {
        rv = APR_SUCCESS;
    }

    return rv;
}

/*
 * process the request and write the response.
 */
@@ -188,10 +133,12 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
    e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(header_brigade, e);

    if ((rv = ap_proxy_pass_brigade(c->bucket_alloc, r, conn, backconn,
    if ((rv = ap_proxy_pass_brigade(backconn->bucket_alloc, r, conn, backconn,
                                    header_brigade, 1)) != OK)
        return rv;

    apr_brigade_cleanup(header_brigade);

    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()");

    if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) {
@@ -248,8 +195,14 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
                if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446)
                                  "sock was readable");
                    done |= proxy_wstunnel_transfer(r, backconn, c, bb,
                                                    "sock", NULL) != APR_SUCCESS;
                    done |= ap_proxy_transfer_between_connections(r, backconn,
                                                                  c,
                                                                  header_brigade,
                                                                  bb, "sock",
                                                                  NULL,
                                                                  AP_IOBUFSIZE,
                                                                  0)
                                                                 != APR_SUCCESS;
                }
                else if (pollevent & APR_POLLERR) {
                    ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447)
@@ -268,8 +221,14 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
                if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448)
                                  "client was readable");
                    done |= proxy_wstunnel_transfer(r, c, backconn, bb,
                                                    "client", &replied) != APR_SUCCESS;
                    done |= ap_proxy_transfer_between_connections(r, c,
                                                                  backconn, bb,
                                                                  header_brigade,
                                                                  "client",
                                                                  &replied,
                                                                  AP_IOBUFSIZE,
                                                                  0)
                                                                 != APR_SUCCESS;
                }
                else if (pollevent & APR_POLLERR) {
                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607)
Loading