From 34117ca6001546eb1ed82703c5c6b420a533c38b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 12 Oct 2015 14:14:36 +0000 Subject: [PATCH] when stream gets reset by client, forward info to mplx and fail writes git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1708124 13f79535-47bb-0310-9956-ffa450edef68 --- modules/http2/h2_io_set.c | 51 +++++++++++++++++++++----------------- modules/http2/h2_io_set.h | 3 ++- modules/http2/h2_mplx.c | 19 ++++++++++---- modules/http2/h2_session.c | 1 + 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/modules/http2/h2_io_set.c b/modules/http2/h2_io_set.c index 91afde8f1f..74ab508fef 100644 --- a/modules/http2/h2_io_set.c +++ b/modules/http2/h2_io_set.c @@ -78,19 +78,6 @@ h2_io *h2_io_set_get(h2_io_set *sp, int stream_id) return ps? *ps : NULL; } -h2_io *h2_io_set_get_highest_prio(h2_io_set *set) -{ - h2_io *highest = NULL; - int i; - for (i = 0; i < set->list->nelts; ++i) { - h2_io *io = h2_io_IDX(set->list, i); - if (!highest /*|| io-prio even higher */ ) { - highest = io; - } - } - return highest; -} - static void h2_io_set_sort(h2_io_set *sp) { qsort(sp->list->elts, sp->list->nelts, sp->list->elt_size, @@ -118,28 +105,46 @@ apr_status_t h2_io_set_add(h2_io_set *sp, h2_io *io) return APR_SUCCESS; } +static void remove_idx(h2_io_set *sp, int idx) +{ + int n; + --sp->list->nelts; + n = sp->list->nelts - idx; + if (n > 0) { + /* Close the hole in the array by moving the upper + * parts down one step. + */ + h2_io **selts = (h2_io**)sp->list->elts; + memmove(selts + idx, selts + idx + 1, n * sizeof(h2_io*)); + } +} + h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io) { int i; for (i = 0; i < sp->list->nelts; ++i) { h2_io *e = h2_io_IDX(sp->list, i); if (e == io) { - int n; - --sp->list->nelts; - n = sp->list->nelts - i; - if (n > 0) { - /* Close the hole in the array by moving the upper - * parts down one step. - */ - h2_io **selts = (h2_io**)sp->list->elts; - memmove(selts+i, selts+i+1, n * sizeof(h2_io*)); - } + remove_idx(sp, i); return e; } } return NULL; } +h2_io *h2_io_set_pop_highest_prio(h2_io_set *set) +{ + /* For now, this just removes the first element in the set. + * the name is misleading... + */ + if (set->list->nelts > 0) { + h2_io *io = h2_io_IDX(set->list, 0); + remove_idx(set, 0); + return io; + } + return NULL; +} + void h2_io_set_destroy_all(h2_io_set *sp) { int i; diff --git a/modules/http2/h2_io_set.h b/modules/http2/h2_io_set.h index a9c6546c70..5e7555af92 100644 --- a/modules/http2/h2_io_set.h +++ b/modules/http2/h2_io_set.h @@ -30,7 +30,6 @@ void h2_io_set_destroy(h2_io_set *set); apr_status_t h2_io_set_add(h2_io_set *set, struct h2_io *io); h2_io *h2_io_set_get(h2_io_set *set, int stream_id); -h2_io *h2_io_set_get_highest_prio(h2_io_set *set); h2_io *h2_io_set_remove(h2_io_set *set, struct h2_io *io); void h2_io_set_remove_all(h2_io_set *set); @@ -44,4 +43,6 @@ typedef int h2_io_set_iter_fn(void *ctx, struct h2_io *io); void h2_io_set_iter(h2_io_set *set, h2_io_set_iter_fn *iter, void *ctx); +h2_io *h2_io_set_pop_highest_prio(h2_io_set *set); + #endif /* defined(__mod_h2__h2_io_set__) */ diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 3b5207677c..6c4ae9f4c4 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -299,6 +299,13 @@ apr_status_t h2_mplx_cleanup_stream(h2_mplx *m, h2_stream *stream) stream_destroy(m, stream, io); } else { + if (stream->rst_error) { + /* Forward error code to fail any further attempt to + * write to io */ + h2_io_rst(io, stream->rst_error); + } + /* Remove io from ready set (if there), since we will never submit it */ + h2_io_set_remove(m->ready_ios, io); /* Add stream to closed set for cleanup when task is done */ h2_stream_set_add(m->closed, stream); } @@ -502,9 +509,8 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_stream_set *streams) } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { - h2_io *io = h2_io_set_get_highest_prio(m->ready_ios); + h2_io *io = h2_io_set_pop_highest_prio(m->ready_ios); if (io) { - stream = h2_stream_set_get(streams, io->id); if (stream) { if (io->rst_error) { @@ -515,15 +521,18 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_stream_set *streams) h2_stream_set_response(stream, io->response, io->bbout); } - h2_io_set_remove(m->ready_ios, io); if (io->output_drained) { apr_thread_cond_signal(io->output_drained); } } else { - ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_NOTFOUND, m->c, - APLOGNO(02953) "h2_mplx(%ld): stream for response %d", + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(02953) + "h2_mplx(%ld): stream for response %d not found", m->id, io->id); + /* We have the io ready, but the stream has gone away, maybe + * reset by the client. Should no longer happen since such + * streams should clear io's from the ready queue. + */ } } apr_thread_mutex_unlock(m->lock); diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 80336081d4..b8fa885a2b 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -243,6 +243,7 @@ static apr_status_t stream_destroy(h2_session *session, "h2_stream(%ld-%d): closing with err=%d %s", session->id, (int)stream->id, (int)error_code, nghttp2_strerror(error_code)); + h2_stream_rst(stream, error_code); } h2_stream_set_remove(session->streams, stream); -- 2.50.0