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/11 15:35:00 UTC

svn commit: r1786512 - in /httpd/httpd/trunk: CHANGES modules/http2/h2_conn.c modules/http2/h2_h2.c modules/http2/h2_session.c modules/http2/h2_session.h modules/http2/h2_switch.c

Author: icing
Date: Sat Mar 11 15:35:00 2017
New Revision: 1786512

URL: http://svn.apache.org/viewvc?rev=1786512&view=rev
Log:
On the trunk:

  *) mod_http2: moving session cleanup to pre_close hook to avoid races with
     modules already shut down and slave connections still operating.


Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/modules/http2/h2_conn.c
    httpd/httpd/trunk/modules/http2/h2_h2.c
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_session.h
    httpd/httpd/trunk/modules/http2/h2_switch.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat Mar 11 15:35:00 2017
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_http2: moving session cleanup to pre_close hook to avoid races with
+     modules already shut down and slave connections still operating.
+     [Stefan Eissing]
+
   *) Add <IfDirective> and <IfSection> directives.  [Joe Orton]
 
   *) mod_http2: stream timeouts now change to vhost values once the request

Modified: httpd/httpd/trunk/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn.c?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_conn.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_conn.c Sat Mar 11 15:35:00 2017
@@ -183,6 +183,7 @@ static module *h2_conn_mpm_module(void)
 apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
 {
     h2_session *session;
+    apr_status_t status;
     
     if (!workers) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911) 
@@ -191,15 +192,16 @@ apr_status_t h2_conn_setup(h2_ctx *ctx,
     }
     
     if (r) {
-        session = h2_session_rcreate(r, ctx, workers);
+        status = h2_session_rcreate(&session, r, ctx, workers);
     }
     else {
-        session = h2_session_create(c, ctx, workers);
+        status = h2_session_create(&session, c, ctx, workers);
     }
 
-    h2_ctx_session_set(ctx, session);
-    
-    return APR_SUCCESS;
+    if (status == APR_SUCCESS) {
+        h2_ctx_session_set(ctx, session);
+    }
+    return status;
 }
 
 apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
@@ -235,7 +237,20 @@ apr_status_t h2_conn_run(struct h2_ctx *
              && mpm_state != AP_MPMQ_STOPPING);
     
     if (c->cs) {
-        c->cs->state = CONN_STATE_WRITE_COMPLETION;
+        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;
+                break;
+                
+        }
     }
     
     return DONE;
@@ -243,13 +258,12 @@ apr_status_t h2_conn_run(struct h2_ctx *
 
 apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
 {
-    apr_status_t status;
-    
-    status = h2_session_pre_close(h2_ctx_session_get(ctx), async_mpm);
-    if (status == APR_SUCCESS) {
-        return DONE; /* This is the same, right? */
+    h2_session *session = h2_ctx_session_get(ctx);
+    if (session) {
+        apr_status_t status = h2_session_pre_close(session, async_mpm);
+        return (status == APR_SUCCESS)? DONE : status;
     }
-    return status;
+    return DONE;
 }
 
 conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)

Modified: httpd/httpd/trunk/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.c?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.c Sat Mar 11 15:35:00 2017
@@ -652,6 +652,7 @@ int h2_h2_process_conn(conn_rec* c)
             status = h2_conn_setup(ctx, c, NULL);
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
             if (status != APR_SUCCESS) {
+                h2_ctx_clear(c);
                 return status;
             }
         }
@@ -674,7 +675,7 @@ static int h2_h2_pre_close_conn(conn_rec
     ctx = h2_ctx_get(c, 0);
     if (ctx) {
         /* If the session has been closed correctly already, we will not
-         * fiond a h2_ctx here. The presence indicates that the session
+         * find a h2_ctx here. The presence indicates that the session
          * is still ongoing. */
         return h2_conn_pre_close(ctx, c);
     }

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Sat Mar 11 15:35:00 2017
@@ -661,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
@@ -693,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;
@@ -707,14 +710,38 @@ 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(), 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;
@@ -723,136 +750,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, 
-                                       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;
+    }
+    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;
     }
-    return session;
+    
+    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)
@@ -1919,7 +1956,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 +1993,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 +2009,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 +2036,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,12 +2224,7 @@ 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)
@@ -2201,5 +2233,5 @@ apr_status_t h2_session_pre_close(h2_ses
                   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;
+    return session_cleanup(session, "pre_close");
 }

Modified: httpd/httpd/trunk/modules/http2/h2_session.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.h?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.h Sat Mar 11 15:35:00 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/trunk/modules/http2/h2_switch.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_switch.c?rev=1786512&r1=1786511&r2=1786512&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_switch.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_switch.c Sat Mar 11 15:35:00 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;
             }