Loading CHANGES +3 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ Changes with Apache 2.4.19 *) mod_http2: fixes problem with wrong lifetime of file buckets on main connection. [Stefan Eissing] *) mod_http2: fixes incorrect denial of requests without :authority header. [Stefan Eissing] Loading modules/http2/h2_bucket_eoc.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ struct h2_session; /** End Of HTTP/2 SESSION (H2EOC) bucket */ extern const apr_bucket_type_t h2_bucket_type_eoc; #define H2_BUCKET_IS_H2EOC(e) (e->type == &h2_bucket_type_eoc) apr_bucket * h2_bucket_eoc_make(apr_bucket *b, struct h2_session *session); Loading modules/http2/h2_bucket_eos.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ struct h2_stream; /** End Of HTTP/2 STREAM (H2EOS) bucket */ extern const apr_bucket_type_t h2_bucket_type_eos; #define H2_BUCKET_IS_H2EOS(e) (e->type == &h2_bucket_type_eos) apr_bucket *h2_bucket_eos_make(apr_bucket *b, struct h2_stream *stream); Loading modules/http2/h2_conn.c +9 −6 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent, } apr_pool_create_ex(&pool, parent, NULL, allocator); apr_pool_tag(pool, "h2_slave_conn"); apr_allocator_owner_set(allocator, parent); apr_allocator_owner_set(allocator, pool); c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec)); if (c == NULL) { Loading Loading @@ -309,15 +309,18 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent, void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator) { apr_pool_t *parent; apr_allocator_t *allocator = apr_pool_allocator_get(slave->pool); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave, "h2_slave_conn(%ld): destroy (task=%s)", slave->id, apr_table_get(slave->notes, H2_TASK_ID_NOTE)); apr_pool_destroy(slave->pool); if (pallocator) { /* Attache the allocator to the parent pool and return it for * reuse, otherwise the own is still the slave pool and it will * get destroyed with it. */ parent = apr_pool_parent_get(slave->pool); if (pallocator && parent) { apr_allocator_owner_set(allocator, parent); *pallocator = allocator; } else { apr_allocator_destroy(allocator); } apr_pool_destroy(slave->pool); } modules/http2/h2_conn_io.c +143 −71 Original line number Diff line number Diff line Loading @@ -14,16 +14,18 @@ */ #include <assert.h> #include <apr_strings.h> #include <ap_mpm.h> #include <httpd.h> #include <http_core.h> #include <http_log.h> #include <http_connection.h> #include <http_request.h> #include "h2_private.h" #include "h2_bucket_eoc.h" #include "h2_bucket_eos.h" #include "h2_config.h" #include "h2_conn_io.h" #include "h2_h2.h" Loading @@ -43,14 +45,92 @@ * which seems to create less TCP packets overall */ #define WRITE_SIZE_MAX (TLS_DATA_MAX - 100) #define WRITE_BUFFER_SIZE (5*WRITE_SIZE_MAX) static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level, const char *tag, apr_bucket_brigade *bb) { char buffer[16 * 1024]; const char *line = "(null)"; apr_size_t bmax = sizeof(buffer)/sizeof(buffer[0]); int off = 0; apr_bucket *b; if (bb) { memset(buffer, 0, bmax--); for (b = APR_BRIGADE_FIRST(bb); bmax && (b != APR_BRIGADE_SENTINEL(bb)); b = APR_BUCKET_NEXT(b)) { if (APR_BUCKET_IS_METADATA(b)) { if (APR_BUCKET_IS_EOS(b)) { off += apr_snprintf(buffer+off, bmax-off, "eos "); } else if (APR_BUCKET_IS_FLUSH(b)) { off += apr_snprintf(buffer+off, bmax-off, "flush "); } else if (AP_BUCKET_IS_EOR(b)) { off += apr_snprintf(buffer+off, bmax-off, "eor "); } else if (H2_BUCKET_IS_H2EOC(b)) { off += apr_snprintf(buffer+off, bmax-off, "h2eoc "); } else if (H2_BUCKET_IS_H2EOS(b)) { off += apr_snprintf(buffer+off, bmax-off, "h2eos "); } else { off += apr_snprintf(buffer+off, bmax-off, "meta(unknown) "); } } else { const char *btype = "data"; if (APR_BUCKET_IS_FILE(b)) { btype = "file"; } else if (APR_BUCKET_IS_PIPE(b)) { btype = "pipe"; } else if (APR_BUCKET_IS_SOCKET(b)) { btype = "socket"; } else if (APR_BUCKET_IS_HEAP(b)) { btype = "heap"; } else if (APR_BUCKET_IS_TRANSIENT(b)) { btype = "transient"; } else if (APR_BUCKET_IS_IMMORTAL(b)) { btype = "immortal"; } #if APR_HAS_MMAP else if (APR_BUCKET_IS_MMAP(b)) { btype = "mmap"; } #endif else if (APR_BUCKET_IS_POOL(b)) { btype = "pool"; } off += apr_snprintf(buffer+off, bmax-off, "%s[%ld] ", btype, (long)(b->length == ((apr_size_t)-1)? -1 : b->length)); } } line = *buffer? buffer : "(empty)"; } /* Intentional no APLOGNO */ ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d)-%s: %s", c->id, stream_id, tag, line); } apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, const h2_config *cfg, apr_pool_t *pool) { io->connection = c; io->c = c; io->output = apr_brigade_create(pool, c->bucket_alloc); io->buflen = 0; io->is_tls = h2_h2_is_tls(c); Loading @@ -65,8 +145,9 @@ apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, } if (io->is_tls) { /* That is where we start with, * see https://issues.apache.org/jira/browse/TS-2503 */ /* This is what we start with, * see https://issues.apache.org/jira/browse/TS-2503 */ io->warmup_size = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE); io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS) * APR_USEC_PER_SEC); Loading @@ -79,9 +160,10 @@ apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, } if (APLOGctrace1(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io(%ld): init, buffering=%d, warmup_size=%ld, cd_secs=%f", io->connection->id, io->buffer_output, (long)io->warmup_size, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): init, buffering=%d, warmup_size=%ld, " "cd_secs=%f", io->c->id, io->buffer_output, (long)io->warmup_size, ((float)io->cooldown_usecs/APR_USEC_PER_SEC)); } Loading Loading @@ -110,16 +192,17 @@ static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) } ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_WRITE, c); status = apr_brigade_length(bb, 0, &bblen); if (status == APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03044) "h2_conn_io(%ld): pass_out brigade %ld bytes", c->id, (long)bblen); apr_brigade_length(bb, 0, &bblen); h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb); status = ap_pass_brigade(c->output_filters, bb); if (status == APR_SUCCESS && pctx->io) { pctx->io->bytes_written += (apr_size_t)bblen; pctx->io->last_write = apr_time_now(); } if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, APLOGNO(03044) "h2_conn_io(%ld): pass_out brigade %ld bytes", c->id, (long)bblen); } apr_brigade_cleanup(bb); return status; Loading @@ -141,17 +224,17 @@ static apr_status_t bucketeer_buffer(h2_conn_io *io) /* long time not written, reset write size */ io->write_size = WRITE_SIZE_INITIAL; io->bytes_written = 0; ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): timeout write size reset to %ld", (long)io->connection->id, (long)io->write_size); (long)io->c->id, (long)io->write_size); } else if (io->write_size < WRITE_SIZE_MAX && io->bytes_written >= io->warmup_size) { /* connection is hot, use max size */ io->write_size = WRITE_SIZE_MAX; ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): threshold reached, write size now %ld", (long)io->connection->id, (long)io->write_size); (long)io->c->id, (long)io->write_size); } bcount = (int)(remaining / io->write_size); Loading @@ -177,50 +260,41 @@ apr_status_t h2_conn_io_writeb(h2_conn_io *io, apr_bucket *b) return APR_SUCCESS; } static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force, int eoc) static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int flush, int eoc) { if (io->buflen > 0 || !APR_BRIGADE_EMPTY(io->output)) { pass_out_ctx ctx; apr_bucket *b; if (io->buflen == 0 && APR_BRIGADE_EMPTY(io->output)) { return APR_SUCCESS; } if (io->buflen > 0) { /* something in the buffer, put it in the output brigade */ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen); ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen); bucketeer_buffer(io); } if (force) { APR_BRIGADE_INSERT_TAIL(io->output, apr_bucket_flush_create(io->output->bucket_alloc)); if (flush) { b = apr_bucket_flush_create(io->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(io->output, b); } ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io: flush"); /* Send it out */ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: flush"); io->buflen = 0; ctx.c = io->connection; ctx.c = io->c; ctx.io = eoc? NULL : io; return pass_out(io->output, &ctx); /* no more access after this, as we might have flushed an EOC bucket * that de-allocated us all. */ } return APR_SUCCESS; } apr_status_t h2_conn_io_pass(h2_conn_io *io, int flush) { return h2_conn_io_flush_int(io, flush, 0); } apr_status_t h2_conn_io_flush(h2_conn_io *io) { /* make sure we always write a flush, even if our buffers are empty. * We want to flush not only our buffers, but alse ones further down * the connection filters. */ apr_bucket *b = apr_bucket_flush_create(io->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(io->output, b); return h2_conn_io_flush_int(io, 0, 0); return h2_conn_io_flush_int(io, 1, 0); } apr_status_t h2_conn_io_consider_pass(h2_conn_io *io) Loading @@ -228,20 +302,18 @@ apr_status_t h2_conn_io_consider_pass(h2_conn_io *io) apr_off_t len = 0; if (!APR_BRIGADE_EMPTY(io->output)) { apr_brigade_length(io->output, 0, &len); len = h2_brigade_mem_size(io->output); } len += io->buflen; if (len >= WRITE_BUFFER_SIZE) { return h2_conn_io_pass(io, 0); return h2_conn_io_flush_int(io, 1, 0); } return APR_SUCCESS; } apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, h2_session *session) { apr_bucket *b = h2_bucket_eoc_create(io->connection->bucket_alloc, session); APR_BRIGADE_INSERT_TAIL(io->output, b); b = apr_bucket_flush_create(io->connection->bucket_alloc); apr_bucket *b = h2_bucket_eoc_create(io->c->bucket_alloc, session); APR_BRIGADE_INSERT_TAIL(io->output, b); return h2_conn_io_flush_int(io, 0, 1); } Loading @@ -252,20 +324,20 @@ apr_status_t h2_conn_io_write(h2_conn_io *io, apr_status_t status = APR_SUCCESS; pass_out_ctx ctx; ctx.c = io->connection; ctx.c = io->c; ctx.io = io; if (io->bufsize > 0) { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: buffering %ld bytes", (long)length); if (!APR_BRIGADE_EMPTY(io->output)) { status = h2_conn_io_pass(io, 0); status = h2_conn_io_flush_int(io, 0, 0); } while (length > 0 && (status == APR_SUCCESS)) { apr_size_t avail = io->bufsize - io->buflen; if (avail <= 0) { h2_conn_io_pass(io, 0); status = h2_conn_io_flush_int(io, 0, 0); } else if (length > avail) { memcpy(io->buffer + io->buflen, buf, avail); Loading @@ -283,7 +355,7 @@ apr_status_t h2_conn_io_write(h2_conn_io *io, } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->c, "h2_conn_io: writing %ld bytes to brigade", (long)length); status = apr_brigade_write(io->output, pass_out, &ctx, buf, length); } Loading Loading
CHANGES +3 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ Changes with Apache 2.4.19 *) mod_http2: fixes problem with wrong lifetime of file buckets on main connection. [Stefan Eissing] *) mod_http2: fixes incorrect denial of requests without :authority header. [Stefan Eissing] Loading
modules/http2/h2_bucket_eoc.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ struct h2_session; /** End Of HTTP/2 SESSION (H2EOC) bucket */ extern const apr_bucket_type_t h2_bucket_type_eoc; #define H2_BUCKET_IS_H2EOC(e) (e->type == &h2_bucket_type_eoc) apr_bucket * h2_bucket_eoc_make(apr_bucket *b, struct h2_session *session); Loading
modules/http2/h2_bucket_eos.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ struct h2_stream; /** End Of HTTP/2 STREAM (H2EOS) bucket */ extern const apr_bucket_type_t h2_bucket_type_eos; #define H2_BUCKET_IS_H2EOS(e) (e->type == &h2_bucket_type_eos) apr_bucket *h2_bucket_eos_make(apr_bucket *b, struct h2_stream *stream); Loading
modules/http2/h2_conn.c +9 −6 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent, } apr_pool_create_ex(&pool, parent, NULL, allocator); apr_pool_tag(pool, "h2_slave_conn"); apr_allocator_owner_set(allocator, parent); apr_allocator_owner_set(allocator, pool); c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec)); if (c == NULL) { Loading Loading @@ -309,15 +309,18 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent, void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator) { apr_pool_t *parent; apr_allocator_t *allocator = apr_pool_allocator_get(slave->pool); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave, "h2_slave_conn(%ld): destroy (task=%s)", slave->id, apr_table_get(slave->notes, H2_TASK_ID_NOTE)); apr_pool_destroy(slave->pool); if (pallocator) { /* Attache the allocator to the parent pool and return it for * reuse, otherwise the own is still the slave pool and it will * get destroyed with it. */ parent = apr_pool_parent_get(slave->pool); if (pallocator && parent) { apr_allocator_owner_set(allocator, parent); *pallocator = allocator; } else { apr_allocator_destroy(allocator); } apr_pool_destroy(slave->pool); }
modules/http2/h2_conn_io.c +143 −71 Original line number Diff line number Diff line Loading @@ -14,16 +14,18 @@ */ #include <assert.h> #include <apr_strings.h> #include <ap_mpm.h> #include <httpd.h> #include <http_core.h> #include <http_log.h> #include <http_connection.h> #include <http_request.h> #include "h2_private.h" #include "h2_bucket_eoc.h" #include "h2_bucket_eos.h" #include "h2_config.h" #include "h2_conn_io.h" #include "h2_h2.h" Loading @@ -43,14 +45,92 @@ * which seems to create less TCP packets overall */ #define WRITE_SIZE_MAX (TLS_DATA_MAX - 100) #define WRITE_BUFFER_SIZE (5*WRITE_SIZE_MAX) static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level, const char *tag, apr_bucket_brigade *bb) { char buffer[16 * 1024]; const char *line = "(null)"; apr_size_t bmax = sizeof(buffer)/sizeof(buffer[0]); int off = 0; apr_bucket *b; if (bb) { memset(buffer, 0, bmax--); for (b = APR_BRIGADE_FIRST(bb); bmax && (b != APR_BRIGADE_SENTINEL(bb)); b = APR_BUCKET_NEXT(b)) { if (APR_BUCKET_IS_METADATA(b)) { if (APR_BUCKET_IS_EOS(b)) { off += apr_snprintf(buffer+off, bmax-off, "eos "); } else if (APR_BUCKET_IS_FLUSH(b)) { off += apr_snprintf(buffer+off, bmax-off, "flush "); } else if (AP_BUCKET_IS_EOR(b)) { off += apr_snprintf(buffer+off, bmax-off, "eor "); } else if (H2_BUCKET_IS_H2EOC(b)) { off += apr_snprintf(buffer+off, bmax-off, "h2eoc "); } else if (H2_BUCKET_IS_H2EOS(b)) { off += apr_snprintf(buffer+off, bmax-off, "h2eos "); } else { off += apr_snprintf(buffer+off, bmax-off, "meta(unknown) "); } } else { const char *btype = "data"; if (APR_BUCKET_IS_FILE(b)) { btype = "file"; } else if (APR_BUCKET_IS_PIPE(b)) { btype = "pipe"; } else if (APR_BUCKET_IS_SOCKET(b)) { btype = "socket"; } else if (APR_BUCKET_IS_HEAP(b)) { btype = "heap"; } else if (APR_BUCKET_IS_TRANSIENT(b)) { btype = "transient"; } else if (APR_BUCKET_IS_IMMORTAL(b)) { btype = "immortal"; } #if APR_HAS_MMAP else if (APR_BUCKET_IS_MMAP(b)) { btype = "mmap"; } #endif else if (APR_BUCKET_IS_POOL(b)) { btype = "pool"; } off += apr_snprintf(buffer+off, bmax-off, "%s[%ld] ", btype, (long)(b->length == ((apr_size_t)-1)? -1 : b->length)); } } line = *buffer? buffer : "(empty)"; } /* Intentional no APLOGNO */ ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d)-%s: %s", c->id, stream_id, tag, line); } apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, const h2_config *cfg, apr_pool_t *pool) { io->connection = c; io->c = c; io->output = apr_brigade_create(pool, c->bucket_alloc); io->buflen = 0; io->is_tls = h2_h2_is_tls(c); Loading @@ -65,8 +145,9 @@ apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, } if (io->is_tls) { /* That is where we start with, * see https://issues.apache.org/jira/browse/TS-2503 */ /* This is what we start with, * see https://issues.apache.org/jira/browse/TS-2503 */ io->warmup_size = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE); io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS) * APR_USEC_PER_SEC); Loading @@ -79,9 +160,10 @@ apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, } if (APLOGctrace1(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io(%ld): init, buffering=%d, warmup_size=%ld, cd_secs=%f", io->connection->id, io->buffer_output, (long)io->warmup_size, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): init, buffering=%d, warmup_size=%ld, " "cd_secs=%f", io->c->id, io->buffer_output, (long)io->warmup_size, ((float)io->cooldown_usecs/APR_USEC_PER_SEC)); } Loading Loading @@ -110,16 +192,17 @@ static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) } ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_WRITE, c); status = apr_brigade_length(bb, 0, &bblen); if (status == APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03044) "h2_conn_io(%ld): pass_out brigade %ld bytes", c->id, (long)bblen); apr_brigade_length(bb, 0, &bblen); h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb); status = ap_pass_brigade(c->output_filters, bb); if (status == APR_SUCCESS && pctx->io) { pctx->io->bytes_written += (apr_size_t)bblen; pctx->io->last_write = apr_time_now(); } if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, APLOGNO(03044) "h2_conn_io(%ld): pass_out brigade %ld bytes", c->id, (long)bblen); } apr_brigade_cleanup(bb); return status; Loading @@ -141,17 +224,17 @@ static apr_status_t bucketeer_buffer(h2_conn_io *io) /* long time not written, reset write size */ io->write_size = WRITE_SIZE_INITIAL; io->bytes_written = 0; ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): timeout write size reset to %ld", (long)io->connection->id, (long)io->write_size); (long)io->c->id, (long)io->write_size); } else if (io->write_size < WRITE_SIZE_MAX && io->bytes_written >= io->warmup_size) { /* connection is hot, use max size */ io->write_size = WRITE_SIZE_MAX; ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io(%ld): threshold reached, write size now %ld", (long)io->connection->id, (long)io->write_size); (long)io->c->id, (long)io->write_size); } bcount = (int)(remaining / io->write_size); Loading @@ -177,50 +260,41 @@ apr_status_t h2_conn_io_writeb(h2_conn_io *io, apr_bucket *b) return APR_SUCCESS; } static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force, int eoc) static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int flush, int eoc) { if (io->buflen > 0 || !APR_BRIGADE_EMPTY(io->output)) { pass_out_ctx ctx; apr_bucket *b; if (io->buflen == 0 && APR_BRIGADE_EMPTY(io->output)) { return APR_SUCCESS; } if (io->buflen > 0) { /* something in the buffer, put it in the output brigade */ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen); ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen); bucketeer_buffer(io); } if (force) { APR_BRIGADE_INSERT_TAIL(io->output, apr_bucket_flush_create(io->output->bucket_alloc)); if (flush) { b = apr_bucket_flush_create(io->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(io->output, b); } ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, "h2_conn_io: flush"); /* Send it out */ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: flush"); io->buflen = 0; ctx.c = io->connection; ctx.c = io->c; ctx.io = eoc? NULL : io; return pass_out(io->output, &ctx); /* no more access after this, as we might have flushed an EOC bucket * that de-allocated us all. */ } return APR_SUCCESS; } apr_status_t h2_conn_io_pass(h2_conn_io *io, int flush) { return h2_conn_io_flush_int(io, flush, 0); } apr_status_t h2_conn_io_flush(h2_conn_io *io) { /* make sure we always write a flush, even if our buffers are empty. * We want to flush not only our buffers, but alse ones further down * the connection filters. */ apr_bucket *b = apr_bucket_flush_create(io->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(io->output, b); return h2_conn_io_flush_int(io, 0, 0); return h2_conn_io_flush_int(io, 1, 0); } apr_status_t h2_conn_io_consider_pass(h2_conn_io *io) Loading @@ -228,20 +302,18 @@ apr_status_t h2_conn_io_consider_pass(h2_conn_io *io) apr_off_t len = 0; if (!APR_BRIGADE_EMPTY(io->output)) { apr_brigade_length(io->output, 0, &len); len = h2_brigade_mem_size(io->output); } len += io->buflen; if (len >= WRITE_BUFFER_SIZE) { return h2_conn_io_pass(io, 0); return h2_conn_io_flush_int(io, 1, 0); } return APR_SUCCESS; } apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, h2_session *session) { apr_bucket *b = h2_bucket_eoc_create(io->connection->bucket_alloc, session); APR_BRIGADE_INSERT_TAIL(io->output, b); b = apr_bucket_flush_create(io->connection->bucket_alloc); apr_bucket *b = h2_bucket_eoc_create(io->c->bucket_alloc, session); APR_BRIGADE_INSERT_TAIL(io->output, b); return h2_conn_io_flush_int(io, 0, 1); } Loading @@ -252,20 +324,20 @@ apr_status_t h2_conn_io_write(h2_conn_io *io, apr_status_t status = APR_SUCCESS; pass_out_ctx ctx; ctx.c = io->connection; ctx.c = io->c; ctx.io = io; if (io->bufsize > 0) { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->c, "h2_conn_io: buffering %ld bytes", (long)length); if (!APR_BRIGADE_EMPTY(io->output)) { status = h2_conn_io_pass(io, 0); status = h2_conn_io_flush_int(io, 0, 0); } while (length > 0 && (status == APR_SUCCESS)) { apr_size_t avail = io->bufsize - io->buflen; if (avail <= 0) { h2_conn_io_pass(io, 0); status = h2_conn_io_flush_int(io, 0, 0); } else if (length > avail) { memcpy(io->buffer + io->buflen, buf, avail); Loading @@ -283,7 +355,7 @@ apr_status_t h2_conn_io_write(h2_conn_io *io, } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->connection, ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->c, "h2_conn_io: writing %ld bytes to brigade", (long)length); status = apr_brigade_write(io->output, pass_out, &ctx, buf, length); } Loading