]> granicus.if.org Git - apache/blobdiff - modules/http2/mod_proxy_http2.c
mod_http2: mergine trunk+2.4.x code divergences back into a single source with proper...
[apache] / modules / http2 / mod_proxy_http2.c
index f64326549742060c523e4f54513f61d4c348dcdb..21f8e1d1f9c7ae6b4169c46a28edb309a5e74a36 100644 (file)
@@ -1,31 +1,35 @@
-/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * http://www.apache.org/licenses/LICENSE-2.0
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include <nghttp2/nghttp2.h>
 
+#include <ap_mmn.h>
 #include <httpd.h>
 #include <mod_proxy.h>
 #include "mod_http2.h"
 
 
 #include "mod_proxy_http2.h"
-#include "h2_request.h"
-#include "h2_util.h"
+#include "h2.h"
+#include "h2_proxy_util.h"
 #include "h2_version.h"
 #include "h2_proxy_session.h"
 
+#define H2MIN(x,y) ((x) < (y) ? (x) : (y))
+
 static void register_hook(apr_pool_t *p);
 
 AP_DECLARE_MODULE(proxy_http2) = {
@@ -35,7 +39,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 */
@@ -44,9 +51,10 @@ static apr_status_t (*req_engine_push)(const char *name, request_rec *r,
                                        http2_req_engine_init *einit);
 static apr_status_t (*req_engine_pull)(h2_req_engine *engine, 
                                        apr_read_type_e block, 
-                                       apr_uint32_t capacity, 
+                                       int capacity, 
                                        request_rec **pr);
-static void (*req_engine_done)(h2_req_engine *engine, conn_rec *r_conn);
+static void (*req_engine_done)(h2_req_engine *engine, conn_rec *r_conn,
+                               apr_status_t status);
                                        
 typedef struct h2_proxy_ctx {
     conn_rec *owner;
@@ -63,9 +71,9 @@ typedef struct h2_proxy_ctx {
     const char *engine_id;
     const char *engine_type;
     apr_pool_t *engine_pool;    
-    apr_uint32_t req_buffer_size;
-    request_rec *next;
-    apr_size_t capacity;
+    apr_size_t req_buffer_size;
+    h2_proxy_fifo *requests;
+    int capacity;
     
     unsigned standalone : 1;
     unsigned is_ssl : 1;
@@ -125,12 +133,12 @@ static int proxy_http2_canon(request_rec *r, char *url)
     apr_port_t port, def_port;
 
     /* ap_port_of_scheme() */
-    if (ap_casecmpstrn(url, "h2c:", 4) == 0) {
+    if (ap_cstr_casecmpn(url, "h2c:", 4) == 0) {
         url += 4;
         scheme = "h2c";
         http_scheme = "http";
     }
-    else if (ap_casecmpstrn(url, "h2:", 3) == 0) {
+    else if (ap_cstr_casecmpn(url, "h2:", 3) == 0) {
         url += 3;
         scheme = "h2";
         http_scheme = "https";
@@ -168,7 +176,7 @@ static int proxy_http2_canon(request_rec *r, char *url)
             path = url;   /* this is the raw path */
         }
         else {
-            path = ap_proxy_canonenc(r->pool, url, strlen(url),
+            path = ap_proxy_canonenc(r->pool, url, (int)strlen(url),
                                      enc_path, 0, r->proxyreq);
             search = r->args;
         }
@@ -210,43 +218,30 @@ static apr_status_t proxy_engine_init(h2_req_engine *engine,
                                         const char *id, 
                                         const char *type,
                                         apr_pool_t *pool, 
-                                        apr_uint32_t req_buffer_size,
+                                        apr_size_t req_buffer_size,
                                         request_rec *r,
                                         http2_output_consumed **pconsumed,
                                         void **pctx)
 {
     h2_proxy_ctx *ctx = ap_get_module_config(r->connection->conn_config, 
                                              &proxy_http2_module);
-    if (ctx) {
-        conn_rec *c = ctx->owner;
-        h2_proxy_ctx *nctx;
-        
-        /* we need another lifetime for this. If we do not host
-         * an engine, the context lives in r->pool. Since we expect
-         * to server more than r, we need to live longer */
-        nctx = apr_pcalloc(pool, sizeof(*nctx));
-        if (nctx == NULL) {
-            return APR_ENOMEM;
-        }
-        memcpy(nctx, ctx, sizeof(*nctx));
-        ctx = nctx;
-        ctx->pool = pool;
-        ctx->engine = engine;
-        ctx->engine_id = id;
-        ctx->engine_type = type;
-        ctx->engine_pool = pool;
-        ctx->req_buffer_size = req_buffer_size;
-        ctx->capacity = 100;
-
-        ap_set_module_config(c->conn_config, &proxy_http2_module, ctx);
-
-        *pconsumed = out_consumed;
-        *pctx = ctx;
-        return APR_SUCCESS;
+    if (!ctx) {
+        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03368)
+                      "h2_proxy_session, engine init, no ctx found");
+        return APR_ENOTIMPL;
     }
-    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03368)
-                  "h2_proxy_session, engine init, no ctx found");
-    return APR_ENOTIMPL;
+    
+    ctx->pool = pool;
+    ctx->engine = engine;
+    ctx->engine_id = id;
+    ctx->engine_type = type;
+    ctx->engine_pool = pool;
+    ctx->req_buffer_size = req_buffer_size;
+    ctx->capacity = H2MIN(100, h2_proxy_fifo_capacity(ctx->requests));
+    
+    *pconsumed = out_consumed;
+    *pctx = ctx;
+    return APR_SUCCESS;
 }
 
 static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
@@ -258,8 +253,8 @@ static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
     url = apr_table_get(r->notes, H2_PROXY_REQ_URL_NOTE);
     apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
                    ctx->p_conn->connection->local_addr->port));
-    status = h2_proxy_session_submit(session, url, r);
-    if (status != OK) {
+    status = h2_proxy_session_submit(session, url, r, ctx->standalone);
+    if (status != APR_SUCCESS) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, r->connection, APLOGNO(03351)
                       "pass request body failed to %pI (%s) from %s (%s)",
                       ctx->p_conn->addr, ctx->p_conn->hostname ? 
@@ -269,64 +264,74 @@ static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
     return status;
 }
 
-static void request_done(h2_proxy_session *session, request_rec *r,
-                         int complete, int touched)
+static void request_done(h2_proxy_ctx *ctx, request_rec *r,
+                         apr_status_t status, int touched)
 {   
-    h2_proxy_ctx *ctx = session->user_data;
     const char *task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
-    
-    if (!complete && !touched) {
-        /* untouched request, need rescheduling */
-        if (req_engine_push && is_h2 && is_h2(ctx->owner)) {
-            if (req_engine_push(ctx->engine_type, r, NULL) == APR_SUCCESS) {
-                /* push to engine */
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, r->connection, 
-                              APLOGNO(03369)
-                              "h2_proxy_session(%s): rescheduled request %s",
-                              ctx->engine_id, task_id);
-                return;
-            }
+
+    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 */
+            status = h2_proxy_fifo_push(ctx->requests, r);
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
+                          APLOGNO(03369)
+                          "h2_proxy_session(%s): rescheduled request %s",
+                          ctx->engine_id, task_id);
+            return;
+        }
+        else {
+            const char *uri;
+            uri = apr_uri_unparse(r->pool, &r->parsed_uri, 0);
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
+                          APLOGNO(03471) "h2_proxy_session(%s): request %s -> %s "
+                          "not complete, cannot repeat", 
+                          ctx->engine_id, task_id, uri);
         }
     }
     
-    if (r == ctx->rbase && complete) {
-        ctx->r_status = APR_SUCCESS;
+    if (r == ctx->rbase) {
+        ctx->r_status = ((status == APR_SUCCESS)? APR_SUCCESS
+                         : HTTP_SERVICE_UNAVAILABLE);
     }
     
-    if (complete) {
-        if (req_engine_done && ctx->engine) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, r->connection, 
-                          APLOGNO(03370)
-                          "h2_proxy_session(%s): finished request %s",
-                          ctx->engine_id, task_id);
-            req_engine_done(ctx->engine, r->connection);
-        }
-    }
-    else {
-        if (req_engine_done && ctx->engine) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, r->connection, 
-                          APLOGNO(03371)
-                          "h2_proxy_session(%s): failed request %s",
-                          ctx->engine_id, task_id);
-            req_engine_done(ctx->engine, r->connection);
-        }
+    if (req_engine_done && ctx->engine) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
+                      APLOGNO(03370)
+                      "h2_proxy_session(%s): finished request %s",
+                      ctx->engine_id, task_id);
+        req_engine_done(ctx->engine, r->connection, status);
     }
 }    
 
+static void session_req_done(h2_proxy_session *session, request_rec *r,
+                             apr_status_t status, int touched)
+{
+    request_done(session->user_data, r, status, touched);
+}
+
 static apr_status_t next_request(h2_proxy_ctx *ctx, int before_leave)
 {
-    if (ctx->next) {
+    if (h2_proxy_fifo_count(ctx->requests) > 0) {
         return APR_SUCCESS;
     }
     else if (req_engine_pull && ctx->engine) {
         apr_status_t status;
+        request_rec *r = NULL;
+        
         status = req_engine_pull(ctx->engine, before_leave? 
                                  APR_BLOCK_READ: APR_NONBLOCK_READ, 
-                                 ctx->capacity, &ctx->next);
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, ctx->owner, 
-                      "h2_proxy_engine(%s): pulled request %s", 
-                      ctx->engine_id, 
-                      (ctx->next? ctx->next->the_request : "NULL"));
+                                 ctx->capacity, &r);
+        if (status == APR_SUCCESS && r) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, ctx->owner, 
+                          "h2_proxy_engine(%s): pulled request (%s) %s", 
+                          ctx->engine_id, 
+                          before_leave? "before leave" : "regular", 
+                          r->the_request);
+            h2_proxy_fifo_push(ctx->requests, r);
+        }
         return APR_STATUS_IS_EAGAIN(status)? APR_SUCCESS : status;
     }
     return APR_EOF;
@@ -334,15 +339,19 @@ static apr_status_t next_request(h2_proxy_ctx *ctx, int before_leave)
 
 static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
     apr_status_t status = OK;
+    int h2_front;
+    request_rec *r;
     
     /* Step Four: Send the Request in a new HTTP/2 stream and
      * loop until we got the response or encounter errors.
      */
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner, 
                   "eng(%s): setup session", ctx->engine_id);
-    ctx->session = h2_proxy_session_setup(ctx->engine_id, ctx->p_conn, ctx->conf, 
-                                          30, h2_log2(ctx->req_buffer_size), 
-                                          request_done);
+    h2_front = is_h2? is_h2(ctx->owner) : 0;
+    ctx->session = h2_proxy_session_setup(ctx->engine_id, ctx->p_conn, ctx->conf,
+                                          h2_front, 30, 
+                                          h2_proxy_log2((int)ctx->req_buffer_size), 
+                                          session_req_done);
     if (!ctx->session) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, 
                       APLOGNO(03372) "session unavailable");
@@ -353,10 +362,9 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
                   "eng(%s): run session %s", ctx->engine_id, ctx->session->id);
     ctx->session->user_data = ctx;
     
-    while (1) {
-        if (ctx->next) {
-            add_request(ctx->session, ctx->next);
-            ctx->next = NULL;
+    while (!ctx->owner->aborted) {
+        if (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
+            add_request(ctx->session, r);
         }
         
         status = h2_proxy_session_process(ctx->session);
@@ -366,7 +374,8 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
             /* ongoing processing, call again */
             if (ctx->session->remote_max_concurrent > 0
                 && ctx->session->remote_max_concurrent != ctx->capacity) {
-                ctx->capacity = ctx->session->remote_max_concurrent;
+                ctx->capacity = H2MIN((int)ctx->session->remote_max_concurrent, 
+                                      h2_proxy_fifo_capacity(ctx->requests));
             }
             s2 = next_request(ctx, 0);
             if (s2 == APR_ECONNABORTED) {
@@ -374,24 +383,30 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, s2, ctx->owner, 
                               APLOGNO(03374) "eng(%s): pull request", 
                               ctx->engine_id);
-                status = s2;
+                /* give notice that we're leaving and cancel all ongoing
+                 * streams. */
+                next_request(ctx, 1); 
+                h2_proxy_session_cancel_all(ctx->session);
+                h2_proxy_session_process(ctx->session);
+                status = ctx->r_status = APR_SUCCESS;
                 break;
             }
-            if (!ctx->next && h2_ihash_is_empty(ctx->session->streams)) {
+            if ((h2_proxy_fifo_count(ctx->requests) == 0) 
+                && h2_proxy_ihash_empty(ctx->session->streams)) {
                 break;
             }
         }
         else {
             /* end of processing, maybe error */
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, 
-                          APLOGNO(03375) "eng(%s): end of session run", 
-                          ctx->engine_id);
+                          APLOGNO(03375) "eng(%s): end of session %s", 
+                          ctx->engine_id, ctx->session->id);
             /*
              * Any open stream of that session needs to
              * a) be reopened on the new session iff safe to do so
              * b) reported as done (failed) otherwise
              */
-            h2_proxy_session_cleanup(ctx->session, request_done);
+            h2_proxy_session_cleanup(ctx->session, session_req_done);
             break;
         }
     }
@@ -402,7 +417,7 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
     return status;
 }
 
-static h2_proxy_ctx *push_request_somewhere(h2_proxy_ctx *ctx)
+static apr_status_t push_request_somewhere(h2_proxy_ctx *ctx, request_rec *r)
 {
     conn_rec *c = ctx->owner;
     const char *engine_type, *hostname;
@@ -412,21 +427,15 @@ static h2_proxy_ctx *push_request_somewhere(h2_proxy_ctx *ctx)
     engine_type = apr_psprintf(ctx->pool, "proxy_http2 %s%s", hostname, 
                                ctx->server_portstr);
     
-    if (c->master && req_engine_push && ctx->next && is_h2 && is_h2(c)) {
+    if (c->master && req_engine_push && r && is_h2 && is_h2(c)) {
         /* If we are have req_engine capabilities, push the handling of this
          * request (e.g. slave connection) to a proxy_http2 engine which 
          * uses the same backend. We may be called to create an engine 
          * ourself. */
-        if (req_engine_push(engine_type, ctx->next, proxy_engine_init)
-            == APR_SUCCESS) {
-            /* to renew the lifetime, we might have set a new ctx */
-            ctx = ap_get_module_config(c->conn_config, &proxy_http2_module);
+        if (req_engine_push(engine_type, r, proxy_engine_init) == APR_SUCCESS) {
             if (ctx->engine == NULL) {
-                /* Another engine instance has taken over processing of this
-                 * request. */
-                ctx->r_status = SUSPENDED;
-                ctx->next = NULL;
-                return ctx;
+                /* request has been assigned to an engine in another thread */
+                return SUSPENDED;
             }
         }
     }
@@ -447,7 +456,8 @@ static h2_proxy_ctx *push_request_somewhere(h2_proxy_ctx *ctx)
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, 
                       "H2: hosting engine %s", ctx->engine_id);
     }
-    return ctx;
+
+    return h2_proxy_fifo_push(ctx->requests, r);
 }
 
 static int proxy_http2_handler(request_rec *r, 
@@ -464,7 +474,7 @@ static int proxy_http2_handler(request_rec *r,
     apr_status_t status;
     h2_proxy_ctx *ctx;
     apr_uri_t uri;
-    int reconnected = 0;
+    int reconnects = 0;
     
     /* find the scheme */
     if ((url[0] != 'h' && url[0] != 'H') || url[1] != '2') {
@@ -489,6 +499,7 @@ static int proxy_http2_handler(request_rec *r,
         default:
             return DECLINED;
     }
+    
     ctx = apr_pcalloc(r->pool, sizeof(*ctx));
     ctx->owner      = r->connection;
     ctx->pool       = r->pool;
@@ -500,8 +511,9 @@ static int proxy_http2_handler(request_rec *r,
     ctx->conf       = conf;
     ctx->flushall   = apr_table_get(r->subprocess_env, "proxy-flushall")? 1 : 0;
     ctx->r_status   = HTTP_SERVICE_UNAVAILABLE;
-    ctx->next       = r;
-    r = NULL;
+    
+    h2_proxy_fifo_set_create(&ctx->requests, ctx->pool, 100);
+    
     ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, ctx);
 
     /* scheme says, this is for us. */
@@ -519,11 +531,6 @@ run_connect:
     }
 
     ctx->p_conn->is_ssl = ctx->is_ssl;
-    if (ctx->is_ssl) {
-        /* If there is still some data on an existing ssl connection, now
-         * would be a good timne to get rid of it. */
-        ap_proxy_ssl_connection_cleanup(ctx->p_conn, ctx->rbase);
-    }
 
     /* Step One: Determine the URL to connect to (might be a proxy),
      * initialize the backend accordingly and determine the server 
@@ -538,10 +545,11 @@ run_connect:
     
     /* If we are not already hosting an engine, try to push the request 
      * to an already existing engine or host a new engine here. */
-    if (!ctx->engine) {
-        ctx = push_request_somewhere(ctx);
+    if (r && !ctx->engine) {
+        ctx->r_status = push_request_somewhere(ctx, r);
+        r = NULL;
         if (ctx->r_status == SUSPENDED) {
-            /* request was pushed to another engine */
+            /* request was pushed to another thread, leave processing here */
             goto cleanup;
         }
     }
@@ -551,35 +559,28 @@ run_connect:
      * backend->hostname. */
     if (ap_proxy_connect_backend(ctx->proxy_func, ctx->p_conn, ctx->worker, 
                                  ctx->server)) {
-        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctx->owner, APLOGNO(03352)
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03352)
                       "H2: failed to make connection to backend: %s",
                       ctx->p_conn->hostname);
-        goto cleanup;
+        goto reconnect;
     }
     
     /* Step Three: Create conn_rec for the socket we have open now. */
     if (!ctx->p_conn->connection) {
-        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, 
-                      locurl, ctx->p_conn->hostname);
-        if ((status = ap_proxy_connection_create(ctx->proxy_func, ctx->p_conn,
-                                                 ctx->owner, 
-                                                 ctx->server)) != OK) {
-            goto cleanup;
-        }
-        
-        /*
-         * On SSL connections set a note on the connection what CN is
-         * requested, such that mod_ssl can check if it is requested to do
-         * so.
-         */
-        if (ctx->p_conn->ssl_hostname) {
-            apr_table_setn(ctx->p_conn->connection->notes,
-                           "proxy-request-hostname", ctx->p_conn->ssl_hostname);
+        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, 
+                          locurl, ctx->p_conn->hostname);
+            goto reconnect;
         }
         
-        if (ctx->is_ssl) {
+        if (!ctx->p_conn->data && ctx->is_ssl) {
+            /* New SSL connection: set a note on the connection about what
+             * protocol we want.
+             */
             apr_table_setn(ctx->p_conn->connection->notes,
                            "proxy-request-alpn-protos", "h2");
         }
@@ -599,29 +600,44 @@ run_session:
         ctx->engine = NULL;
     }
 
-cleanup:
-    if (!reconnected && ctx->engine && next_request(ctx, 1) == APR_SUCCESS) {
+reconnect:
+    if (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;
+#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
             proxy_run_detach_backend(r, ctx->p_conn);
+#endif
             ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server);
             ctx->p_conn = NULL;
         }
-        reconnected = 1; /* we do this only once, then fail */
-        goto run_connect;
+        ++reconnects;
+        if (reconnects < 5 && !ctx->owner->aborted) {
+            goto run_connect;
+        } 
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(10023)
+                      "giving up after %d reconnects, %d requests todo",
+                      reconnects, h2_proxy_fifo_count(ctx->requests));
     }
     
+cleanup:
     if (ctx->p_conn) {
         if (status != APR_SUCCESS) {
             /* close socket when errors happened or session shut down (EOF) */
             ctx->p_conn->close = 1;
         }
+#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
         proxy_run_detach_backend(ctx->rbase, ctx->p_conn);
+#endif
         ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server);
         ctx->p_conn = NULL;
     }
 
+    /* Any requests will still have need to fail */
+    while (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
+        request_done(ctx, r, HTTP_SERVICE_UNAVAILABLE, 1);
+    }
+    
     ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, NULL);
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, 
                   APLOGNO(03377) "leaving handler");