Skip to content

Commit

Permalink
v1.9.0 from Apache svn
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Eissing committed Feb 14, 2017
1 parent 3f7e2ec commit c47e682
Show file tree
Hide file tree
Showing 22 changed files with 1,450 additions and 1,602 deletions.
13 changes: 13 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
v1.9.0
--------------------------------------------------------------------------------
* not counting file buckets again stream max buffer limits.
Effectively transfering static files in one step from slave to master
connection.
* mod_http2: comforting ap_check_pipeline() on slave connections
to facilitate reuse (see https://github.com/icing/mod_h2/issues/128).
[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.

v1.8.11
--------------------------------------------------------------------------------
* regression fix on bugzilla PR 59348, on graceful restart, ongoing
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#

AC_PREREQ([2.69])
AC_INIT([mod_http2], [1.8.11], [[email protected]])
AC_INIT([mod_http2], [1.9.0], [[email protected]])

LT_PREREQ([2.2.6])
LT_INIT()
Expand Down
30 changes: 20 additions & 10 deletions mod_http2/h2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
113 changes: 53 additions & 60 deletions mod_http2/h2_bucket_beam.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
******************************************************************************/
Expand All @@ -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;
Expand Down Expand Up @@ -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 *))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -919,7 +906,6 @@ apr_status_t h2_beam_receive(h2_bucket_beam *beam,
}

/* 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)) {
Expand Down Expand Up @@ -1025,14 +1011,15 @@ apr_status_t h2_beam_receive(h2_bucket_beam *beam,
for (brecv = APR_BRIGADE_FIRST(bb);
brecv != APR_BRIGADE_SENTINEL(bb);
brecv = APR_BUCKET_NEXT(brecv)) {
remain -= brecv->length;
if (remain < 0) {
apr_bucket_split(brecv, brecv->length+remain);
beam->recv_buffer = apr_brigade_split_ex(bb,
APR_BUCKET_NEXT(brecv),
beam->recv_buffer);
break;
}
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,
APR_BUCKET_NEXT(brecv),
beam->recv_buffer);
break;
}
}
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
}


26 changes: 13 additions & 13 deletions mod_http2/h2_bucket_beam.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
******************************************************************************/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
2 changes: 1 addition & 1 deletion mod_http2/h2_bucket_eos.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
26 changes: 15 additions & 11 deletions mod_http2/h2_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,18 +204,21 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
{
apr_status_t status;
int mpm_state = 0;
h2_session *session = h2_ctx_session_get(ctx);

ap_assert(session);
do {
if (c->cs) {
c->cs->sense = CONN_SENSE_DEFAULT;
c->cs->state = CONN_STATE_HANDLER;
}

status = h2_session_process(h2_ctx_session_get(ctx), async_mpm);
status = h2_session_process(session, async_mpm);

if (APR_STATUS_IS_EOF(status)) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, APLOGNO(03045)
"h2_session(%ld): process, closing conn", c->id);
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
H2_SSSN_LOG(APLOGNO(03045), session,
"process, closing conn"));
c->keepalive = AP_CONN_CLOSE;
}
else {
Expand Down Expand Up @@ -253,10 +256,11 @@ conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
apr_pool_t *pool;
conn_rec *c;
void *cfg;
module *mpm;

ap_assert(master);
ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, master,
"h2_conn(%ld): create slave", master->id);
"h2_stream(%ld-%d): create slave", master->id, slave_id);

/* We create a pool with its own allocator to be used for
* processing a request. This is the only way to have the processing
Expand All @@ -271,7 +275,8 @@ conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
if (c == NULL) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master,
APLOGNO(02913) "h2_task: creating conn");
APLOGNO(02913) "h2_session(%ld-%d): create slave",
master->id, slave_id);
return NULL;
}

Expand Down Expand Up @@ -304,21 +309,20 @@ conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
/* TODO: not all mpm modules have learned about slave connections yet.
* copy their config from master to slave.
*/
if (h2_conn_mpm_module()) {
cfg = ap_get_module_config(master->conn_config, h2_conn_mpm_module());
ap_set_module_config(c->conn_config, h2_conn_mpm_module(), cfg);
if ((mpm = h2_conn_mpm_module()) != NULL) {
cfg = ap_get_module_config(master->conn_config, mpm);
ap_set_module_config(c->conn_config, mpm, cfg);
}

ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
"h2_task: creating conn, master=%ld, sid=%ld, logid=%s",
master->id, c->id, c->log_id);
"h2_stream(%ld-%d): created slave", master->id, slave_id);
return c;
}

void h2_slave_destroy(conn_rec *slave)
{
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave,
"h2_slave_conn(%ld): destroy (task=%s)", slave->id,
"h2_stream(%s): destroy slave",
apr_table_get(slave->notes, H2_TASK_ID_NOTE));
apr_pool_destroy(slave->pool);
}
Expand Down
Loading

0 comments on commit c47e682

Please sign in to comment.