Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:Update
apache2
apache2-mod_http2-1.11.0.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File apache2-mod_http2-1.11.0.patch of Package apache2
Index: httpd-2.4.23/modules/http2/h2_bucket_beam.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_bucket_beam.c 2018-10-02 09:36:09.215205659 +0200 +++ httpd-2.4.23/modules/http2/h2_bucket_beam.c 2018-10-02 09:36:09.239205784 +0200 @@ -673,7 +673,7 @@ apr_size_t h2_beam_buffer_size_get(h2_bu h2_beam_lock bl; apr_size_t buffer_size = 0; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { buffer_size = beam->max_buf_size; leave_yellow(beam, &bl); } @@ -706,7 +706,7 @@ void h2_beam_abort(h2_bucket_beam *beam) { h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { beam->aborted = 1; r_purge_sent(beam); h2_blist_cleanup(&beam->send_list); @@ -720,7 +720,7 @@ apr_status_t h2_beam_close(h2_bucket_bea { h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { r_purge_sent(beam); beam_close(beam); report_consumption(beam, &bl); @@ -733,7 +733,7 @@ apr_status_t h2_beam_leave(h2_bucket_bea { h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { recv_buffer_cleanup(beam, &bl); beam->aborted = 1; beam_close(beam); @@ -922,6 +922,7 @@ apr_status_t h2_beam_send(h2_bucket_beam while (!APR_BRIGADE_EMPTY(sender_bb) && APR_SUCCESS == rv) { if (space_left <= 0) { report_prod_io(beam, force_report, &bl); + r_purge_sent(beam); rv = wait_not_full(beam, block, &space_left, &bl); if (APR_SUCCESS != rv) { break; @@ -1173,7 +1174,7 @@ apr_off_t h2_beam_get_buffered(h2_bucket apr_off_t l = 0; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { for (b = H2_BLIST_FIRST(&beam->send_list); b != H2_BLIST_SENTINEL(&beam->send_list); b = APR_BUCKET_NEXT(b)) { @@ -1191,7 +1192,7 @@ apr_off_t h2_beam_get_mem_used(h2_bucket apr_off_t l = 0; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { for (b = H2_BLIST_FIRST(&beam->send_list); b != H2_BLIST_SENTINEL(&beam->send_list); b = APR_BUCKET_NEXT(b)) { @@ -1207,7 +1208,7 @@ int h2_beam_empty(h2_bucket_beam *beam) int empty = 1; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { empty = (H2_BLIST_EMPTY(&beam->send_list) && (!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer))); leave_yellow(beam, &bl); @@ -1220,7 +1221,7 @@ int h2_beam_holds_proxies(h2_bucket_beam int has_proxies = 1; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { has_proxies = !H2_BPROXY_LIST_EMPTY(&beam->proxies); leave_yellow(beam, &bl); } @@ -1232,7 +1233,7 @@ int h2_beam_was_received(h2_bucket_beam int happend = 0; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { happend = (beam->received_bytes > 0); leave_yellow(beam, &bl); } @@ -1244,7 +1245,7 @@ apr_size_t h2_beam_get_files_beamed(h2_b apr_size_t n = 0; h2_beam_lock bl; - if (enter_yellow(beam, &bl) == APR_SUCCESS) { + if (beam && enter_yellow(beam, &bl) == APR_SUCCESS) { n = beam->files_beamed; leave_yellow(beam, &bl); } Index: httpd-2.4.23/modules/http2/h2_config.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_config.c 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2_config.c 2018-10-02 09:36:09.239205784 +0200 @@ -603,6 +603,30 @@ static const char *h2_conf_set_early_hin return "value must be On or Off"; } +void h2_get_num_workers(server_rec *s, int *minw, int *maxw) +{ + int threads_per_child = 0; + const h2_config *config = h2_config_sget(s); + + *minw = h2_config_geti(config, H2_CONF_MIN_WORKERS); + *maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS); + ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child); + + if (*minw <= 0) { + *minw = threads_per_child; + } + if (*maxw <= 0) { + /* As a default, this seems to work quite well under mpm_event. + * For people enabling http2 under mpm_prefork, start 4 threads unless + * configured otherwise. People get unhappy if their http2 requests are + * blocking each other. */ + *maxw = 3 * (*minw) / 2; + if (*maxw < 4) { + *maxw = 4; + } + } +} + #define AP_END_CMD AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL) const command_rec h2_cmds[] = { Index: httpd-2.4.23/modules/http2/h2_config.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_config.h 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2_config.h 2018-10-02 09:36:09.239205784 +0200 @@ -94,6 +94,8 @@ const h2_config *h2_config_rget(request_ int h2_config_geti(const h2_config *conf, h2_config_var_t var); apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var); +void h2_get_num_workers(server_rec *s, int *minw, int *maxw); + void h2_config_init(apr_pool_t *pool); const struct h2_priority *h2_config_get_priority(const h2_config *conf, Index: httpd-2.4.23/modules/http2/h2_conn.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_conn.c 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2_conn.c 2018-10-02 09:36:09.239205784 +0200 @@ -126,18 +126,7 @@ apr_status_t h2_conn_child_init(apr_pool h2_config_init(pool); - minw = h2_config_geti(config, H2_CONF_MIN_WORKERS); - maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS); - if (minw <= 0) { - minw = max_threads_per_child; - } - if (maxw <= 0) { - /* As a default, this seems to work quite well under mpm_event. - * For people enabling http2 under mpm_prefork, start 4 threads unless - * configured otherwise. People get unhappy if their http2 requests are - * blocking each other. */ - maxw = H2MAX(3 * minw / 2, 4); - } + h2_get_num_workers(s, &minw, &maxw); idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS); ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, @@ -237,25 +226,24 @@ apr_status_t h2_conn_run(struct h2_ctx * } while (!async_mpm && c->keepalive == AP_CONN_KEEPALIVE && 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; + c->cs->state = CONN_STATE_WRITE_COMPLETION; break; - + case H2_SESSION_ST_CLEANUP: + case H2_SESSION_ST_DONE: + default: + c->cs->state = CONN_STATE_LINGER; + break; } } - - return DONE; + + return APR_SUCCESS; } apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c) @@ -325,8 +313,6 @@ conn_rec *h2_slave_create(conn_rec *mast c->log = NULL; c->log_id = apr_psprintf(pool, "%ld-%d", master->id, slave_id); - /* Simulate that we had already a request on this connection. */ - c->keepalives = 1; c->aborted = 0; /* We cannot install the master connection socket on the slaves, as * modules mess with timeouts/blocking of the socket, with @@ -361,6 +347,14 @@ void h2_slave_destroy(conn_rec *slave) apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd) { - return ap_run_pre_connection(slave, csd); + if (slave->keepalives == 0) { + /* Simulate that we had already a request on this connection. Some + * hooks trigger special behaviour when keepalives is 0. + * (Not necessarily in pre_connection, but later. Set it here, so it + * is in place.) */ + slave->keepalives = 1; + return ap_run_pre_connection(slave, csd); + } + return APR_SUCCESS; } Index: httpd-2.4.23/modules/http2/h2_filter.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_filter.c 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2_filter.c 2018-10-02 09:36:09.239205784 +0200 @@ -290,6 +290,8 @@ apr_bucket *h2_bucket_observer_beam(stru } static apr_status_t bbout(apr_bucket_brigade *bb, const char *fmt, ...) + __attribute__((format(printf,2,3))); +static apr_status_t bbout(apr_bucket_brigade *bb, const char *fmt, ...) { va_list args; apr_status_t rv; @@ -350,8 +352,8 @@ static int add_stream(h2_stream *stream, bbout(x->bb, " \"created\": %f,\n", ((double)stream->created)/APR_USEC_PER_SEC); bbout(x->bb, " \"flowIn\": %d,\n", flowIn); bbout(x->bb, " \"flowOut\": %d,\n", flowOut); - bbout(x->bb, " \"dataIn\": %"APR_UINT64_T_FMT",\n", stream->in_data_octets); - bbout(x->bb, " \"dataOut\": %"APR_UINT64_T_FMT"\n", stream->out_data_octets); + bbout(x->bb, " \"dataIn\": %"APR_OFF_T_FMT",\n", stream->in_data_octets); + bbout(x->bb, " \"dataOut\": %"APR_OFF_T_FMT"\n", stream->out_data_octets); bbout(x->bb, " }"); ++x->idx; @@ -521,6 +523,11 @@ int h2_filter_h2_status_handler(request_ r->clength = -1; r->chunked = 1; apr_table_unset(r->headers_out, "Content-Length"); + /* Discourage content-encodings */ + apr_table_unset(r->headers_out, "Content-Encoding"); + apr_table_setn(r->subprocess_env, "no-brotli", "1"); + apr_table_setn(r->subprocess_env, "no-gzip", "1"); + ap_set_content_type(r, "application/json"); apr_table_setn(r->notes, H2_FILTER_DEBUG_NOTE, "on"); Index: httpd-2.4.23/modules/http2/h2_from_h1.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_from_h1.c 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2_from_h1.c 2018-10-02 09:36:09.239205784 +0200 @@ -208,10 +208,18 @@ static h2_headers *create_response(h2_ta /* determine the protocol and whether we should use keepalives. */ ap_set_keepalive(r); - if (r->chunked) { + if (AP_STATUS_IS_HEADER_ONLY(r->status)) { + apr_table_unset(r->headers_out, "Transfer-Encoding"); apr_table_unset(r->headers_out, "Content-Length"); + r->content_type = r->content_encoding = NULL; + r->content_languages = NULL; + r->clength = r->chunked = 0; } - + else if (r->chunked) { + apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked"); + apr_table_unset(r->headers_out, "Content-Length"); + } + ctype = ap_make_content_type(r, r->content_type); if (ctype) { apr_table_setn(r->headers_out, "Content-Type", ctype); @@ -412,7 +420,7 @@ static apr_status_t pass_response(h2_tas h2_headers *response = h2_headers_create(parser->http_status, make_table(parser), - NULL, task->pool); + NULL, 0, task->pool); apr_brigade_cleanup(parser->tmp); b = h2_bucket_headers_create(task->c->bucket_alloc, response); APR_BRIGADE_INSERT_TAIL(parser->tmp, b); @@ -771,6 +779,10 @@ apr_status_t h2_filter_request_in(ap_fil APR_BUCKET_REMOVE(b); apr_bucket_destroy(b); ap_remove_input_filter(f); + + if (headers->raw_bytes && h2_task_logio_add_bytes_in) { + h2_task_logio_add_bytes_in(task->c, headers->raw_bytes); + } break; } } Index: httpd-2.4.23/modules/http2/h2.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2.h 2018-10-02 09:36:09.115205137 +0200 +++ httpd-2.4.23/modules/http2/h2.h 2018-10-02 09:36:09.239205784 +0200 @@ -50,6 +50,9 @@ extern const char *H2_MAGIC_TOKEN; /* Max data size to write so it fits inside a TLS record */ #define H2_DATA_CHUNK_SIZE ((16*1024) - 100 - 9) +/* Size of the frame header itself in HTTP/2 */ +#define H2_FRAME_HDR_LEN 9 + /* Maximum number of padding bytes in a frame, rfc7540 */ #define H2_MAX_PADLEN 256 /* Initial default window size, RFC 7540 ch. 6.5.2 */ @@ -136,6 +139,7 @@ struct h2_request { apr_time_t request_time; unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */ unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */ + apr_off_t raw_bytes; /* RAW network bytes that generated this request - if known. */ }; typedef struct h2_headers h2_headers; @@ -144,6 +148,7 @@ struct h2_headers { int status; apr_table_t *headers; apr_table_t *notes; + apr_off_t raw_bytes; /* RAW network bytes that generated this request - if known. */ }; typedef apr_status_t h2_io_data_cb(void *ctx, const char *data, apr_off_t len); Index: httpd-2.4.23/modules/http2/h2_h2.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_h2.c 2018-10-02 09:36:09.119205158 +0200 +++ httpd-2.4.23/modules/http2/h2_h2.c 2018-10-02 09:36:09.239205784 +0200 @@ -59,7 +59,6 @@ const char *H2_MAGIC_TOKEN = "PRI * HTTP /******************************************************************************* * The optional mod_ssl functions we need. */ -static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *opt_ssl_engine_disable; static APR_OPTIONAL_FN_TYPE(ssl_is_https) *opt_ssl_is_https; static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *opt_ssl_var_lookup; @@ -445,7 +444,6 @@ apr_status_t h2_h2_init(apr_pool_t *pool { (void)pool; ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "h2_h2, child_init"); - opt_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); opt_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); opt_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); @@ -636,10 +634,10 @@ int h2_h2_process_conn(conn_rec* c) } h2_ctx_protocol_set(ctx, h2_h2_is_tls(c)? "h2" : "h2c"); } - else { + else if (APLOGctrace2(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "h2_h2, not detected in %d bytes: %s", - (int)slen, s); + "h2_h2, not detected in %d bytes(base64): %s", + (int)slen, h2_util_base64url_encode(s, slen, c->pool)); } apr_brigade_destroy(temp); @@ -653,10 +651,11 @@ int h2_h2_process_conn(conn_rec* c) ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup"); if (status != APR_SUCCESS) { h2_ctx_clear(c); - return status; + return !OK; } } - return h2_conn_run(ctx, c); + h2_conn_run(ctx, c); + return OK; } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined"); Index: httpd-2.4.23/modules/http2/h2_headers.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_headers.c 2018-10-02 09:36:09.119205158 +0200 +++ httpd-2.4.23/modules/http2/h2_headers.c 2018-10-02 09:36:09.239205784 +0200 @@ -110,7 +110,8 @@ apr_bucket *h2_bucket_headers_beam(struc h2_headers *h2_headers_create(int status, apr_table_t *headers_in, - apr_table_t *notes, apr_pool_t *pool) + apr_table_t *notes, apr_off_t raw_bytes, + apr_pool_t *pool) { h2_headers *headers = apr_pcalloc(pool, sizeof(h2_headers)); headers->status = status; @@ -124,7 +125,7 @@ h2_headers *h2_headers_create(int status h2_headers *h2_headers_rcreate(request_rec *r, int status, apr_table_t *header, apr_pool_t *pool) { - h2_headers *headers = h2_headers_create(status, header, r->notes, pool); + h2_headers *headers = h2_headers_create(status, header, r->notes, 0, pool); if (headers->status == HTTP_FORBIDDEN) { const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden"); if (cause) { @@ -148,7 +149,7 @@ h2_headers *h2_headers_rcreate(request_r h2_headers *h2_headers_copy(apr_pool_t *pool, h2_headers *h) { return h2_headers_create(h->status, apr_table_copy(pool, h->headers), - apr_table_copy(pool, h->notes), pool); + apr_table_copy(pool, h->notes), h->raw_bytes, pool); } h2_headers *h2_headers_die(apr_status_t type, Index: httpd-2.4.23/modules/http2/h2_headers.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_headers.h 2018-10-02 09:36:09.119205158 +0200 +++ httpd-2.4.23/modules/http2/h2_headers.h 2018-10-02 09:36:09.239205784 +0200 @@ -40,10 +40,12 @@ apr_bucket *h2_bucket_headers_beam(struc * @param status the headers status * @param header the headers of the headers * @param notes the notes carried by the headers + * @param raw_bytes the raw network bytes (if known) used to transmit these * @param pool the memory pool to use */ h2_headers *h2_headers_create(int status, apr_table_t *header, - apr_table_t *notes, apr_pool_t *pool); + apr_table_t *notes, apr_off_t raw_bytes, + apr_pool_t *pool); /** * Create the headers from the given request_rec. Index: httpd-2.4.23/modules/http2/h2_mplx.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_mplx.c 2018-10-02 09:36:09.119205158 +0200 +++ httpd-2.4.23/modules/http2/h2_mplx.c 2018-10-02 09:36:09.239205784 +0200 @@ -285,34 +285,6 @@ static int output_consumed_signal(h2_mpl return 0; } -static void task_destroy(h2_mplx *m, h2_task *task) -{ - conn_rec *slave = NULL; - int reuse_slave = 0; - - slave = task->c; - - if (m->s->keep_alive_max == 0 || slave->keepalives < m->s->keep_alive_max) { - reuse_slave = ((m->spare_slaves->nelts < (m->limit_active * 3 / 2)) - && !task->rst_error); - } - - if (slave) { - if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) { - h2_beam_log(task->output.beam, m->c, APLOG_DEBUG, - APLOGNO(03385) "h2_task_destroy, reuse slave"); - h2_task_destroy(task); - APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave; - } - else { - h2_beam_log(task->output.beam, m->c, APLOG_TRACE1, - "h2_task_destroy, destroy slave"); - slave->sbh = NULL; - h2_slave_destroy(slave); - } - } -} - static int stream_destroy_iter(void *ctx, void *val) { h2_mplx *m = ctx; @@ -330,8 +302,42 @@ static int stream_destroy_iter(void *ctx } if (stream->task) { - task_destroy(m, stream->task); + h2_task *task = stream->task; + conn_rec *slave; + int reuse_slave = 0; + stream->task = NULL; + slave = task->c; + if (slave) { + /* On non-serialized requests, the IO logging has not accounted for any + * meta data send over the network: response headers and h2 frame headers. we + * counted this on the stream and need to add this now. + * This is supposed to happen before the EOR bucket triggers the + * logging of the transaction. *fingers crossed* */ + if (task->request && !task->request->serialize && h2_task_logio_add_bytes_out) { + apr_off_t unaccounted = stream->out_frame_octets - stream->out_data_octets; + if (unaccounted > 0) { + h2_task_logio_add_bytes_out(slave, unaccounted); + } + } + + if (m->s->keep_alive_max == 0 || slave->keepalives < m->s->keep_alive_max) { + reuse_slave = ((m->spare_slaves->nelts < (m->limit_active * 3 / 2)) + && !task->rst_error); + } + + if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) { + h2_beam_log(task->output.beam, m->c, APLOG_DEBUG, + APLOGNO(03385) "h2_task_destroy, reuse slave"); + h2_task_destroy(task); + APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave; + } + else { + h2_beam_log(task->output.beam, m->c, APLOG_TRACE1, + "h2_task_destroy, destroy slave"); + h2_slave_destroy(slave); + } + } } h2_stream_destroy(stream); return 0; @@ -377,11 +383,12 @@ static int report_stream_iter(void *ctx, h2_mplx *m = ctx; h2_stream *stream = val; h2_task *task = stream->task; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c, - H2_STRM_MSG(stream, "started=%d, scheduled=%d, ready=%d, " - "out_buffer=%ld"), - !!stream->task, stream->scheduled, h2_stream_is_ready(stream), - (long)h2_beam_get_buffered(stream->output)); + if (APLOGctrace1(m->c)) { + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c, + H2_STRM_MSG(stream, "started=%d, scheduled=%d, ready=%d, out_buffer=%ld"), + !!stream->task, stream->scheduled, h2_stream_is_ready(stream), + (long)h2_beam_get_buffered(stream->output)); + } if (task) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, /* NO APLOGNO */ H2_STRM_MSG(stream, "->03198: %s %s %s" Index: httpd-2.4.23/modules/http2/h2_proxy_util.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_proxy_util.c 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_proxy_util.c 2018-10-02 09:36:09.243205805 +0200 @@ -915,8 +915,8 @@ static size_t subst_str(link_ctx *ctx, i delta = nlen - olen; plen = ctx->slen + delta + 1; p = apr_pcalloc(ctx->pool, plen); - strncpy(p, ctx->s, start); - strncpy(p + start, ns, nlen); + memcpy(p, ctx->s, start); + memcpy(p + start, ns, nlen); strcpy(p + start + nlen, ctx->s + end); ctx->s = p; ctx->slen = (int)strlen(p); @@ -942,7 +942,7 @@ static void map_link(link_ctx *ctx) /* common to use relative uris in link header, for mappings * to work need to prefix the backend server uri */ need_len += ctx->psu_len; - strncpy(buffer, ctx->p_server_uri, sizeof(buffer)); + apr_cpystrn(buffer, ctx->p_server_uri, sizeof(buffer)); buffer_len = ctx->psu_len; } if (need_len > sizeof(buffer)) { @@ -950,9 +950,7 @@ static void map_link(link_ctx *ctx) "link_reverse_map uri too long, skipped: %s", ctx->s); return; } - strncpy(buffer + buffer_len, ctx->s + ctx->link_start, link_len); - buffer_len += link_len; - buffer[buffer_len] = '\0'; + apr_cpystrn(buffer + buffer_len, ctx->s + ctx->link_start, link_len + 1); if (!prepend_p_server && strcmp(ctx->real_backend_uri, ctx->p_server_uri) && !strncmp(buffer, ctx->real_backend_uri, ctx->rbu_len)) { @@ -960,8 +958,8 @@ static void map_link(link_ctx *ctx) * to work, we need to use the proxy uri */ int path_start = ctx->link_start + ctx->rbu_len; link_len -= ctx->rbu_len; - strcpy(buffer, ctx->p_server_uri); - strncpy(buffer + ctx->psu_len, ctx->s + path_start, link_len); + memcpy(buffer, ctx->p_server_uri, ctx->psu_len); + memcpy(buffer + ctx->psu_len, ctx->s + path_start, link_len); buffer_len = ctx->psu_len + link_len; buffer[buffer_len] = '\0'; } Index: httpd-2.4.23/modules/http2/h2_push.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_push.c 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_push.c 2018-10-02 09:36:09.243205805 +0200 @@ -351,7 +351,7 @@ static int add_push(link_ctx *ctx) ctx->req->authority, path, headers, ctx->req->serialize); /* atm, we do not push on pushes */ - h2_request_end_headers(req, ctx->pool, 1); + h2_request_end_headers(req, ctx->pool, 1, 0); push->req = req; if (has_param(ctx, "critical")) { h2_priority *prio = apr_pcalloc(ctx->pool, sizeof(*prio)); Index: httpd-2.4.23/modules/http2/h2_request.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_request.c 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_request.c 2018-10-02 09:36:09.243205805 +0200 @@ -149,7 +149,7 @@ apr_status_t h2_request_add_header(h2_re return status; } -apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos) +apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos, size_t raw_bytes) { const char *s; @@ -189,7 +189,8 @@ apr_status_t h2_request_end_headers(h2_r apr_table_setn(req->headers, "Content-Length", "0"); } } - + req->raw_bytes += raw_bytes; + return APR_SUCCESS; } Index: httpd-2.4.23/modules/http2/h2_request.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_request.h 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_request.h 2018-10-02 09:36:09.243205805 +0200 @@ -29,7 +29,7 @@ apr_status_t h2_request_add_trailer(h2_r const char *name, size_t nlen, const char *value, size_t vlen); -apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos); +apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos, size_t raw_bytes); h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src); Index: httpd-2.4.23/modules/http2/h2_session.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_session.c 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_session.c 2018-10-02 09:36:09.243205805 +0200 @@ -234,6 +234,7 @@ static int on_data_chunk_recv_cb(nghttp2 stream = h2_session_stream_get(session, stream_id); if (stream) { status = h2_stream_recv_DATA(stream, flags, data, len); + dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, "stream data rcvd"); } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03064) @@ -316,9 +317,9 @@ static int on_header_cb(nghttp2_session } /** - * nghttp2 session has received a complete frame. Most, it uses - * for processing of internal state. HEADER and DATA frames however - * we need to handle ourself. + * nghttp2 session has received a complete frame. Most are used by nghttp2 + * for processing of internal state. Some, like HEADER and DATA frames, + * we need to act on. */ static int on_frame_recv_cb(nghttp2_session *ng2s, const nghttp2_frame *frame, @@ -347,7 +348,8 @@ static int on_frame_recv_cb(nghttp2_sess * trailers */ stream = h2_session_stream_get(session, frame->hd.stream_id); if (stream) { - rv = h2_stream_recv_frame(stream, NGHTTP2_HEADERS, frame->hd.flags); + rv = h2_stream_recv_frame(stream, NGHTTP2_HEADERS, frame->hd.flags, + frame->hd.length + H2_FRAME_HDR_LEN); } break; case NGHTTP2_DATA: @@ -357,7 +359,8 @@ static int on_frame_recv_cb(nghttp2_sess H2_STRM_LOG(APLOGNO(02923), stream, "DATA, len=%ld, flags=%d"), (long)frame->hd.length, frame->hd.flags); - rv = h2_stream_recv_frame(stream, NGHTTP2_DATA, frame->hd.flags); + rv = h2_stream_recv_frame(stream, NGHTTP2_DATA, frame->hd.flags, + frame->hd.length + H2_FRAME_HDR_LEN); } break; case NGHTTP2_PRIORITY: @@ -375,6 +378,9 @@ static int on_frame_recv_cb(nghttp2_sess "h2_stream(%ld-%d): WINDOW_UPDATE incr=%d", session->id, (int)frame->hd.stream_id, frame->window_update.window_size_increment); + if (nghttp2_session_want_write(session->ngh2)) { + dispatch_event(session, H2_SESSION_EV_FRAME_RCVD, 0, "window update"); + } break; case NGHTTP2_RST_STREAM: ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03067) @@ -401,6 +407,12 @@ static int on_frame_recv_cb(nghttp2_sess frame->goaway.error_code, NULL); } break; + case NGHTTP2_SETTINGS: + if (APLOGctrace2(session->c)) { + ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, + H2_SSSN_MSG(session, "SETTINGS, len=%ld"), (long)frame->hd.length); + } + break; default: if (APLOGctrace2(session->c)) { char buffer[256]; @@ -412,7 +424,40 @@ static int on_frame_recv_cb(nghttp2_sess } break; } - return (APR_SUCCESS == rv)? 0 : NGHTTP2_ERR_PROTO; + + if (session->state == H2_SESSION_ST_IDLE) { + /* We received a frame, but session is in state IDLE. That means the frame + * did not really progress any of the (possibly) open streams. It was a meta + * frame, e.g. SETTINGS/WINDOW_UPDATE/unknown/etc. + * Remember: IDLE means we cannot send because either there are no streams open or + * all open streams are blocked on exhausted WINDOWs for outgoing data. + * The more frames we receive that do not change this, the less interested we + * become in serving this connection. This is expressed in increasing "idle_delays". + * Eventually, the connection will timeout and we'll close it. */ + session->idle_frames = H2MIN(session->idle_frames + 1, session->frames_received); + ap_log_cerror( APLOG_MARK, APLOG_TRACE2, 0, session->c, + H2_SSSN_MSG(session, "session has %ld idle frames"), + (long)session->idle_frames); + if (session->idle_frames > 10) { + apr_size_t busy_frames = H2MAX(session->frames_received - session->idle_frames, 1); + int idle_ratio = (int)(session->idle_frames / busy_frames); + if (idle_ratio > 100) { + session->idle_delay = apr_time_from_msec(H2MIN(1000, idle_ratio)); + } + else if (idle_ratio > 10) { + session->idle_delay = apr_time_from_msec(10); + } + else if (idle_ratio > 1) { + session->idle_delay = apr_time_from_msec(1); + } + else { + session->idle_delay = 0; + } + } + } + + if (APR_SUCCESS != rv) return NGHTTP2_ERR_PROTO; + return 0; } static int h2_session_continue_data(h2_session *session) { @@ -545,7 +590,8 @@ static int on_frame_send_cb(nghttp2_sess stream = h2_session_stream_get(session, stream_id); if (stream) { - h2_stream_send_frame(stream, frame->hd.type, frame->hd.flags); + h2_stream_send_frame(stream, frame->hd.type, frame->hd.flags, + frame->hd.length + H2_FRAME_HDR_LEN); } return 0; } @@ -1599,23 +1645,57 @@ static void update_child_status(h2_sessi static void transit(h2_session *session, const char *action, h2_session_state nstate) { + apr_time_t timeout; + int ostate, loglvl; + const char *s; + if (session->state != nstate) { - int loglvl = APLOG_DEBUG; - if ((session->state == H2_SESSION_ST_BUSY && nstate == H2_SESSION_ST_WAIT) - || (session->state == H2_SESSION_ST_WAIT && nstate == H2_SESSION_ST_BUSY)){ + ostate = session->state; + session->state = nstate; + + loglvl = APLOG_DEBUG; + if ((ostate == H2_SESSION_ST_BUSY && nstate == H2_SESSION_ST_WAIT) + || (ostate == H2_SESSION_ST_WAIT && nstate == H2_SESSION_ST_BUSY)){ loglvl = APLOG_TRACE1; } ap_log_cerror(APLOG_MARK, loglvl, 0, session->c, H2_SSSN_LOG(APLOGNO(03078), session, "transit [%s] -- %s --> [%s]"), - h2_session_state_str(session->state), action, + h2_session_state_str(ostate), action, h2_session_state_str(nstate)); - session->state = nstate; + switch (session->state) { case H2_SESSION_ST_IDLE: - update_child_status(session, (session->open_streams == 0? - SERVER_BUSY_KEEPALIVE - : SERVER_BUSY_READ), "idle"); + if (!session->remote.emitted_count) { + /* on fresh connections, with async mpm, do not return + * to mpm for a second. This gives the first request a better + * chance to arrive (und connection leaving IDLE state). + * If we return to mpm right away, this connection has the + * same chance of being cleaned up by the mpm as connections + * that already served requests - not fair. */ + session->idle_sync_until = apr_time_now() + apr_time_from_sec(1); + s = "timeout"; + timeout = H2MAX(session->s->timeout, session->s->keep_alive_timeout); + update_child_status(session, SERVER_BUSY_READ, "idle"); + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c, + H2_SSSN_LOG("", session, "enter idle, timeout = %d sec"), + (int)apr_time_sec(H2MAX(session->s->timeout, session->s->keep_alive_timeout))); + } + else if (session->open_streams) { + s = "timeout"; + timeout = session->s->keep_alive_timeout; + update_child_status(session, SERVER_BUSY_KEEPALIVE, "idle"); + } + else { + /* normal keepalive setup */ + s = "keepalive"; + timeout = session->s->keep_alive_timeout; + update_child_status(session, SERVER_BUSY_KEEPALIVE, "idle"); + } + session->idle_until = apr_time_now() + timeout; + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c, + H2_SSSN_LOG("", session, "enter idle, %s = %d sec"), + s, (int)apr_time_sec(timeout)); break; case H2_SESSION_ST_DONE: update_child_status(session, SERVER_CLOSING, "done"); @@ -1722,8 +1802,6 @@ static void h2_session_ev_no_io(h2_sessi * This means we only wait for WINDOW_UPDATE from the * client and can block on READ. */ transit(session, "no io (flow wait)", H2_SESSION_ST_IDLE); - session->idle_until = apr_time_now() + session->s->timeout; - session->keep_sync_until = session->idle_until; /* Make sure we have flushed all previously written output * so that the client will react. */ if (h2_conn_io_flush(&session->io) != APR_SUCCESS) { @@ -1734,12 +1812,7 @@ static void h2_session_ev_no_io(h2_sessi } else if (session->local.accepting) { /* When we have no streams, but accept new, switch to idle */ - apr_time_t now = apr_time_now(); transit(session, "no io (keepalive)", H2_SESSION_ST_IDLE); - session->idle_until = (session->remote.emitted_count? - session->s->keep_alive_timeout : - session->s->timeout) + now; - session->keep_sync_until = now + apr_time_from_sec(1); } else { /* We are no longer accepting new streams and there are @@ -1754,12 +1827,25 @@ static void h2_session_ev_no_io(h2_sessi } } -static void h2_session_ev_data_read(h2_session *session, int arg, const char *msg) +static void h2_session_ev_frame_rcvd(h2_session *session, int arg, const char *msg) +{ + switch (session->state) { + case H2_SESSION_ST_IDLE: + case H2_SESSION_ST_WAIT: + transit(session, "frame received", H2_SESSION_ST_BUSY); + break; + default: + /* nop */ + break; + } +} + +static void h2_session_ev_stream_change(h2_session *session, int arg, const char *msg) { switch (session->state) { case H2_SESSION_ST_IDLE: case H2_SESSION_ST_WAIT: - transit(session, "data read", H2_SESSION_ST_BUSY); + transit(session, "stream change", H2_SESSION_ST_BUSY); break; default: /* nop */ @@ -1799,16 +1885,6 @@ static void h2_session_ev_pre_close(h2_s static void ev_stream_open(h2_session *session, h2_stream *stream) { h2_iq_append(session->in_process, stream->id); - switch (session->state) { - case H2_SESSION_ST_IDLE: - if (session->open_streams == 1) { - /* enter timeout, since we have a stream again */ - session->idle_until = (session->s->timeout + apr_time_now()); - } - break; - default: - break; - } } static void ev_stream_closed(h2_session *session, h2_stream *stream) @@ -1821,11 +1897,6 @@ static void ev_stream_closed(h2_session } switch (session->state) { case H2_SESSION_ST_IDLE: - if (session->open_streams == 0) { - /* enter keepalive timeout, since we no longer have streams */ - session->idle_until = (session->s->keep_alive_timeout - + apr_time_now()); - } break; default: break; @@ -1883,6 +1954,7 @@ static void on_stream_state_enter(void * default: break; } + dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, "stream state change"); } static void on_stream_event(void *ctx, h2_stream *stream, @@ -1941,8 +2013,8 @@ static void dispatch_event(h2_session *s case H2_SESSION_EV_NO_IO: h2_session_ev_no_io(session, arg, msg); break; - case H2_SESSION_EV_DATA_READ: - h2_session_ev_data_read(session, arg, msg); + case H2_SESSION_EV_FRAME_RCVD: + h2_session_ev_frame_rcvd(session, arg, msg); break; case H2_SESSION_EV_NGH2_DONE: h2_session_ev_ngh2_done(session, arg, msg); @@ -1953,6 +2025,9 @@ static void dispatch_event(h2_session *s case H2_SESSION_EV_PRE_CLOSE: h2_session_ev_pre_close(session, arg, msg); break; + case H2_SESSION_EV_STREAM_CHANGE: + h2_session_ev_stream_change(session, arg, msg); + break; default: ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c, H2_SSSN_MSG(session, "unknown event %d"), ev); @@ -1986,13 +2061,15 @@ apr_status_t h2_session_process(h2_sessi apr_status_t status = APR_SUCCESS; conn_rec *c = session->c; int rv, mpm_state, trace = APLOGctrace3(c); - + apr_time_t now; + if (trace) { ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c, H2_SSSN_MSG(session, "process start, async=%d"), async); } while (session->state != H2_SESSION_ST_DONE) { + now = apr_time_now(); session->have_read = session->have_written = 0; if (session->local.accepting @@ -2030,39 +2107,42 @@ apr_status_t h2_session_process(h2_sessi break; case H2_SESSION_ST_IDLE: - /* We trust our connection into the default timeout/keepalive - * handling of the core filters/mpm iff: - * - keep_sync_until is not set - * - we have an async mpm - * - we have no open streams to process - * - we are not sitting on a Upgrade: request - * - we already have seen at least one request - */ - if (!session->keep_sync_until && async && !session->open_streams - && !session->r && session->remote.emitted_count) { + if (session->idle_until && (apr_time_now() + session->idle_delay) > session->idle_until) { + ap_log_cerror( APLOG_MARK, APLOG_TRACE1, status, c, + H2_SSSN_MSG(session, "idle, timeout reached, closing")); + if (session->idle_delay) { + apr_table_setn(session->c->notes, "short-lingering-close", "1"); + } + dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout"); + goto out; + } + + if (session->idle_delay) { + /* we are less interested in spending time on this connection */ + ap_log_cerror( APLOG_MARK, APLOG_TRACE2, status, c, + H2_SSSN_MSG(session, "session is idle (%ld ms), idle wait %ld sec left"), + (long)apr_time_as_msec(session->idle_delay), + (long)apr_time_sec(session->idle_until - now)); + apr_sleep(session->idle_delay); + session->idle_delay = 0; + } + + h2_conn_io_flush(&session->io); + if (async && !session->r && (now > session->idle_sync_until)) { if (trace) { ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, H2_SSSN_MSG(session, "nonblock read, %d streams open"), session->open_streams); } - h2_conn_io_flush(&session->io); status = h2_session_read(session, 0); if (status == APR_SUCCESS) { session->have_read = 1; - dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL); } - else if (APR_STATUS_IS_EAGAIN(status) - || APR_STATUS_IS_TIMEUP(status)) { - if (apr_time_now() > session->idle_until) { - dispatch_event(session, - H2_SESSION_EV_CONN_TIMEOUT, 0, NULL); - } - else { - status = APR_EAGAIN; - goto out; - } + else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) { + status = APR_EAGAIN; + goto out; } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, @@ -2074,7 +2154,6 @@ apr_status_t h2_session_process(h2_sessi } else { /* make certain, we send everything before we idle */ - h2_conn_io_flush(&session->io); if (trace) { ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, H2_SSSN_MSG(session, @@ -2086,7 +2165,6 @@ apr_status_t h2_session_process(h2_sessi */ status = h2_mplx_idle(session->mplx); if (status == APR_EAGAIN) { - dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL); break; } else if (status != APR_SUCCESS) { @@ -2097,33 +2175,11 @@ apr_status_t h2_session_process(h2_sessi status = h2_session_read(session, 1); if (status == APR_SUCCESS) { session->have_read = 1; - dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL); } else if (status == APR_EAGAIN) { /* nothing to read */ } else if (APR_STATUS_IS_TIMEUP(status)) { - apr_time_t now = apr_time_now(); - if (now > session->keep_sync_until) { - /* if we are on an async mpm, now is the time that - * we may dare to pass control to it. */ - session->keep_sync_until = 0; - } - if (now > session->idle_until) { - if (trace) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, - H2_SSSN_MSG(session, - "keepalive timeout")); - } - dispatch_event(session, - H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout"); - } - else if (trace) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, - H2_SSSN_MSG(session, - "keepalive, %f sec left"), - (session->idle_until - now) / 1000000.0f); - } /* continue reading handling */ } else if (APR_STATUS_IS_ECONNABORTED(status) @@ -2141,6 +2197,18 @@ apr_status_t h2_session_process(h2_sessi dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, "error"); } } + if (nghttp2_session_want_write(session->ngh2)) { + ap_update_child_status(session->c->sbh, SERVER_BUSY_WRITE, NULL); + status = h2_session_send(session); + if (status == APR_SUCCESS) { + status = h2_conn_io_flush(&session->io); + } + if (status != APR_SUCCESS) { + dispatch_event(session, H2_SESSION_EV_CONN_ERROR, + H2_ERR_INTERNAL_ERROR, "writing"); + break; + } + } break; case H2_SESSION_ST_BUSY: @@ -2150,7 +2218,6 @@ apr_status_t h2_session_process(h2_sessi status = h2_session_read(session, 0); if (status == APR_SUCCESS) { session->have_read = 1; - dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL); } else if (status == APR_EAGAIN) { /* nothing to read */ @@ -2214,7 +2281,7 @@ apr_status_t h2_session_process(h2_sessi session->iowait); if (status == APR_SUCCESS) { session->wait_us = 0; - dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL); + dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, NULL); } else if (APR_STATUS_IS_TIMEUP(status)) { /* go back to checking all inputs again */ Index: httpd-2.4.23/modules/http2/h2_session.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_session.h 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_session.h 2018-10-02 09:36:09.243205805 +0200 @@ -65,10 +65,11 @@ typedef enum { H2_SESSION_EV_PROTO_ERROR, /* protocol error */ H2_SESSION_EV_CONN_TIMEOUT, /* connection timeout */ H2_SESSION_EV_NO_IO, /* nothing has been read or written */ - H2_SESSION_EV_DATA_READ, /* connection data has been read */ + H2_SESSION_EV_FRAME_RCVD, /* a frame has been received */ H2_SESSION_EV_NGH2_DONE, /* nghttp2 wants neither read nor write anything */ H2_SESSION_EV_MPM_STOPPING, /* the process is stopping */ H2_SESSION_EV_PRE_CLOSE, /* connection will close after this */ + H2_SESSION_EV_STREAM_CHANGE, /* a stream (state/input/output) changed */ } h2_session_event_t; typedef struct h2_session { @@ -117,7 +118,9 @@ typedef struct h2_session { apr_size_t max_stream_mem; /* max buffer memory for a single stream */ apr_time_t idle_until; /* Time we shut down due to sheer boredom */ - apr_time_t keep_sync_until; /* Time we sync wait until passing to async mpm */ + apr_time_t idle_sync_until; /* Time we sync wait until keepalive handling kicks in */ + apr_size_t idle_frames; /* number of rcvd frames that kept session in idle state */ + apr_interval_time_t idle_delay; /* Time we delay processing rcvd frames in idle state */ apr_bucket_brigade *bbtmp; /* brigade for keeping temporary data */ struct apr_thread_cond_t *iowait; /* our cond when trywaiting for data */ Index: httpd-2.4.23/modules/http2/h2_stream.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_stream.c 2018-10-02 09:36:09.203205597 +0200 +++ httpd-2.4.23/modules/http2/h2_stream.c 2018-10-02 09:36:09.243205805 +0200 @@ -220,7 +220,8 @@ static apr_status_t close_input(h2_strea stream->in_buffer = apr_brigade_create(stream->pool, c->bucket_alloc); } - r = h2_headers_create(HTTP_OK, stream->trailers, NULL, stream->pool); + r = h2_headers_create(HTTP_OK, stream->trailers, NULL, + stream->in_trailer_octets, stream->pool); stream->trailers = NULL; b = h2_bucket_headers_create(c->bucket_alloc, r); APR_BRIGADE_INSERT_TAIL(stream->in_buffer, b); @@ -368,7 +369,7 @@ static void set_policy_for(h2_stream *st r->serialize = h2_config_geti(stream->session->config, H2_CONF_SER_HEADERS); } -apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags) +apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_t frame_len) { apr_status_t status = APR_SUCCESS; int new_state, eos = 0; @@ -380,7 +381,9 @@ apr_status_t h2_stream_send_frame(h2_str AP_DEBUG_ASSERT(new_state > S_XXX); return transit(stream, new_state); } - + + ++stream->out_frames; + stream->out_frame_octets += frame_len; switch (ftype) { case NGHTTP2_DATA: eos = (flags & NGHTTP2_FLAG_END_STREAM); @@ -394,7 +397,7 @@ apr_status_t h2_stream_send_frame(h2_str /* start pushed stream */ ap_assert(stream->request == NULL); ap_assert(stream->rtmp != NULL); - status = h2_request_end_headers(stream->rtmp, stream->pool, 1); + status = h2_request_end_headers(stream->rtmp, stream->pool, 1, 0); if (status != APR_SUCCESS) { return status; } @@ -415,7 +418,7 @@ apr_status_t h2_stream_send_frame(h2_str return status; } -apr_status_t h2_stream_recv_frame(h2_stream *stream, int ftype, int flags) +apr_status_t h2_stream_recv_frame(h2_stream *stream, int ftype, int flags, size_t frame_len) { apr_status_t status = APR_SUCCESS; int new_state, eos = 0; @@ -440,6 +443,7 @@ apr_status_t h2_stream_recv_frame(h2_str if (!eos) { h2_stream_rst(stream, H2_ERR_PROTOCOL_ERROR); } + stream->in_trailer_octets += frame_len; } else { /* request HEADER */ @@ -451,7 +455,7 @@ apr_status_t h2_stream_recv_frame(h2_str * to abort the connection here, since this is clearly a protocol error */ return APR_EINVAL; } - status = h2_request_end_headers(stream->rtmp, stream->pool, eos); + status = h2_request_end_headers(stream->rtmp, stream->pool, eos, frame_len); if (status != APR_SUCCESS) { return status; } @@ -628,7 +632,7 @@ apr_status_t h2_stream_set_request_rec(h stream->rtmp = req; /* simulate the frames that led to this */ return h2_stream_recv_frame(stream, NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM); + NGHTTP2_FLAG_END_STREAM, 0); } return status; } Index: httpd-2.4.23/modules/http2/h2_stream.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_stream.h 2018-10-02 09:36:09.203205597 +0200 +++ httpd-2.4.23/modules/http2/h2_stream.h 2018-10-02 09:36:09.243205805 +0200 @@ -95,10 +95,13 @@ struct h2_stream { struct h2_task *task; /* assigned task to fullfill request */ const h2_priority *pref_priority; /* preferred priority for this stream */ + apr_off_t out_frames; /* # of frames sent out */ + apr_off_t out_frame_octets; /* # of RAW frame octets sent out */ apr_off_t out_data_frames; /* # of DATA frames sent */ apr_off_t out_data_octets; /* # of DATA octets (payload) sent */ apr_off_t in_data_frames; /* # of DATA frames received */ apr_off_t in_data_octets; /* # of DATA octets (payload) received */ + apr_off_t in_trailer_octets; /* # of HEADER octets (payload) received in trailers */ h2_stream_monitor *monitor; /* optional monitor for stream states */ }; @@ -195,8 +198,8 @@ apr_status_t h2_stream_add_header(h2_str const char *name, size_t nlen, const char *value, size_t vlen); -apr_status_t h2_stream_send_frame(h2_stream *stream, int frame_type, int flags); -apr_status_t h2_stream_recv_frame(h2_stream *stream, int frame_type, int flags); +apr_status_t h2_stream_send_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len); +apr_status_t h2_stream_recv_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len); /* * Process a frame of received DATA. Index: httpd-2.4.23/modules/http2/h2_switch.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_switch.c 2018-10-02 09:36:09.123205178 +0200 +++ httpd-2.4.23/modules/http2/h2_switch.c 2018-10-02 09:36:09.243205805 +0200 @@ -169,13 +169,12 @@ static int h2_protocol_switch(conn_rec * ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088) "session setup"); h2_ctx_clear(c); - return status; + return !OK; } h2_conn_run(ctx, c); - return DONE; } - return DONE; + return OK; } return DECLINED; Index: httpd-2.4.23/modules/http2/h2_task.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_task.c 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/h2_task.c 2018-10-02 09:36:09.243205805 +0200 @@ -674,7 +674,14 @@ static apr_status_t h2_task_process_requ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): start process_request", task->id); + /* Add the raw bytes of the request (e.g. header frame lengths to + * the logio for this request. */ + if (req->raw_bytes && h2_task_logio_add_bytes_in) { + h2_task_logio_add_bytes_in(c, req->raw_bytes); + } + ap_process_request(r); + if (task->frozen) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): process_request frozen", task->id); Index: httpd-2.4.23/modules/http2/h2_version.h =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_version.h 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/h2_version.h 2018-10-02 09:36:09.243205805 +0200 @@ -26,7 +26,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "1.10.12" +#define MOD_HTTP2_VERSION "1.11.0" /** * @macro @@ -34,7 +34,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_HTTP2_VERSION_NUM 0x010a0b +#define MOD_HTTP2_VERSION_NUM 0x010b00 #endif /* mod_h2_h2_version_h */ Index: httpd-2.4.23/modules/http2/h2_workers.c =================================================================== --- httpd-2.4.23.orig/modules/http2/h2_workers.c 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/h2_workers.c 2018-10-02 09:36:09.243205805 +0200 @@ -305,7 +305,18 @@ h2_workers *h2_workers_create(server_rec workers->max_workers = max_workers; workers->max_idle_secs = (idle_secs > 0)? idle_secs : 10; - status = h2_fifo_create(&workers->mplxs, pool, 2 * workers->max_workers); + /* FIXME: the fifo set we use here has limited capacity. Once the + * set is full, connections with new requests do a wait. Unfortunately, + * we have optimizations in place there that makes such waiting "unfair" + * in the sense that it may take connections a looong time to get scheduled. + * + * Need to rewrite this to use one of our double-linked lists and a mutex + * to have unlimited capacity and fair scheduling. + * + * For now, we just make enough room to have many connections inside one + * process. + */ + status = h2_fifo_set_create(&workers->mplxs, pool, 8 * 1024); if (status != APR_SUCCESS) { return NULL; } Index: httpd-2.4.23/modules/http2/mod_http2.c =================================================================== --- httpd-2.4.23.orig/modules/http2/mod_http2.c 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/mod_http2.c 2018-10-02 09:36:09.243205805 +0200 @@ -52,7 +52,10 @@ AP_DECLARE_MODULE(http2) = { h2_config_create_svr, /* func to create per server config */ h2_config_merge_svr, /* func to merge per server config */ h2_cmds, /* command handlers */ - h2_hooks + h2_hooks, +#if defined(AP_MODULE_FLAG_NONE) + AP_MODULE_FLAG_ALWAYS_MERGE +#endif }; static int h2_h2_fixups(request_rec *r); @@ -189,6 +192,11 @@ static void http2_req_engine_done(h2_req h2_mplx_req_engine_done(ngn, r_conn, status); } +static void http2_get_num_workers(server_rec *s, int *minw, int *maxw) +{ + h2_get_num_workers(s, minw, maxw); +} + /* Runs once per created child process. Perform any process * related initionalization here. */ @@ -214,6 +222,7 @@ static void h2_hooks(apr_pool_t *pool) APR_REGISTER_OPTIONAL_FN(http2_req_engine_push); APR_REGISTER_OPTIONAL_FN(http2_req_engine_pull); APR_REGISTER_OPTIONAL_FN(http2_req_engine_done); + APR_REGISTER_OPTIONAL_FN(http2_get_num_workers); ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks"); Index: httpd-2.4.23/modules/http2/mod_http2.h =================================================================== --- httpd-2.4.23.orig/modules/http2/mod_http2.h 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/mod_http2.h 2018-10-02 09:36:09.243205805 +0200 @@ -92,4 +92,9 @@ APR_DECLARE_OPTIONAL_FN(void, http2_req_engine_done, (h2_req_engine *engine, conn_rec *rconn, apr_status_t status)); + +APR_DECLARE_OPTIONAL_FN(void, + http2_get_num_workers, (server_rec *s, + int *minw, int *max)); + #endif Index: httpd-2.4.23/modules/http2/mod_proxy_http2.c =================================================================== --- httpd-2.4.23.orig/modules/http2/mod_proxy_http2.c 2018-10-02 09:36:09.127205199 +0200 +++ httpd-2.4.23/modules/http2/mod_proxy_http2.c 2018-10-02 09:36:09.243205805 +0200 @@ -37,7 +37,10 @@ AP_DECLARE_MODULE(proxy_http2) = { NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ NULL, /* command apr_table_t */ - register_hook /* register hooks */ + register_hook, /* register hooks */ +#if defined(AP_MODULE_FLAG_NONE) + AP_MODULE_FLAG_ALWAYS_MERGE +#endif }; /* Optional functions from mod_http2 */ @@ -576,9 +579,9 @@ run_connect: /* Step Three: Create conn_rec for the socket we have open now. */ if (!ctx->p_conn->connection) { - if ((status = ap_proxy_connection_create(ctx->proxy_func, ctx->p_conn, - ctx->owner, - ctx->server)) != OK) { + status = ap_proxy_connection_create_ex(ctx->proxy_func, + ctx->p_conn, ctx->rbase); + if (status != OK) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, APLOGNO(03353) "setup new connection: is_ssl=%d %s %s %s", ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname, Index: httpd-2.4.23/include/httpd.h =================================================================== --- httpd-2.4.23.orig/include/httpd.h 2018-10-02 09:36:08.931204176 +0200 +++ httpd-2.4.23/include/httpd.h 2018-10-02 09:36:09.235205763 +0200 @@ -568,6 +568,10 @@ AP_DECLARE(const char *) ap_get_server_b ((x) == HTTP_INTERNAL_SERVER_ERROR) || \ ((x) == HTTP_SERVICE_UNAVAILABLE) || \ ((x) == HTTP_NOT_IMPLEMENTED)) + +/** does the status imply header only response (i.e. never w/ a body)? */ +#define AP_STATUS_IS_HEADER_ONLY(x) ((x) == HTTP_NO_CONTENT || \ + (x) == HTTP_NOT_MODIFIED) /** @} */ /**
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor