You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2017/03/12 14:20:29 UTC
svn commit: r1786582 [2/2] - in /httpd/httpd/branches/2.4.x: ./
modules/http2/
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c Sun Mar 12 14:20:29 2017
@@ -100,48 +100,43 @@ static void leave_mutex(h2_mplx *m, int
}
}
-static void beam_leave(void *ctx, apr_thread_mutex_t *lock)
-{
- leave_mutex(ctx, 1);
-}
-
-static apr_status_t beam_enter(void *ctx, h2_beam_lock *pbl)
-{
- h2_mplx *m = ctx;
- int acquired;
- apr_status_t status;
-
- status = enter_mutex(m, &acquired);
- if (status == APR_SUCCESS) {
- pbl->mutex = m->lock;
- pbl->leave = acquired? beam_leave : NULL;
- pbl->leave_ctx = m;
- }
- return status;
-}
+static void check_data_for(h2_mplx *m, int stream_id);
static void stream_output_consumed(void *ctx,
h2_bucket_beam *beam, apr_off_t length)
{
h2_stream *stream = ctx;
+ h2_mplx *m = stream->session->mplx;
h2_task *task = stream->task;
+ int acquired;
+
if (length > 0 && task && task->assigned) {
- h2_req_engine_out_consumed(task->assigned, task->c, length);
+ if (enter_mutex(m, &acquired) == APR_SUCCESS) {
+ h2_req_engine_out_consumed(task->assigned, task->c, length);
+ leave_mutex(m, acquired);
+ }
}
}
static void stream_input_ev(void *ctx, h2_bucket_beam *beam)
{
h2_mplx *m = ctx;
- apr_atomic_set32(&m->event_pending, 1);
+ apr_atomic_set32(&m->event_pending, 1);
}
static void stream_input_consumed(void *ctx,
h2_bucket_beam *beam, apr_off_t length)
{
- h2_mplx *m = ctx;
- if (m->input_consumed && length) {
- m->input_consumed(m->input_consumed_ctx, beam->id, length);
+ if (length > 0) {
+ h2_mplx *m = ctx;
+ int acquired;
+
+ if (enter_mutex(m, &acquired) == APR_SUCCESS) {
+ if (m->input_consumed) {
+ m->input_consumed(m->input_consumed_ctx, beam->id, length);
+ }
+ leave_mutex(m, acquired);
+ }
}
}
@@ -161,8 +156,6 @@ static int can_beam_file(void *ctx, h2_b
return 0;
}
-static void have_out_data_for(h2_mplx *m, h2_stream *stream);
-
static void check_tx_reservation(h2_mplx *m)
{
if (m->tx_handles_reserved <= 0) {
@@ -190,17 +183,21 @@ static void stream_joined(h2_mplx *m, h2
h2_ihash_remove(m->shold, stream->id);
h2_ihash_add(m->spurge, stream);
- m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input);
+ if (stream->input) {
+ m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input);
+ }
m->tx_handles_reserved += h2_beam_get_files_beamed(stream->output);
}
static void stream_cleanup(h2_mplx *m, h2_stream *stream)
{
ap_assert(stream->state == H2_SS_CLEANUP);
-
+
+ if (stream->input) {
+ h2_beam_on_consumed(stream->input, NULL, NULL, NULL);
+ h2_beam_abort(stream->input);
+ }
h2_beam_on_produced(stream->output, NULL, NULL);
- h2_beam_on_consumed(stream->input, NULL, NULL, NULL);
- h2_beam_abort(stream->input);
h2_beam_leave(stream->output);
h2_stream_cleanup(stream);
@@ -231,7 +228,6 @@ static void stream_cleanup(h2_mplx *m, h
*/
h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
const h2_config *conf,
- apr_interval_time_t stream_timeout,
h2_workers *workers)
{
apr_status_t status = APR_SUCCESS;
@@ -295,7 +291,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
m->q = h2_iq_create(m->pool, m->max_streams);
m->readyq = h2_iq_create(m->pool, m->max_streams);
- m->stream_timeout = stream_timeout;
m->workers = workers;
m->workers_max = workers->max_workers;
m->workers_limit = 6; /* the original h1 max parallel connections */
@@ -376,18 +371,21 @@ static int stream_destroy_iter(void *ctx
h2_ihash_remove(m->spurge, stream->id);
ap_assert(stream->state == H2_SS_CLEANUP);
- if (stream->input == NULL || stream->output == NULL) {
+ if (stream->output == NULL) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, m->c,
H2_STRM_MSG(stream, "already with beams==NULL"));
return 0;
}
- /* Process outstanding events before destruction */
- input_consumed_signal(m, stream);
- h2_beam_log(stream->input, m->c, APLOG_TRACE2, "stream_destroy");
+ if (stream->input) {
+ /* Process outstanding events before destruction */
+ input_consumed_signal(m, stream);
+ h2_beam_log(stream->input, m->c, APLOG_TRACE2, "stream_destroy");
+ h2_beam_destroy(stream->input);
+ stream->input = NULL;
+ }
+
h2_beam_log(stream->output, m->c, APLOG_TRACE2, "stream_destroy");
- h2_beam_destroy(stream->input);
- stream->input = NULL;
h2_beam_destroy(stream->output);
stream->output = NULL;
if (stream->task) {
@@ -581,17 +579,12 @@ void h2_mplx_set_consumed_cb(h2_mplx *m,
static void output_produced(void *ctx, h2_bucket_beam *beam, apr_off_t bytes)
{
h2_mplx *m = ctx;
- apr_status_t status;
- h2_stream *stream;
int acquired;
- if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
- stream = h2_ihash_get(m->streams, beam->id);
- if (stream) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
- "h2_mplx(%s): output_produced", stream->task->id);
- have_out_data_for(m, stream);
- }
+ if (enter_mutex(m, &acquired) == APR_SUCCESS) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
+ "h2_mplx(%ld-%d): output_produced", m->c->id, beam->id);
+ check_data_for(m, beam->id);
leave_mutex(m, acquired);
}
}
@@ -628,12 +621,12 @@ static apr_status_t out_open(h2_mplx *m,
}
/* time to protect the beam against multi-threaded use */
- h2_beam_mutex_set(stream->output, beam_enter, stream->task->cond, m);
+ h2_beam_mutex_enable(stream->output);
/* we might see some file buckets in the output, see
* if we have enough handles reserved. */
check_tx_reservation(m);
- have_out_data_for(m, stream);
+ check_data_for(m, stream->id);
return status;
}
@@ -673,7 +666,7 @@ static apr_status_t out_close(h2_mplx *m
status = h2_beam_close(task->output.beam);
h2_beam_log(task->output.beam, m->c, APLOG_TRACE2, "out_close");
output_consumed_signal(m, task);
- have_out_data_for(m, stream);
+ check_data_for(m, task->stream_id);
return status;
}
@@ -706,11 +699,10 @@ apr_status_t h2_mplx_out_trywait(h2_mplx
return status;
}
-static void have_out_data_for(h2_mplx *m, h2_stream *stream)
+static void check_data_for(h2_mplx *m, int stream_id)
{
ap_assert(m);
- ap_assert(stream);
- h2_iq_append(m->readyq, stream->id);
+ h2_iq_append(m->readyq, stream_id);
apr_atomic_set32(&m->event_pending, 1);
if (m->added_output) {
apr_thread_cond_signal(m->added_output);
@@ -751,8 +743,7 @@ apr_status_t h2_mplx_process(h2_mplx *m,
h2_ihash_add(m->streams, stream);
if (h2_stream_is_ready(stream)) {
/* already have a response */
- apr_atomic_set32(&m->event_pending, 1);
- h2_iq_append(m->readyq, stream->id);
+ check_data_for(m, stream->id);
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
H2_STRM_MSG(stream, "process, add to readyq"));
}
@@ -812,14 +803,14 @@ static h2_task *next_stream_task(h2_mplx
m->max_stream_started = sid;
}
- h2_beam_timeout_set(stream->input, m->stream_timeout);
- h2_beam_on_consumed(stream->input, stream_input_ev,
- stream_input_consumed, m);
- h2_beam_on_file_beam(stream->input, can_beam_file, m);
- h2_beam_mutex_set(stream->input, beam_enter, stream->task->cond, m);
+ if (stream->input) {
+ h2_beam_on_consumed(stream->input, stream_input_ev,
+ stream_input_consumed, m);
+ h2_beam_on_file_beam(stream->input, can_beam_file, m);
+ h2_beam_mutex_enable(stream->input);
+ }
h2_beam_buffer_size_set(stream->output, m->stream_max_mem);
- h2_beam_timeout_set(stream->output, m->stream_timeout);
}
stream->task->worker_started = 1;
stream->task->started_at = apr_time_now();
@@ -931,18 +922,22 @@ static void task_done(h2_mplx *m, h2_tas
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
H2_STRM_MSG(stream, "task_done, stream open"));
/* more data will not arrive, resume the stream */
- h2_beam_mutex_set(stream->input, NULL, NULL, NULL);
- h2_beam_mutex_set(stream->output, NULL, NULL, NULL);
- h2_beam_leave(stream->input);
- have_out_data_for(m, stream);
+ if (stream->input) {
+ h2_beam_mutex_disable(stream->input);
+ h2_beam_leave(stream->input);
+ }
+ h2_beam_mutex_disable(stream->output);
+ check_data_for(m, stream->id);
}
else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
H2_STRM_MSG(stream, "task_done, in hold"));
/* stream was just waiting for us. */
- h2_beam_mutex_set(stream->input, NULL, NULL, NULL);
- h2_beam_mutex_set(stream->output, NULL, NULL, NULL);
- h2_beam_leave(stream->input);
+ if (stream->input) {
+ h2_beam_mutex_disable(stream->input);
+ h2_beam_leave(stream->input);
+ }
+ h2_beam_mutex_disable(stream->output);
stream_joined(m, stream);
}
else if ((stream = h2_ihash_get(m->spurge, task->stream_id)) != NULL) {
@@ -1016,7 +1011,7 @@ static int timed_out_busy_iter(void *dat
stream_iter_ctx *ctx = data;
h2_stream *stream = val;
if (stream->task && !stream->task->worker_done
- && (ctx->now - stream->task->started_at) > ctx->m->stream_timeout) {
+ && (ctx->now - stream->task->started_at) > stream->task->timeout) {
/* timed out stream occupying a worker, found */
ctx->stream = stream;
return 0;
@@ -1273,10 +1268,6 @@ apr_status_t h2_mplx_dispatch_master_eve
h2_stream *stream;
size_t i, n;
- if (!h2_mplx_has_master_events(m)) {
- return APR_EAGAIN;
- }
-
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
"h2_mplx(%ld): dispatch events", m->id);
@@ -1308,11 +1299,7 @@ apr_status_t h2_mplx_keep_active(h2_mplx
int acquired;
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
- h2_stream *s = h2_ihash_get(m->streams, stream_id);
- if (s) {
- h2_iq_append(m->readyq, stream_id);
- apr_atomic_set32(&m->event_pending, 1);
- }
+ check_data_for(m, stream_id);
leave_mutex(m, acquired);
}
return status;
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h Sun Mar 12 14:20:29 2017
@@ -96,7 +96,6 @@ struct h2_mplx {
struct apr_thread_cond_t *join_wait;
apr_size_t stream_max_mem;
- apr_interval_time_t stream_timeout;
apr_pool_t *spare_io_pool;
apr_array_header_t *spare_slaves; /* spare slave connections */
@@ -125,7 +124,6 @@ apr_status_t h2_mplx_child_init(apr_pool
*/
h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master,
const struct h2_config *conf,
- apr_interval_time_t stream_timeout,
struct h2_workers *workers);
/**
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_session.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_session.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_session.c Sun Mar 12 14:20:29 2017
@@ -31,6 +31,7 @@
#include "h2_private.h"
#include "h2.h"
+#include "h2_bucket_beam.h"
#include "h2_bucket_eos.h"
#include "h2_config.h"
#include "h2_ctx.h"
@@ -73,10 +74,14 @@ static int h2_session_status_from_apr_st
static void update_window(void *ctx, int stream_id, apr_off_t bytes_read)
{
h2_session *session = (h2_session*)ctx;
- nghttp2_session_consume(session->ngh2, stream_id, bytes_read);
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
- "h2_stream(%ld-%d): consumed %ld bytes",
- session->id, stream_id, (long)bytes_read);
+ while (bytes_read > 0) {
+ int len = (bytes_read > INT_MAX)? INT_MAX : bytes_read;
+ nghttp2_session_consume(session->ngh2, stream_id, (int)bytes_read);
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
+ "h2_stream(%ld-%d): consumed %d bytes",
+ session->id, stream_id, len);
+ bytes_read -= len;
+ }
}
static apr_status_t h2_session_receive(void *ctx,
@@ -656,26 +661,29 @@ static apr_status_t h2_session_shutdown(
* we have, but no longer accept new ones. Report the max stream
* we have received and discard all new ones. */
}
- nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE,
- session->local.accepted_max,
- error, (uint8_t*)msg, msg? strlen(msg):0);
+
session->local.accepting = 0;
session->local.shutdown = 1;
- status = nghttp2_session_send(session->ngh2);
- if (status == APR_SUCCESS) {
- status = h2_conn_io_flush(&session->io);
+ if (!session->c->aborted) {
+ nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE,
+ session->local.accepted_max,
+ error, (uint8_t*)msg, msg? strlen(msg):0);
+ status = nghttp2_session_send(session->ngh2);
+ if (status == APR_SUCCESS) {
+ status = h2_conn_io_flush(&session->io);
+ }
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+ H2_SSSN_LOG(APLOGNO(03069), session,
+ "sent GOAWAY, err=%d, msg=%s"), error, msg? msg : "");
}
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
- H2_SSSN_LOG(APLOGNO(03069), session,
- "sent GOAWAY, err=%d, msg=%s"), error, msg? msg : "");
dispatch_event(session, H2_SESSION_EV_LOCAL_GOAWAY, error, msg);
return status;
}
-static apr_status_t session_pool_cleanup(void *data)
+static apr_status_t session_cleanup(h2_session *session, const char *trigger)
{
- h2_session *session = data;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
+ conn_rec *c = session->c;
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
H2_SSSN_MSG(session, "pool_cleanup"));
if (session->state != H2_SESSION_ST_DONE
@@ -688,13 +696,13 @@ static apr_status_t session_pool_cleanup
* connection when sending the next request, this has the effect
* that at least this one request will fail.
*/
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, session->c,
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c,
H2_SSSN_LOG(APLOGNO(03199), session,
"connection disappeared without proper "
"goodbye, clients will be confused, should not happen"));
}
- transit(session, "pool cleanup", H2_SESSION_ST_CLEANUP);
+ transit(session, trigger, H2_SESSION_ST_CLEANUP);
h2_mplx_set_consumed_cb(session->mplx, NULL, NULL);
h2_mplx_release_and_join(session->mplx, session->iowait);
session->mplx = NULL;
@@ -702,14 +710,39 @@ static apr_status_t session_pool_cleanup
ap_assert(session->ngh2);
nghttp2_session_del(session->ngh2);
session->ngh2 = NULL;
+ h2_ctx_clear(c);
+
+
+ return APR_SUCCESS;
+}
+static apr_status_t session_pool_cleanup(void *data)
+{
+ conn_rec *c = data;
+ h2_session *session;
+ h2_ctx *ctx = h2_ctx_get(c, 0);
+
+ if (ctx && (session = h2_ctx_session_get(ctx))) {
+ /* if the session is still there, now is the last chance
+ * to perform cleanup. Normally, cleanup should have happened
+ * earlier in the connection pre_close. Main reason is that
+ * any ongoing requests on slave connections might still access
+ * data which has, at this time, already been freed. An example
+ * is mod_ssl that uses request hooks. */
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c,
+ H2_SSSN_LOG(APLOGNO(10020), session,
+ "session cleanup triggered by pool cleanup. "
+ "this should have happened earlier already."));
+ return session_cleanup(session, "pool cleanup");
+ }
return APR_SUCCESS;
}
-static h2_session *h2_session_create_int(conn_rec *c,
- request_rec *r,
- h2_ctx *ctx,
- h2_workers *workers)
+static apr_status_t h2_session_create_int(h2_session **psession,
+ conn_rec *c,
+ request_rec *r,
+ h2_ctx *ctx,
+ h2_workers *workers)
{
nghttp2_session_callbacks *callbacks = NULL;
nghttp2_option *options = NULL;
@@ -718,136 +751,146 @@ static h2_session *h2_session_create_int
uint32_t n;
apr_pool_t *pool = NULL;
h2_session *session;
-
- apr_status_t status = apr_allocator_create(&allocator);
+ apr_status_t status;
+ int rv;
+
+ *psession = NULL;
+ status = apr_allocator_create(&allocator);
if (status != APR_SUCCESS) {
- return NULL;
+ return status;
}
apr_allocator_max_free_set(allocator, ap_max_mem_free);
apr_pool_create_ex(&pool, c->pool, NULL, allocator);
if (!pool) {
apr_allocator_destroy(allocator);
- return NULL;
+ return APR_ENOMEM;
}
apr_pool_tag(pool, "h2_session");
apr_allocator_owner_set(allocator, pool);
status = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool);
if (status != APR_SUCCESS) {
apr_pool_destroy(pool);
- return NULL;
+ return APR_ENOMEM;
}
apr_allocator_mutex_set(allocator, mutex);
- /* get h2_session a lifetime beyond its pool and everything
- * connected to it. */
session = apr_pcalloc(pool, sizeof(h2_session));
- if (session) {
- int rv;
- session->id = c->id;
- session->c = c;
- session->r = r;
- session->s = h2_ctx_server_get(ctx);
- session->pool = pool;
- session->config = h2_config_sget(session->s);
- session->workers = workers;
-
- session->state = H2_SESSION_ST_INIT;
- session->local.accepting = 1;
- session->remote.accepting = 1;
-
- apr_pool_pre_cleanup_register(pool, session, session_pool_cleanup);
-
- session->max_stream_count = h2_config_geti(session->config,
- H2_CONF_MAX_STREAMS);
- session->max_stream_mem = h2_config_geti(session->config,
- H2_CONF_STREAM_MAX_MEM);
-
- status = apr_thread_cond_create(&session->iowait, session->pool);
- if (status != APR_SUCCESS) {
- return NULL;
- }
-
- session->monitor = apr_pcalloc(pool, sizeof(h2_stream_monitor));
- if (session->monitor == NULL) {
- return NULL;
- }
- session->monitor->ctx = session;
- session->monitor->on_state_enter = on_stream_state_enter;
- session->monitor->on_state_event = on_stream_state_event;
-
- session->mplx = h2_mplx_create(c, session->pool, session->config,
- session->s->timeout, workers);
-
- h2_mplx_set_consumed_cb(session->mplx, update_window, session);
-
- /* Install the connection input filter that feeds the session */
- session->cin = h2_filter_cin_create(session->pool,
- h2_session_receive, session);
- ap_add_input_filter("H2_IN", session->cin, r, c);
-
- h2_conn_io_init(&session->io, c, session->config);
- session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
-
- status = init_callbacks(c, &callbacks);
- if (status != APR_SUCCESS) {
- ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, APLOGNO(02927)
- "nghttp2: error in init_callbacks");
- return NULL;
- }
-
- rv = nghttp2_option_new(&options);
- if (rv != 0) {
- ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
- APLOGNO(02928) "nghttp2_option_new: %s",
- nghttp2_strerror(rv));
- return NULL;
- }
- nghttp2_option_set_peer_max_concurrent_streams(
- options, (uint32_t)session->max_stream_count);
- /* We need to handle window updates ourself, otherwise we
- * get flooded by nghttp2. */
- nghttp2_option_set_no_auto_window_update(options, 1);
-
- rv = nghttp2_session_server_new2(&session->ngh2, callbacks,
- session, options);
- nghttp2_session_callbacks_del(callbacks);
- nghttp2_option_del(options);
-
- if (rv != 0) {
- ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
- APLOGNO(02929) "nghttp2_session_server_new: %s",
- nghttp2_strerror(rv));
- return NULL;
- }
-
- n = h2_config_geti(session->config, H2_CONF_PUSH_DIARY_SIZE);
- session->push_diary = h2_push_diary_create(session->pool, n);
-
- if (APLOGcdebug(c)) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
- H2_SSSN_LOG(APLOGNO(03200), session,
- "created, max_streams=%d, stream_mem=%d, "
- "workers_limit=%d, workers_max=%d, "
- "push_diary(type=%d,N=%d)"),
- (int)session->max_stream_count,
- (int)session->max_stream_mem,
- session->mplx->workers_limit,
- session->mplx->workers_max,
- session->push_diary->dtype,
- (int)session->push_diary->N);
- }
+ if (!session) {
+ return APR_ENOMEM;
+ }
+
+ *psession = session;
+ session->id = c->id;
+ session->c = c;
+ session->r = r;
+ session->s = h2_ctx_server_get(ctx);
+ session->pool = pool;
+ session->config = h2_config_sget(session->s);
+ session->workers = workers;
+
+ session->state = H2_SESSION_ST_INIT;
+ session->local.accepting = 1;
+ session->remote.accepting = 1;
+
+ session->max_stream_count = h2_config_geti(session->config,
+ H2_CONF_MAX_STREAMS);
+ session->max_stream_mem = h2_config_geti(session->config,
+ H2_CONF_STREAM_MAX_MEM);
+
+ status = apr_thread_cond_create(&session->iowait, session->pool);
+ if (status != APR_SUCCESS) {
+ apr_pool_destroy(pool);
+ return status;
+ }
+
+ session->monitor = apr_pcalloc(pool, sizeof(h2_stream_monitor));
+ if (session->monitor == NULL) {
+ apr_pool_destroy(pool);
+ return status;
+ }
+ session->monitor->ctx = session;
+ session->monitor->on_state_enter = on_stream_state_enter;
+ session->monitor->on_state_event = on_stream_state_event;
+
+ session->mplx = h2_mplx_create(c, session->pool, session->config,
+ workers);
+
+ h2_mplx_set_consumed_cb(session->mplx, update_window, session);
+
+ /* Install the connection input filter that feeds the session */
+ session->cin = h2_filter_cin_create(session->pool,
+ h2_session_receive, session);
+ ap_add_input_filter("H2_IN", session->cin, r, c);
+
+ h2_conn_io_init(&session->io, c, session->config);
+ session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
+
+ status = init_callbacks(c, &callbacks);
+ if (status != APR_SUCCESS) {
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, APLOGNO(02927)
+ "nghttp2: error in init_callbacks");
+ apr_pool_destroy(pool);
+ return status;
+ }
+
+ rv = nghttp2_option_new(&options);
+ if (rv != 0) {
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
+ APLOGNO(02928) "nghttp2_option_new: %s",
+ nghttp2_strerror(rv));
+ apr_pool_destroy(pool);
+ return status;
}
- return session;
+ nghttp2_option_set_peer_max_concurrent_streams(
+ options, (uint32_t)session->max_stream_count);
+ /* We need to handle window updates ourself, otherwise we
+ * get flooded by nghttp2. */
+ nghttp2_option_set_no_auto_window_update(options, 1);
+
+ rv = nghttp2_session_server_new2(&session->ngh2, callbacks,
+ session, options);
+ nghttp2_session_callbacks_del(callbacks);
+ nghttp2_option_del(options);
+
+ if (rv != 0) {
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
+ APLOGNO(02929) "nghttp2_session_server_new: %s",
+ nghttp2_strerror(rv));
+ apr_pool_destroy(pool);
+ return APR_ENOMEM;
+ }
+
+ n = h2_config_geti(session->config, H2_CONF_PUSH_DIARY_SIZE);
+ session->push_diary = h2_push_diary_create(session->pool, n);
+
+ if (APLOGcdebug(c)) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ H2_SSSN_LOG(APLOGNO(03200), session,
+ "created, max_streams=%d, stream_mem=%d, "
+ "workers_limit=%d, workers_max=%d, "
+ "push_diary(type=%d,N=%d)"),
+ (int)session->max_stream_count,
+ (int)session->max_stream_mem,
+ session->mplx->workers_limit,
+ session->mplx->workers_max,
+ session->push_diary->dtype,
+ (int)session->push_diary->N);
+ }
+
+ apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);
+ return APR_SUCCESS;
}
-h2_session *h2_session_create(conn_rec *c, h2_ctx *ctx, h2_workers *workers)
+apr_status_t h2_session_create(h2_session **psession,
+ conn_rec *c, h2_ctx *ctx, h2_workers *workers)
{
- return h2_session_create_int(c, NULL, ctx, workers);
+ return h2_session_create_int(psession, c, NULL, ctx, workers);
}
-h2_session *h2_session_rcreate(request_rec *r, h2_ctx *ctx, h2_workers *workers)
+apr_status_t h2_session_rcreate(h2_session **psession,
+ request_rec *r, h2_ctx *ctx, h2_workers *workers)
{
- return h2_session_create_int(r->connection, r, ctx, workers);
+ return h2_session_create_int(psession, r->connection, r, ctx, workers);
}
static apr_status_t h2_session_start(h2_session *session, int *rv)
@@ -1369,7 +1412,7 @@ static apr_status_t on_stream_resume(voi
ap_assert(stream);
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
H2_STRM_MSG(stream, "on_resume"));
-
+
send_headers:
headers = NULL;
status = h2_stream_out_prepare(stream, &len, &eos, &headers);
@@ -1738,12 +1781,7 @@ static void ev_stream_open(h2_session *s
}
ap_assert(!stream->scheduled);
- if (stream->request) {
- const h2_request *r = stream->request;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
- H2_STRM_MSG(stream, "schedule %s %s://%s%s chunked=%d"),
- r->method, r->scheme, r->authority, r->path, r->chunked);
- stream->scheduled = 1;
+ if (h2_stream_prep_processing(stream) == APR_SUCCESS) {
h2_mplx_process(session->mplx, stream, stream_pri_cmp, session);
}
else {
@@ -1919,7 +1957,6 @@ apr_status_t h2_session_process(h2_sessi
}
while (session->state != H2_SESSION_ST_DONE) {
- trace = APLOGctrace3(c);
session->have_read = session->have_written = 0;
if (session->local.accepting
@@ -1957,8 +1994,6 @@ apr_status_t h2_session_process(h2_sessi
break;
case H2_SESSION_ST_IDLE:
- /* make certain, we send everything before we idle */
- h2_conn_io_flush(&session->io);
/* We trust our connection into the default timeout/keepalive
* handling of the core filters/mpm iff:
* - keep_sync_until is not set
@@ -1975,6 +2010,7 @@ apr_status_t h2_session_process(h2_sessi
"nonblock read, %d streams open"),
session->open_streams);
}
+ h2_conn_io_flush(&session->io);
status = h2_session_read(session, 0);
if (status == APR_SUCCESS) {
@@ -2001,6 +2037,8 @@ 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,
@@ -2187,19 +2225,24 @@ out:
dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
}
- status = APR_SUCCESS;
- if (session->state == H2_SESSION_ST_DONE) {
- status = APR_EOF;
- }
-
- return status;
+ return (session->state == H2_SESSION_ST_DONE)? APR_EOF : APR_SUCCESS;
}
apr_status_t h2_session_pre_close(h2_session *session, int async)
{
+ apr_status_t status;
+
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
H2_SSSN_MSG(session, "pre_close"));
dispatch_event(session, H2_SESSION_EV_PRE_CLOSE, 0,
(session->state == H2_SESSION_ST_IDLE)? "timeout" : NULL);
- return APR_SUCCESS;
+ status = session_cleanup(session, "pre_close");
+ if (status == APR_SUCCESS) {
+ /* no one should hold a reference to this session any longer and
+ * the h2_ctx was removed from the connection.
+ * Take the pool (and thus all subpools etc. down now, instead of
+ * during cleanup of main connection pool. */
+ apr_pool_destroy(session->pool);
+ }
+ return status;
}
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_session.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_session.h?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_session.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_session.h Sun Mar 12 14:20:29 2017
@@ -132,24 +132,28 @@ const char *h2_session_state_str(h2_sess
/**
* Create a new h2_session for the given connection.
* The session will apply the configured parameter.
+ * @param psession pointer receiving the created session on success or NULL
* @param c the connection to work on
* @param cfg the module config to apply
* @param workers the worker pool to use
* @return the created session
*/
-h2_session *h2_session_create(conn_rec *c, struct h2_ctx *ctx,
- struct h2_workers *workers);
+apr_status_t h2_session_create(h2_session **psession,
+ conn_rec *c, struct h2_ctx *ctx,
+ struct h2_workers *workers);
/**
* Create a new h2_session for the given request.
* The session will apply the configured parameter.
+ * @param psession pointer receiving the created session on success or NULL
* @param r the request that was upgraded
* @param cfg the module config to apply
* @param workers the worker pool to use
* @return the created session
*/
-h2_session *h2_session_rcreate(request_rec *r, struct h2_ctx *ctx,
- struct h2_workers *workers);
+apr_status_t h2_session_rcreate(h2_session **psession,
+ request_rec *r, struct h2_ctx *ctx,
+ struct h2_workers *workers);
/**
* Process the given HTTP/2 session until it is ended or a fatal
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c Sun Mar 12 14:20:29 2017
@@ -170,14 +170,23 @@ static void H2_STREAM_OUT_LOG(int lvl, h
}
}
+static apr_status_t setup_input(h2_stream *stream) {
+ if (stream->input == NULL && !stream->input_eof) {
+ h2_beam_create(&stream->input, stream->pool, stream->id,
+ "input", H2_BEAM_OWNER_SEND, 0,
+ stream->session->s->timeout);
+ h2_beam_send_from(stream->input, stream->pool);
+ }
+ return APR_SUCCESS;
+}
+
static apr_status_t close_input(h2_stream *stream)
{
conn_rec *c = stream->session->c;
- apr_status_t status;
- apr_bucket_brigade *tmp;
- apr_bucket *b;
+ apr_status_t status = APR_SUCCESS;
- if (h2_beam_is_closed(stream->input)) {
+ stream->input_eof = 1;
+ if (stream->input && h2_beam_is_closed(stream->input)) {
return APR_SUCCESS;
}
@@ -187,22 +196,30 @@ static apr_status_t close_input(h2_strea
return APR_ECONNRESET;
}
- tmp = apr_brigade_create(stream->pool, c->bucket_alloc);
if (stream->trailers && !apr_is_empty_table(stream->trailers)) {
- h2_headers *r = h2_headers_create(HTTP_OK, stream->trailers,
- NULL, stream->pool);
+ apr_bucket_brigade *tmp;
+ apr_bucket *b;
+ h2_headers *r;
+
+ tmp = apr_brigade_create(stream->pool, c->bucket_alloc);
+
+ r = h2_headers_create(HTTP_OK, stream->trailers, NULL, stream->pool);
+ stream->trailers = NULL;
b = h2_bucket_headers_create(c->bucket_alloc, r);
APR_BRIGADE_INSERT_TAIL(tmp, b);
- stream->trailers = NULL;
+
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(tmp, b);
+
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c,
H2_STRM_MSG(stream, "added trailers"));
+ setup_input(stream);
+ status = h2_beam_send(stream->input, tmp, APR_BLOCK_READ);
+ apr_brigade_destroy(tmp);
+ }
+ if (stream->input) {
+ return h2_beam_close(stream->input);
}
-
- b = apr_bucket_eos_create(c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(tmp, b);
- status = h2_beam_send(stream->input, tmp, APR_BLOCK_READ);
- apr_brigade_destroy(tmp);
- h2_beam_close(stream->input);
return status;
}
@@ -440,18 +457,16 @@ apr_status_t h2_stream_recv_DATA(h2_stre
apr_bucket_brigade *tmp;
ap_assert(stream);
- if (!stream->input) {
- return APR_EOF;
+ if (len > 0) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, session->c,
+ H2_STRM_MSG(stream, "recv DATA, len=%d"), (int)len);
+
+ tmp = apr_brigade_create(stream->pool, session->c->bucket_alloc);
+ apr_brigade_write(tmp, NULL, NULL, (const char *)data, len);
+ setup_input(stream);
+ status = h2_beam_send(stream->input, tmp, APR_BLOCK_READ);
+ apr_brigade_destroy(tmp);
}
-
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, session->c,
- H2_STRM_MSG(stream, "recv DATA, len=%d"), (int)len);
-
- tmp = apr_brigade_create(stream->pool, session->c->bucket_alloc);
- apr_brigade_write(tmp, NULL, NULL, (const char *)data, len);
- status = h2_beam_send(stream->input, tmp, APR_BLOCK_READ);
- apr_brigade_destroy(tmp);
-
stream->in_data_frames++;
stream->in_data_octets += len;
return status;
@@ -478,9 +493,8 @@ h2_stream *h2_stream_create(int id, apr_
stream->monitor = monitor;
stream->max_mem = session->max_stream_mem;
- h2_beam_create(&stream->input, pool, id, "input", H2_BEAM_OWNER_SEND, 0);
- h2_beam_send_from(stream->input, stream->pool);
- h2_beam_create(&stream->output, pool, id, "output", H2_BEAM_OWNER_RECV, 0);
+ h2_beam_create(&stream->output, pool, id, "output", H2_BEAM_OWNER_RECV, 0,
+ session->s->timeout);
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
H2_STRM_LOG(APLOGNO(03082), stream, "created"));
@@ -498,14 +512,16 @@ void h2_stream_cleanup(h2_stream *stream
* references into request pools */
apr_brigade_cleanup(stream->out_buffer);
}
- h2_beam_abort(stream->input);
- status = h2_beam_wait_empty(stream->input, APR_NONBLOCK_READ);
- if (status == APR_EAGAIN) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c,
- H2_STRM_MSG(stream, "wait on input drain"));
- status = h2_beam_wait_empty(stream->input, APR_BLOCK_READ);
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, stream->session->c,
- H2_STRM_MSG(stream, "input drain returned"));
+ if (stream->input) {
+ h2_beam_abort(stream->input);
+ status = h2_beam_wait_empty(stream->input, APR_NONBLOCK_READ);
+ if (status == APR_EAGAIN) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c,
+ H2_STRM_MSG(stream, "wait on input drain"));
+ status = h2_beam_wait_empty(stream->input, APR_BLOCK_READ);
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, stream->session->c,
+ H2_STRM_MSG(stream, "input drain returned"));
+ }
}
}
@@ -527,10 +543,26 @@ apr_pool_t *h2_stream_detach_pool(h2_str
return pool;
}
+apr_status_t h2_stream_prep_processing(h2_stream *stream)
+{
+ if (stream->request) {
+ const h2_request *r = stream->request;
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
+ H2_STRM_MSG(stream, "schedule %s %s://%s%s chunked=%d"),
+ r->method, r->scheme, r->authority, r->path, r->chunked);
+ setup_input(stream);
+ stream->scheduled = 1;
+ return APR_SUCCESS;
+ }
+ return APR_EINVAL;
+}
+
void h2_stream_rst(h2_stream *stream, int error_code)
{
stream->rst_error = error_code;
- h2_beam_abort(stream->input);
+ if (stream->input) {
+ h2_beam_abort(stream->input);
+ }
h2_beam_leave(stream->output);
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
H2_STRM_MSG(stream, "reset, error=%d"), error_code);
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_stream.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_stream.h?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_stream.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_stream.h Sun Mar 12 14:20:29 2017
@@ -77,6 +77,7 @@ struct h2_stream {
unsigned int aborted : 1; /* was aborted */
unsigned int scheduled : 1; /* stream has been scheduled */
unsigned int has_response : 1; /* response headers are known */
+ unsigned int input_eof : 1; /* no more request data coming */
unsigned int push_policy; /* which push policy to use for this request */
struct h2_task *task; /* assigned task to fullfill request */
@@ -110,6 +111,8 @@ h2_stream *h2_stream_create(int id, apr_
*/
void h2_stream_destroy(h2_stream *stream);
+apr_status_t h2_stream_prep_processing(h2_stream *stream);
+
/*
* Set a new monitor for this stream, replacing any existing one. Can
* be called with NULL to have no monitor installed.
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c Sun Mar 12 14:20:29 2017
@@ -160,6 +160,7 @@ static int h2_protocol_switch(conn_rec *
if (status != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088)
"session setup");
+ h2_ctx_clear(c);
return status;
}
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_task.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_task.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_task.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_task.c Sun Mar 12 14:20:29 2017
@@ -17,7 +17,6 @@
#include <stddef.h>
#include <apr_atomic.h>
-#include <apr_thread_cond.h>
#include <apr_strings.h>
#include <httpd.h>
@@ -386,7 +385,7 @@ static apr_status_t h2_filter_parse_h1(a
******************************************************************************/
int h2_task_can_redo(h2_task *task) {
- if (h2_beam_was_received(task->input.beam)) {
+ if (task->input.beam && h2_beam_was_received(task->input.beam)) {
/* cannot repeat that. */
return 0;
}
@@ -403,7 +402,9 @@ void h2_task_redo(h2_task *task)
void h2_task_rst(h2_task *task, int error)
{
task->rst_error = error;
- h2_beam_leave(task->input.beam);
+ if (task->input.beam) {
+ h2_beam_leave(task->input.beam);
+ }
if (!task->worker_done) {
h2_beam_abort(task->output.beam);
}
@@ -506,9 +507,9 @@ h2_task *h2_task_create(h2_stream *strea
task->request = stream->request;
task->input.beam = stream->input;
task->output.beam = stream->output;
+ task->timeout = stream->session->s->timeout;
h2_beam_send_from(stream->output, task->pool);
- apr_thread_cond_create(&task->cond, pool);
h2_ctx_create_for(slave, task);
return task;
@@ -601,6 +602,15 @@ static apr_status_t h2_task_process_requ
"h2_task(%s): create request_rec", task->id);
r = h2_request_create_rec(req, c);
if (r && (r->status == HTTP_OK)) {
+ /* set timeouts for virtual host of request */
+ if (task->timeout != r->server->timeout) {
+ task->timeout = r->server->timeout;
+ h2_beam_timeout_set(task->output.beam, task->timeout);
+ if (task->input.beam) {
+ h2_beam_timeout_set(task->input.beam, task->timeout);
+ }
+ }
+
ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
if (cs) {
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_task.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_task.h?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_task.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_task.h Sun Mar 12 14:20:29 2017
@@ -37,7 +37,6 @@
* of our own to disble those.
*/
-struct apr_thread_cond_t;
struct h2_bucket_beam;
struct h2_conn;
struct h2_mplx;
@@ -57,6 +56,7 @@ struct h2_task {
apr_pool_t *pool;
const struct h2_request *request;
+ apr_interval_time_t timeout;
int rst_error; /* h2 related stream abort error */
struct {
@@ -76,7 +76,6 @@ struct h2_task {
} output;
struct h2_mplx *mplx;
- struct apr_thread_cond_t *cond;
unsigned int filters_set : 1;
unsigned int frozen : 1;
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_version.h?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_version.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_version.h Sun Mar 12 14:20:29 2017
@@ -26,7 +26,7 @@
* @macro
* Version number of the http2 module as c string
*/
-#define MOD_HTTP2_VERSION "1.9.2"
+#define MOD_HTTP2_VERSION "1.9.3"
/**
* @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 0x010902
+#define MOD_HTTP2_VERSION_NUM 0x010903
#endif /* mod_h2_h2_version_h */
Modified: httpd/httpd/branches/2.4.x/modules/http2/mod_proxy_http2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/mod_proxy_http2.c?rev=1786582&r1=1786581&r2=1786582&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/mod_proxy_http2.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/mod_proxy_http2.c Sun Mar 12 14:20:29 2017
@@ -276,6 +276,9 @@ static void request_done(h2_proxy_sessio
h2_proxy_ctx *ctx = session->user_data;
const char *task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
+ "h2_proxy_session(%s): request done %s, touched=%d",
+ ctx->engine_id, task_id, touched);
if (status != APR_SUCCESS) {
if (!touched) {
/* untouched request, need rescheduling */
@@ -289,6 +292,12 @@ static void request_done(h2_proxy_sessio
return;
}
}
+ else if (!ctx->next) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
+ "h2_proxy_session(%s): retry untouched request",
+ ctx->engine_id);
+ ctx->next = r;
+ }
}
else {
const char *uri;
@@ -620,7 +629,7 @@ run_session:
}
cleanup:
- if (!reconnected && ctx->engine && next_request(ctx, 1) == APR_SUCCESS) {
+ if (!reconnected && next_request(ctx, 1) == APR_SUCCESS) {
/* Still more to do, tear down old conn and start over */
if (ctx->p_conn) {
ctx->p_conn->close = 1;