Commit 833fe55e authored by Stefan Eissing's avatar Stefan Eissing
Browse files

On the 2.4.x branch:

 Merged /httpd/httpd/trunk:r1784571,1785672,1785683,1786512,1786575-1786576
 mod_http2/mod_proxy_http2 backport



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1786582 13f79535-47bb-0310-9956-ffa450edef68
parent 0349aac5
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -2,6 +2,21 @@

Changes with Apache 2.4.26

  *) mod_http2: moving session cleanup to pre_close hook to avoid races with
     modules already shut down and slave connections still operating.
     [Stefan Eissing]

  *) mod_http2: stream timeouts now change to vhost values once the request
     is parsed and processing starts. Initial values are taken from base
     server or SNI host as before. [Stefan Eissing]
     
  *) mod_proxy_http2: fixed retry behaviour when frontend connection uses 
     http/1.1. [Stefan Eissing]
     
  *) mod_http2: separate mutex instances for each bucket beam, resulting in 
     less lock contention. input beams only created when necessary.
     [Stefan Eissing]
     
  *) mod_lua: Support for Lua 5.3

  *) mod_proxy_http2: support for ProxyPreserverHost directive. [Stefan Eissing]
+86 −41
Original line number Diff line number Diff line
@@ -195,6 +195,19 @@ static apr_bucket *h2_beam_bucket(h2_bucket_beam *beam,
 * bucket beam that can transport buckets across threads
 ******************************************************************************/

static void mutex_leave(void *ctx, apr_thread_mutex_t *lock)
{
    apr_thread_mutex_unlock(lock);
}

static apr_status_t mutex_enter(void *ctx, h2_beam_lock *pbl)
{
    h2_bucket_beam *beam = ctx;
    pbl->mutex = beam->lock;
    pbl->leave = mutex_leave;
    return apr_thread_mutex_lock(pbl->mutex);
}

static apr_status_t enter_yellow(h2_bucket_beam *beam, h2_beam_lock *pbl)
{
    h2_beam_mutex_enter *enter = beam->m_enter;
@@ -227,26 +240,37 @@ static apr_off_t bucket_mem_used(apr_bucket *b)
    }
}

static int report_consumption(h2_bucket_beam *beam)
static int report_consumption(h2_bucket_beam *beam, h2_beam_lock *pbl)
{
    int rv = 0;
    if (beam->cons_io_cb) { 
        beam->cons_io_cb(beam->cons_ctx, beam, beam->received_bytes
                         - beam->cons_bytes_reported);
    apr_off_t len = beam->received_bytes - beam->cons_bytes_reported;
    h2_beam_io_callback *cb = beam->cons_io_cb;
     
    if (cb) {
        void *ctx = beam->cons_ctx;
        
        if (pbl) leave_yellow(beam, pbl);
        cb(ctx, beam, len);
        if (pbl) enter_yellow(beam, pbl);
        rv = 1;
    }
    beam->cons_bytes_reported = beam->received_bytes;
    beam->cons_bytes_reported += len;
    return rv;
}

static void report_prod_io(h2_bucket_beam *beam, int force)
static void report_prod_io(h2_bucket_beam *beam, int force, h2_beam_lock *pbl)
{
    if (force || beam->prod_bytes_reported != beam->sent_bytes) {
        if (beam->prod_io_cb) { 
            beam->prod_io_cb(beam->prod_ctx, beam, beam->sent_bytes
                             - beam->prod_bytes_reported);
    apr_off_t len = beam->sent_bytes - beam->prod_bytes_reported;
    if (force || len > 0) {
        h2_beam_io_callback *cb = beam->prod_io_cb; 
        if (cb) {
            void *ctx = beam->prod_ctx;
            
            leave_yellow(beam, pbl);
            cb(ctx, beam, len);
            enter_yellow(beam, pbl);
        }
        beam->prod_bytes_reported = beam->sent_bytes;
        beam->prod_bytes_reported += len;
    }
}

@@ -293,10 +317,10 @@ static apr_size_t calc_space_left(h2_bucket_beam *beam)
static apr_status_t wait_cond(h2_bucket_beam *beam, apr_thread_mutex_t *lock)
{
    if (beam->timeout > 0) {
        return apr_thread_cond_timedwait(beam->m_cond, lock, beam->timeout);
        return apr_thread_cond_timedwait(beam->cond, lock, beam->timeout);
    }
    else {
        return apr_thread_cond_wait(beam->m_cond, lock);
        return apr_thread_cond_wait(beam->cond, lock);
    }
}

@@ -307,7 +331,7 @@ static apr_status_t r_wait_space(h2_bucket_beam *beam, apr_read_type_e block,
    while (!beam->aborted && *premain <= 0 
           && (block == APR_BLOCK_READ) && pbl->mutex) {
        apr_status_t status;
        report_prod_io(beam, 1);
        report_prod_io(beam, 1, pbl);
        status = wait_cond(beam, pbl->mutex);
        if (APR_STATUS_IS_TIMEUP(status)) {
            return status;
@@ -378,8 +402,8 @@ static void h2_beam_emitted(h2_bucket_beam *beam, h2_beam_proxy *proxy)
        if (!bl.mutex) {
            r_purge_sent(beam);
        }
        else if (beam->m_cond) {
            apr_thread_cond_broadcast(beam->m_cond);
        else if (beam->cond) {
            apr_thread_cond_broadcast(beam->cond);
        }
        leave_yellow(beam, &bl);
    }
@@ -399,8 +423,8 @@ static apr_status_t beam_close(h2_bucket_beam *beam)
{
    if (!beam->closed) {
        beam->closed = 1;
        if (beam->m_cond) {
            apr_thread_cond_broadcast(beam->m_cond);
        if (beam->cond) {
            apr_thread_cond_broadcast(beam->cond);
        }
    }
    return APR_SUCCESS;
@@ -445,7 +469,7 @@ static apr_status_t beam_send_cleanup(void *data)
    /* sender is going away, clear up all references to its memory */
    r_purge_sent(beam);
    h2_blist_cleanup(&beam->send_list);
    report_consumption(beam);
    report_consumption(beam, NULL);
    while (!H2_BPROXY_LIST_EMPTY(&beam->proxies)) {
        h2_beam_proxy *proxy = H2_BPROXY_LIST_FIRST(&beam->proxies);
        H2_BPROXY_REMOVE(proxy);
@@ -535,7 +559,8 @@ apr_status_t h2_beam_destroy(h2_bucket_beam *beam)
apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool, 
                            int id, const char *tag, 
                            h2_beam_owner_t owner,
                            apr_size_t max_buf_size)
                            apr_size_t max_buf_size,
                            apr_interval_time_t timeout)
{
    h2_bucket_beam *beam;
    apr_status_t status = APR_SUCCESS;
@@ -555,10 +580,17 @@ apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool,
    H2_BPROXY_LIST_INIT(&beam->proxies);
    beam->tx_mem_limits = 1;
    beam->max_buf_size = max_buf_size;
    apr_pool_pre_cleanup_register(pool, beam, beam_cleanup);
    beam->timeout = timeout;

    status = apr_thread_mutex_create(&beam->lock, APR_THREAD_MUTEX_DEFAULT, 
                                     pool);
    if (status == APR_SUCCESS) {
        status = apr_thread_cond_create(&beam->cond, pool);
        if (status == APR_SUCCESS) {
            apr_pool_pre_cleanup_register(pool, beam, beam_cleanup);
            *pbeam = beam;
    
        }
    }
    return status;
}

@@ -586,7 +618,6 @@ apr_size_t h2_beam_buffer_size_get(h2_bucket_beam *beam)

void h2_beam_mutex_set(h2_bucket_beam *beam, 
                       h2_beam_mutex_enter m_enter,
                       apr_thread_cond_t *cond,
                       void *m_ctx)
{
    h2_beam_lock bl;
@@ -594,11 +625,20 @@ void h2_beam_mutex_set(h2_bucket_beam *beam,
    if (enter_yellow(beam, &bl) == APR_SUCCESS) {
        beam->m_enter = m_enter;
        beam->m_ctx   = m_ctx;
        beam->m_cond  = cond;
        leave_yellow(beam, &bl);
    }
}

void h2_beam_mutex_enable(h2_bucket_beam *beam)
{
    h2_beam_mutex_set(beam, mutex_enter, beam);
}

void h2_beam_mutex_disable(h2_bucket_beam *beam)
{
    h2_beam_mutex_set(beam, NULL, NULL);
}

void h2_beam_timeout_set(h2_bucket_beam *beam, apr_interval_time_t timeout)
{
    h2_beam_lock bl;
@@ -630,10 +670,10 @@ void h2_beam_abort(h2_bucket_beam *beam)
            beam->aborted = 1;
            r_purge_sent(beam);
            h2_blist_cleanup(&beam->send_list);
            report_consumption(beam);
            report_consumption(beam, &bl);
        }
        if (beam->m_cond) {
            apr_thread_cond_broadcast(beam->m_cond);
        if (beam->cond) {
            apr_thread_cond_broadcast(beam->cond);
        }
        leave_yellow(beam, &bl);
    }
@@ -646,7 +686,7 @@ apr_status_t h2_beam_close(h2_bucket_beam *beam)
    if (enter_yellow(beam, &bl) == APR_SUCCESS) {
        r_purge_sent(beam);
        beam_close(beam);
        report_consumption(beam);
        report_consumption(beam, &bl);
        leave_yellow(beam, &bl);
    }
    return beam->aborted? APR_ECONNABORTED : APR_SUCCESS;
@@ -680,8 +720,8 @@ apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block)
                status = APR_EAGAIN;
                break;
            }
            if (beam->m_cond) {
                apr_thread_cond_broadcast(beam->m_cond);
            if (beam->cond) {
                apr_thread_cond_broadcast(beam->cond);
            }
            status = wait_cond(beam, bl.mutex);
        }
@@ -868,12 +908,12 @@ apr_status_t h2_beam_send(h2_bucket_beam *beam,
                b = APR_BRIGADE_FIRST(sender_bb);
                status = append_bucket(beam, b, block, &bl);
            }
            report_prod_io(beam, force_report);
            if (beam->m_cond) {
                apr_thread_cond_broadcast(beam->m_cond);
            report_prod_io(beam, force_report, &bl);
            if (beam->cond) {
                apr_thread_cond_broadcast(beam->cond);
            }
        }
        report_consumption(beam);
        report_consumption(beam, &bl);
        leave_yellow(beam, &bl);
    }
    return status;
@@ -940,6 +980,11 @@ transfer:
                                                    bb->p, bb->bucket_alloc);
                }
            }
            else if (bsender->length == 0) {
                APR_BUCKET_REMOVE(bsender);
                H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender);
                continue;
            }
            else if (APR_BUCKET_IS_FILE(bsender)) {
                /* This is set aside into the target brigade pool so that 
                 * any read operation messes with that pool and not 
@@ -1040,15 +1085,15 @@ transfer:
        }
        
        if (transferred) {
            if (beam->m_cond) {
                apr_thread_cond_broadcast(beam->m_cond);
            if (beam->cond) {
                apr_thread_cond_broadcast(beam->cond);
            }
            status = APR_SUCCESS;
        }
        else if (beam->closed) {
            status = APR_EOF;
        }
        else if (block == APR_BLOCK_READ && bl.mutex && beam->m_cond) {
        else if (block == APR_BLOCK_READ && bl.mutex && beam->cond) {
            status = wait_cond(beam, bl.mutex);
            if (status != APR_SUCCESS) {
                goto leave;
@@ -1056,8 +1101,8 @@ transfer:
            goto transfer;
        }
        else {
            if (beam->m_cond) {
                apr_thread_cond_broadcast(beam->m_cond);
            if (beam->cond) {
                apr_thread_cond_broadcast(beam->cond);
            }
            status = APR_EAGAIN;
        }
@@ -1198,7 +1243,7 @@ int h2_beam_report_consumption(h2_bucket_beam *beam)
    h2_beam_lock bl;
    int rv = 0;
    if (enter_yellow(beam, &bl) == APR_SUCCESS) {
        rv = report_consumption(beam);
        rv = report_consumption(beam, &bl);
        leave_yellow(beam, &bl);
    }
    return rv;
+8 −3
Original line number Diff line number Diff line
@@ -190,9 +190,10 @@ struct h2_bucket_beam {
    unsigned int close_sent : 1;
    unsigned int tx_mem_limits : 1; /* only memory size counts on transfers */

    struct apr_thread_mutex_t *lock;
    struct apr_thread_cond_t *cond;
    void *m_ctx;
    h2_beam_mutex_enter *m_enter;
    struct apr_thread_cond_t *m_cond;
    
    apr_off_t cons_bytes_reported;    /* amount of bytes reported as consumed */
    h2_beam_ev_callback *cons_ev_cb;
@@ -222,12 +223,14 @@ struct h2_bucket_beam {
 *                      the pool owner is using this beam for sending or receiving
 * @param buffer_size   maximum memory footprint of buckets buffered in beam, or
 *                      0 for no limitation
 * @param timeout       timeout for blocking operations
 */
apr_status_t h2_beam_create(h2_bucket_beam **pbeam,
                            apr_pool_t *pool, 
                            int id, const char *tag,
                            h2_beam_owner_t owner,  
                            apr_size_t buffer_size);
                            apr_size_t buffer_size,
                            apr_interval_time_t timeout);

/**
 * Destroys the beam immediately without cleanup.
@@ -315,9 +318,11 @@ apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block);

void h2_beam_mutex_set(h2_bucket_beam *beam, 
                       h2_beam_mutex_enter m_enter,
                       struct apr_thread_cond_t *cond,
                       void *m_ctx);

void h2_beam_mutex_enable(h2_bucket_beam *beam);
void h2_beam_mutex_disable(h2_bucket_beam *beam);

/** 
 * Set/get the timeout for blocking read/write operations. Only works
 * if a mutex has been set for the beam.
+26 −12
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ static module *h2_conn_mpm_module(void)
apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
{
    h2_session *session;
    apr_status_t status;
    
    if (!workers) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911) 
@@ -191,15 +192,16 @@ apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
    }
    
    if (r) {
        session = h2_session_rcreate(r, ctx, workers);
        status = h2_session_rcreate(&session, r, ctx, workers);
    }
    else {
        session = h2_session_create(c, ctx, workers);
        status = h2_session_create(&session, c, ctx, workers);
    }

    if (status == APR_SUCCESS) {
        h2_ctx_session_set(ctx, session);
    
    return APR_SUCCESS;
    }
    return status;
}

apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
@@ -235,7 +237,20 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
             && mpm_state != AP_MPMQ_STOPPING);
    
    if (c->cs) {
        switch (session->state) {
            case H2_SESSION_ST_INIT:
            case H2_SESSION_ST_CLEANUP:
            case H2_SESSION_ST_DONE:
            case H2_SESSION_ST_IDLE:
                c->cs->state = CONN_STATE_WRITE_COMPLETION;
                break;
            case H2_SESSION_ST_BUSY:
            case H2_SESSION_ST_WAIT:
            default:
                c->cs->state = CONN_STATE_HANDLER;
                break;
                
        }
    }
    
    return DONE;
@@ -243,13 +258,12 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)

apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
{
    apr_status_t status;
    
    status = h2_session_pre_close(h2_ctx_session_get(ctx), async_mpm);
    if (status == APR_SUCCESS) {
        return DONE; /* This is the same, right? */
    h2_session *session = h2_ctx_session_get(ctx);
    if (session) {
        apr_status_t status = h2_session_pre_close(session, async_mpm);
        return (status == APR_SUCCESS)? DONE : status;
    }
    return status;
    return DONE;
}

conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
+2 −1
Original line number Diff line number Diff line
@@ -652,6 +652,7 @@ int h2_h2_process_conn(conn_rec* c)
            status = h2_conn_setup(ctx, c, NULL);
            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
            if (status != APR_SUCCESS) {
                h2_ctx_clear(c);
                return status;
            }
        }
@@ -674,7 +675,7 @@ static int h2_h2_pre_close_conn(conn_rec *c)
    ctx = h2_ctx_get(c, 0);
    if (ctx) {
        /* If the session has been closed correctly already, we will not
         * fiond a h2_ctx here. The presence indicates that the session
         * find a h2_ctx here. The presence indicates that the session
         * is still ongoing. */
        return h2_conn_pre_close(ctx, c);
    }
Loading