Commit bc6ad1ef authored by Stefan Eissing's avatar Stefan Eissing
Browse files

On the 2.4.x branch:

merge of r1780598,1781304,1782875,1782944,1782958,1782975 from trunk



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

Changes with Apache 2.4.26

  *) mod_http2: not counting file buckets again stream max buffer limits. 
     Effectively transfering static files in one step from slave to master 
     connection. [Stefan Eissing]
    
  *) mod_http2: comforting ap_check_pipeline() on slave connections
     to facilitate reuse (see https://github.com/icing/mod_h2/issues/128).
     [Stefan Eissing, reported by Armin Abfalterer]
     
  *) mod_http2: http/2 streams now with state handling/transitions as defined
     in RFC7540. Stream cleanup/connection shutdown reworked to become easier
     to understand/maintain/debug. Added many asserts on state and cleanup 
     transitions. [Stefan Eissing]
     
  *) mod_auth_digest: Use an anonymous shared memory segment by default,
     preventing startup failure after unclean shutdown.  PR 54622.
     [Jan Kaluza]
+20 −10
Original line number Diff line number Diff line
@@ -80,22 +80,13 @@ typedef enum {
    H2_PUSH_FAST_LOAD,
} h2_push_policy;

typedef enum {
    H2_STREAM_ST_IDLE,
    H2_STREAM_ST_OPEN,
    H2_STREAM_ST_RESV_LOCAL,
    H2_STREAM_ST_RESV_REMOTE,
    H2_STREAM_ST_CLOSED_INPUT,
    H2_STREAM_ST_CLOSED_OUTPUT,
    H2_STREAM_ST_CLOSED,
} h2_stream_state_t;

typedef enum {
    H2_SESSION_ST_INIT,             /* send initial SETTINGS, etc. */
    H2_SESSION_ST_DONE,             /* finished, connection close */
    H2_SESSION_ST_IDLE,             /* nothing to write, expecting data inc */
    H2_SESSION_ST_BUSY,             /* read/write without stop */
    H2_SESSION_ST_WAIT,             /* waiting for tasks reporting back */
    H2_SESSION_ST_CLEANUP,          /* pool is being cleaned up */
} h2_session_state;

typedef struct h2_session_props {
@@ -108,6 +99,25 @@ typedef struct h2_session_props {
    unsigned int shutdown : 1;      /* if the final GOAWAY has been sent */
} h2_session_props;

typedef enum h2_stream_state_t {
    H2_SS_IDLE,
    H2_SS_RSVD_R,
    H2_SS_RSVD_L,
    H2_SS_OPEN,
    H2_SS_CLOSED_R,
    H2_SS_CLOSED_L,
    H2_SS_CLOSED,
    H2_SS_CLEANUP,
    H2_SS_MAX
} h2_stream_state_t;

typedef enum {
    H2_SEV_CLOSED_L,
    H2_SEV_CLOSED_R,
    H2_SEV_CANCELLED,
    H2_SEV_EOS_SENT
} h2_stream_event_t;


/* h2_request is the transformer of HTTP2 streams into HTTP/1.1 internal
 * format that will be fed to various httpd input filters to finally
+53 −60
Original line number Diff line number Diff line
@@ -191,34 +191,6 @@ static apr_bucket *h2_beam_bucket(h2_bucket_beam *beam,
}


apr_size_t h2_util_bl_print(char *buffer, apr_size_t bmax, 
                            const char *tag, const char *sep, 
                            h2_blist *bl)
{
    apr_size_t off = 0;
    const char *sp = "";
    apr_bucket *b;
    
    if (bl) {
        memset(buffer, 0, bmax--);
        off += apr_snprintf(buffer+off, bmax-off, "%s(", tag);
        for (b = H2_BLIST_FIRST(bl); 
             bmax && (b != H2_BLIST_SENTINEL(bl));
             b = APR_BUCKET_NEXT(b)) {
            
            off += h2_util_bucket_print(buffer+off, bmax-off, b, sp);
            sp = " ";
        }
        off += apr_snprintf(buffer+off, bmax-off, ")%s", sep);
    }
    else {
        off += apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
    }
    return off;
}



/*******************************************************************************
 * bucket beam that can transport buckets across threads
 ******************************************************************************/
@@ -244,6 +216,17 @@ static void leave_yellow(h2_bucket_beam *beam, h2_beam_lock *pbl)
    }
}

static apr_off_t bucket_mem_used(apr_bucket *b)
{
    if (APR_BUCKET_IS_FILE(b)) {
        return 0;
    }
    else {
        /* should all have determinate length */
        return b->length;
    }
}

static int report_consumption(h2_bucket_beam *beam)
{
    int rv = 0;
@@ -426,8 +409,10 @@ static apr_status_t beam_close(h2_bucket_beam *beam)
    return APR_SUCCESS;
}

static void beam_set_send_pool(h2_bucket_beam *beam, apr_pool_t *pool);
static void beam_set_recv_pool(h2_bucket_beam *beam, apr_pool_t *pool);
int h2_beam_is_closed(h2_bucket_beam *beam)
{
    return beam->closed;
}

static int pool_register(h2_bucket_beam *beam, apr_pool_t *pool, 
                         apr_status_t (*cleanup)(void *))
@@ -457,20 +442,6 @@ static apr_status_t beam_recv_cleanup(void *data)
    return APR_SUCCESS;
}

static void beam_set_recv_pool(h2_bucket_beam *beam, apr_pool_t *pool) 
{
    if (beam->recv_pool == pool || 
        (beam->recv_pool && pool 
         && apr_pool_is_ancestor(beam->recv_pool, pool))) {
        /* when receiver same or sub-pool of existing, stick
         * to the the pool we already have. */
        return;
    }
    pool_kill(beam, beam->recv_pool, beam_recv_cleanup);
    beam->recv_pool = pool;
    pool_register(beam, beam->recv_pool, beam_recv_cleanup);
}

static apr_status_t beam_send_cleanup(void *data)
{
    h2_bucket_beam *beam = data;
@@ -585,6 +556,7 @@ apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool,
    H2_BLIST_INIT(&beam->hold_list);
    H2_BLIST_INIT(&beam->purge_list);
    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);

@@ -683,6 +655,21 @@ apr_status_t h2_beam_close(h2_bucket_beam *beam)
    return beam->aborted? APR_ECONNABORTED : APR_SUCCESS;
}

apr_status_t h2_beam_leave(h2_bucket_beam *beam)
{
    h2_beam_lock bl;
    
    if (enter_yellow(beam, &bl) == APR_SUCCESS) {
        if (beam->recv_buffer && !APR_BRIGADE_EMPTY(beam->recv_buffer)) {
            apr_brigade_cleanup(beam->recv_buffer);
        }
        beam->aborted = 1;
        beam_close(beam);
        leave_yellow(beam, &bl);
    }
    return APR_SUCCESS;
}

apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block)
{
    apr_status_t status;
@@ -919,7 +906,6 @@ transfer:
        }

        /* transfer enough buckets from our receiver brigade, if we have one */
        beam_set_recv_pool(beam, bb->p);
        while (beam->recv_buffer
               && !APR_BRIGADE_EMPTY(beam->recv_buffer)
               && (readbytes <= 0 || remain >= 0)) {
@@ -1025,7 +1011,8 @@ transfer:
            for (brecv = APR_BRIGADE_FIRST(bb);
                 brecv != APR_BRIGADE_SENTINEL(bb);
                 brecv = APR_BUCKET_NEXT(brecv)) {
                 remain -= brecv->length;
                remain -= (beam->tx_mem_limits? bucket_mem_used(brecv) 
                           : brecv->length);
                if (remain < 0) {
                    apr_bucket_split(brecv, brecv->length+remain);
                    beam->recv_buffer = apr_brigade_split_ex(bb, 
@@ -1149,13 +1136,7 @@ apr_off_t h2_beam_get_mem_used(h2_bucket_beam *beam)
        for (b = H2_BLIST_FIRST(&beam->send_list); 
            b != H2_BLIST_SENTINEL(&beam->send_list);
            b = APR_BUCKET_NEXT(b)) {
            if (APR_BUCKET_IS_FILE(b)) {
                /* do not count */
            }
            else {
                /* should all have determinate length */
                l += b->length;
            }
            l += bucket_mem_used(b);
        }
        leave_yellow(beam, &bl);
    }
@@ -1229,3 +1210,15 @@ int h2_beam_report_consumption(h2_bucket_beam *beam)
    return 0;
}

void h2_beam_log(h2_bucket_beam *beam, conn_rec *c, int level, const char *msg)
{
    if (beam && APLOG_C_IS_LEVEL(c,level)) {
        ap_log_cerror(APLOG_MARK, level, 0, c, 
                      "beam(%ld-%d,%s,closed=%d,aborted=%d,empty=%d,buf=%ld): %s", 
                      c->id, beam->id, beam->tag, beam->closed, beam->aborted, 
                      h2_beam_empty(beam), (long)h2_beam_get_buffered(beam),
                      msg);
    }
}

+13 −13
Original line number Diff line number Diff line
@@ -51,19 +51,6 @@ typedef struct {
        APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link);	\
    } while (0)

/**
 * Print the buckets in the list into the buffer (type and lengths).
 * @param buffer the buffer to print into
 * @param bmax max number of characters to place in buffer, incl. trailing 0
 * @param tag tag string for this bucket list
 * @param sep separator to use
 * @param bl the bucket list to print
 * @return number of characters printed
 */
apr_size_t h2_util_bl_print(char *buffer, apr_size_t bmax, 
                            const char *tag, const char *sep, 
                            h2_blist *bl);

/*******************************************************************************
 * h2_bucket_beam
 ******************************************************************************/
@@ -201,6 +188,7 @@ struct h2_bucket_beam {
    unsigned int aborted : 1;
    unsigned int closed : 1;
    unsigned int close_sent : 1;
    unsigned int tx_mem_limits : 1; /* only memory size counts on transfers */

    void *m_ctx;
    h2_beam_mutex_enter *m_enter;
@@ -305,6 +293,16 @@ void h2_beam_abort(h2_bucket_beam *beam);
 */
apr_status_t h2_beam_close(h2_bucket_beam *beam);

/**
 * Receives leaves the beam, e.g. will no longer read. This will
 * interrupt any sender blocked writing and fail future send. 
 * 
 * Call from the receiver side only.
 */
apr_status_t h2_beam_leave(h2_bucket_beam *beam);

int h2_beam_is_closed(h2_bucket_beam *beam);

/**
 * Return APR_SUCCESS when all buckets in transit have been handled. 
 * When called with APR_BLOCK_READ and a mutex set, will wait until the green
@@ -401,4 +399,6 @@ typedef apr_bucket *h2_bucket_beamer(h2_bucket_beam *beam,

void h2_register_bucket_beamer(h2_bucket_beamer *beamer);

void h2_beam_log(h2_bucket_beam *beam, conn_rec *c, int level, const char *msg);

#endif /* h2_bucket_beam_h */
+1 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ static void bucket_destroy(void *data)
        }
        apr_bucket_free(h);
        if (stream) {
            h2_stream_eos_destroy(stream);
            h2_stream_dispatch(stream, H2_SEV_EOS_SENT);
        }
    }
}
Loading