From 27028fe3f39343c471d51acbb922ee0957fcf6df Mon Sep 17 00:00:00 2001
From: Stefan Eissing <icing@apache.org>
Date: Tue, 20 Oct 2015 14:13:06 +0000
Subject: [PATCH] moved ssl handshake trigger from mod_http2 to new
 process_connection hook in mod_ssl

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1709602 13f79535-47bb-0310-9956-ffa450edef68
---
 modules/http2/h2_h2.c | 109 ++++++++++++++++--------------------------
 modules/ssl/mod_ssl.c |  23 +++++++++
 2 files changed, 63 insertions(+), 69 deletions(-)

diff --git a/modules/http2/h2_h2.c b/modules/http2/h2_h2.c
index 383d2ab443..ec2daf126f 100644
--- a/modules/http2/h2_h2.c
+++ b/modules/http2/h2_h2.c
@@ -533,6 +533,7 @@ int h2_allows_h2_upgrade(conn_rec *c)
  * Register various hooks
  */
 static const char *const mod_reqtimeout[] = { "reqtimeout.c", NULL};
+static const char* const mod_ssl[]        = {"mod_ssl.c", NULL};
 
 void h2_h2_register_hooks(void)
 {
@@ -540,7 +541,8 @@ void h2_h2_register_hooks(void)
      * take over, if h2* was selected as protocol.
      */
     ap_hook_process_connection(h2_h2_process_conn, 
-                               NULL, NULL, APR_HOOK_FIRST);
+                               mod_ssl, NULL, APR_HOOK_MIDDLE);
+                               
     /* Perform connection cleanup before the actual processing happens.
      */
     ap_hook_process_connection(h2_h2_remove_timeout, 
@@ -576,80 +578,49 @@ int h2_h2_process_conn(conn_rec* c)
         return DECLINED;
     }
 
-    /* If we have not already switched to a h2* protocol and the connection 
-     * is on "http/1.1"
-     * -> on TLS, try to trigger ALPN
-     * -> sniff for the magic PRIamble if enabled
-     */
     if (h2_ctx_protocol_get(c)) {
-        /* we have a protocol selected */
+        /* Something has been negotiated */
     }
-    else if (!strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))) {
-        apr_bucket_brigade* temp = NULL;
-        apr_status_t status = APR_SUCCESS;
-        int is_tls = h2_h2_is_tls(c);
-    
-        /* we are still on HTTP/1.1, trigger ALPN if TLS */
-        /* TODO: this part should be in mod_ssl */
-        if (is_tls) {
-            /* trigger the TLS handshake */
-            temp = apr_brigade_create(c->pool, c->bucket_alloc);
-            status = ap_get_brigade(c->input_filters, temp,
-                                    AP_MODE_INIT, APR_BLOCK_READ, 0);
-            if (status != APR_SUCCESS) {
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
-                              "h2_h2, failed to trigger ALPN");
-                return DECLINED;
-            }
-        }
-
-        if (h2_ctx_protocol_get(c)) {
-            /* NOW, something has been negotiated */
+    else if (!strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))
+             && h2_allows_h2_direct(c) 
+             && h2_is_acceptable_connection(c, 1)) {
+        /* connection still is on http/1.1 and H2Direct is enabled. 
+         * Otherwise connection is in a fully acceptable state.
+         * -> peek at the first 24 incoming bytes
+         */
+        apr_bucket_brigade *temp;
+        apr_status_t status;
+        char *s = NULL;
+        apr_size_t slen;
+        
+        temp = apr_brigade_create(c->pool, c->bucket_alloc);
+        status = ap_get_brigade(c->input_filters, temp,
+                                AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24);
+        
+        if (status != APR_SUCCESS) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
+                          "h2_h2, error reading 24 bytes speculative");
+            apr_brigade_destroy(temp);
+            return DECLINED;
         }
-        else if (!strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))
-            && h2_allows_h2_direct(c) 
-            && h2_is_acceptable_connection(c, 1)) {
-            /* ALPN might have been triggered, but we're still on
-             * http/1.1. Check the actual bytes read for the H2 Magic
-             * Token, *if* H2Direct mode is enabled here *and*
-             * connection is in a fully acceptable state.
-             */
-            char *s = NULL;
-            apr_size_t slen;
-
-            if (!temp) {
-                temp = apr_brigade_create(c->pool, c->bucket_alloc);
-            }
-            
-            status = ap_get_brigade(c->input_filters, temp,
-                                    AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24);
-                                    
-            if (status != APR_SUCCESS) {
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
-                              "h2_h2, error reading 24 bytes speculative");
-                return DECLINED;
-            }
-            
-            apr_brigade_pflatten(temp, &s, &slen, c->pool);
-            if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) {
-                ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                              "h2_h2, direct mode detected");
-                h2_ctx_protocol_set(ctx, is_tls? "h2" : "h2c");
-            }
-            else {
-                ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                              "h2_h2, not detected in %d bytes: %s", 
-                              (int)slen, s);
-            }
-            
-            if (temp) {
-                apr_brigade_destroy(temp);
-            }
+        
+        apr_brigade_pflatten(temp, &s, &slen, c->pool);
+        if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                          "h2_h2, direct mode detected");
+            h2_ctx_protocol_set(ctx, h2_h2_is_tls(c)? "h2" : "h2c");
         }
         else {
-            /* the connection is not HTTP/1.1 or not for us, don't touch it */
-            return DECLINED;
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+                          "h2_h2, not detected in %d bytes: %s", 
+                          (int)slen, s);
         }
+        
+        apr_brigade_destroy(temp);
+    }
+    else {
+        /* the connection is not HTTP/1.1 or not for us, don't touch it */
+        return DECLINED;
     }
 
     /* If "h2" was selected as protocol (by whatever mechanism), take over
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
index 4b7d1818b7..be3b037e1e 100644
--- a/modules/ssl/mod_ssl.c
+++ b/modules/ssl/mod_ssl.c
@@ -550,6 +550,7 @@ static apr_port_t ssl_hook_default_port(const request_rec *r)
 
 static int ssl_hook_pre_connection(conn_rec *c, void *csd)
 {
+
     SSLSrvConfigRec *sc;
     SSLConnRec *sslconn = myConnConfig(c);
 
@@ -591,6 +592,26 @@ static int ssl_hook_pre_connection(conn_rec *c, void *csd)
     return ssl_init_ssl_connection(c, NULL);
 }
 
+static int ssl_hook_process_connection(conn_rec* c)
+{
+    SSLConnRec *sslconn = myConnConfig(c);
+
+    if (sslconn && !sslconn->disabled) {
+        /* On an active SSL connection, let the input filters initialize
+         * themselves which triggers the handshake, which again triggers
+         * all kinds of useful things such as SNI and ALPN.
+         */
+        apr_bucket_brigade* temp;
+
+        temp = apr_brigade_create(c->pool, c->bucket_alloc);
+        ap_get_brigade(c->input_filters, temp,
+                       AP_MODE_INIT, APR_BLOCK_READ, 0);
+        apr_brigade_destroy(temp);
+    }
+    
+    return DECLINED;
+}
+
 /*
  *  the module registration phase
  */
@@ -604,6 +625,8 @@ static void ssl_register_hooks(apr_pool_t *p)
     ssl_io_filter_register(p);
 
     ap_hook_pre_connection(ssl_hook_pre_connection,NULL,NULL, APR_HOOK_MIDDLE);
+    ap_hook_process_connection(ssl_hook_process_connection, 
+                                                   NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_test_config   (ssl_hook_ConfigTest,    NULL,NULL, APR_HOOK_MIDDLE);
     ap_hook_post_config   (ssl_init_Module,        NULL,NULL, APR_HOOK_MIDDLE);
     ap_hook_http_scheme   (ssl_hook_http_scheme,   NULL,NULL, APR_HOOK_MIDDLE);
-- 
2.40.0