httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ic...@apache.org
Subject svn commit: r1715371 [2/6] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ modules/http2/
Date Fri, 20 Nov 2015 15:13:11 GMT
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c Fri Nov 20 15:13:11 2015
@@ -54,6 +54,383 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_is_http
 static int (*opt_ssl_engine_disable)(conn_rec*);
 static int (*opt_ssl_is_https)(conn_rec*);
 /*******************************************************************************
+ * SSL var lookup
+ */
+APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
+                        (apr_pool_t *, server_rec *,
+                         conn_rec *, request_rec *,
+                         char *));
+static char *(*opt_ssl_var_lookup)(apr_pool_t *, server_rec *,
+                                   conn_rec *, request_rec *,
+                                   char *);
+
+
+/*******************************************************************************
+ * HTTP/2 error stuff
+ */
+static const char *h2_err_descr[] = {
+    "no error",                    /* 0x0 */
+    "protocol error",
+    "internal error",
+    "flow control error",
+    "settings timeout",
+    "stream closed",               /* 0x5 */
+    "frame size error",
+    "refused stream",
+    "cancel",
+    "compression error",
+    "connect error",               /* 0xa */
+    "enhance your calm",
+    "inadequate security",
+    "http/1.1 required",
+};
+
+const char *h2_h2_err_description(unsigned int h2_error)
+{
+    if (h2_error < (sizeof(h2_err_descr)/sizeof(h2_err_descr[0]))) {
+        return h2_err_descr[h2_error];
+    }
+    return "unknown http/2 errotr code";
+}
+
+/*******************************************************************************
+ * Check connection security requirements of RFC 7540
+ */
+
+/*
+ * Black Listed Ciphers from RFC 7549 Appendix A
+ *
+ */
+static const char *RFC7540_names[] = {
+    /* ciphers with NULL encrpytion */
+    "NULL-MD5",                         /* TLS_NULL_WITH_NULL_NULL */
+    /* same */                          /* TLS_RSA_WITH_NULL_MD5 */
+    "NULL-SHA",                         /* TLS_RSA_WITH_NULL_SHA */
+    "NULL-SHA256",                      /* TLS_RSA_WITH_NULL_SHA256 */
+    "PSK-NULL-SHA",                     /* TLS_PSK_WITH_NULL_SHA */
+    "DHE-PSK-NULL-SHA",                 /* TLS_DHE_PSK_WITH_NULL_SHA */
+    "RSA-PSK-NULL-SHA",                 /* TLS_RSA_PSK_WITH_NULL_SHA */
+    "PSK-NULL-SHA256",                  /* TLS_PSK_WITH_NULL_SHA256 */
+    "PSK-NULL-SHA384",                  /* TLS_PSK_WITH_NULL_SHA384 */
+    "DHE-PSK-NULL-SHA256",              /* TLS_DHE_PSK_WITH_NULL_SHA256 */
+    "DHE-PSK-NULL-SHA384",              /* TLS_DHE_PSK_WITH_NULL_SHA384 */
+    "RSA-PSK-NULL-SHA256",              /* TLS_RSA_PSK_WITH_NULL_SHA256 */
+    "RSA-PSK-NULL-SHA384",              /* TLS_RSA_PSK_WITH_NULL_SHA384 */
+    "ECDH-ECDSA-NULL-SHA",              /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
+    "ECDHE-ECDSA-NULL-SHA",             /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
+    "ECDH-RSA-NULL-SHA",                /* TLS_ECDH_RSA_WITH_NULL_SHA */
+    "ECDHE-RSA-NULL-SHA",               /* TLS_ECDHE_RSA_WITH_NULL_SHA */
+    "AECDH-NULL-SHA",                   /* TLS_ECDH_anon_WITH_NULL_SHA */
+    "ECDHE-PSK-NULL-SHA",               /* TLS_ECDHE_PSK_WITH_NULL_SHA */
+    "ECDHE-PSK-NULL-SHA256",            /* TLS_ECDHE_PSK_WITH_NULL_SHA256 */
+    "ECDHE-PSK-NULL-SHA384",            /* TLS_ECDHE_PSK_WITH_NULL_SHA384 */
+    
+    /* DES/3DES ciphers */
+    "PSK-3DES-EDE-CBC-SHA",             /* TLS_PSK_WITH_3DES_EDE_CBC_SHA */
+    "DHE-PSK-3DES-EDE-CBC-SHA",         /* TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA */
+    "RSA-PSK-3DES-EDE-CBC-SHA",         /* TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA */
+    "ECDH-ECDSA-DES-CBC3-SHA",          /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA */
+    "ECDHE-ECDSA-DES-CBC3-SHA",         /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA */
+    "ECDH-RSA-DES-CBC3-SHA",            /* TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA */
+    "ECDHE-RSA-DES-CBC3-SHA",           /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */
+    "AECDH-DES-CBC3-SHA",               /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
+    "SRP-3DES-EDE-CBC-SHA",             /* TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA */
+    "SRP-RSA-3DES-EDE-CBC-SHA",         /* TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA */
+    "SRP-DSS-3DES-EDE-CBC-SHA",         /* TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA */
+    "ECDHE-PSK-3DES-EDE-CBC-SHA",       /* TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA */
+    "DES-CBC-SHA",                      /* TLS_RSA_WITH_DES_CBC_SHA */
+    "DES-CBC3-SHA",                     /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */
+    "DHE-DSS-DES-CBC3-SHA",             /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */
+    "DHE-RSA-DES-CBC-SHA",              /* TLS_DHE_RSA_WITH_DES_CBC_SHA */
+    "DHE-RSA-DES-CBC3-SHA",             /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */
+    "ADH-DES-CBC-SHA",                  /* TLS_DH_anon_WITH_DES_CBC_SHA */
+    "ADH-DES-CBC3-SHA",                 /* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */
+    "EXP-DH-DSS-DES-CBC-SHA",           /* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */
+    "DH-DSS-DES-CBC-SHA",               /* TLS_DH_DSS_WITH_DES_CBC_SHA */
+    "DH-DSS-DES-CBC3-SHA",              /* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */
+    "EXP-DH-RSA-DES-CBC-SHA",           /* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */
+    "DH-RSA-DES-CBC-SHA",               /* TLS_DH_RSA_WITH_DES_CBC_SHA */
+    "DH-RSA-DES-CBC3-SHA",              /* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */
+
+    /* blacklisted EXPORT ciphers */
+    "EXP-RC4-MD5",                      /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */
+    "EXP-RC2-CBC-MD5",                  /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */
+    "EXP-DES-CBC-SHA",                  /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */
+    "EXP-DHE-DSS-DES-CBC-SHA",          /* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */
+    "EXP-DHE-RSA-DES-CBC-SHA",          /* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */
+    "EXP-ADH-DES-CBC-SHA",              /* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */
+    "EXP-ADH-RC4-MD5",                  /* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */
+
+    /* blacklisted RC4 encryption */
+    "RC4-MD5",                          /* TLS_RSA_WITH_RC4_128_MD5 */
+    "RC4-SHA",                          /* TLS_RSA_WITH_RC4_128_SHA */
+    "ADH-RC4-MD5",                      /* TLS_DH_anon_WITH_RC4_128_MD5 */
+    "KRB5-RC4-SHA",                     /* TLS_KRB5_WITH_RC4_128_SHA */
+    "KRB5-RC4-MD5",                     /* TLS_KRB5_WITH_RC4_128_MD5 */
+    "EXP-KRB5-RC4-SHA",                 /* TLS_KRB5_EXPORT_WITH_RC4_40_SHA */
+    "EXP-KRB5-RC4-MD5",                 /* TLS_KRB5_EXPORT_WITH_RC4_40_MD5 */
+    "PSK-RC4-SHA",                      /* TLS_PSK_WITH_RC4_128_SHA */
+    "DHE-PSK-RC4-SHA",                  /* TLS_DHE_PSK_WITH_RC4_128_SHA */
+    "RSA-PSK-RC4-SHA",                  /* TLS_RSA_PSK_WITH_RC4_128_SHA */
+    "ECDH-ECDSA-RC4-SHA",               /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */
+    "ECDHE-ECDSA-RC4-SHA",              /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA */
+    "ECDH-RSA-RC4-SHA",                 /* TLS_ECDH_RSA_WITH_RC4_128_SHA */
+    "ECDHE-RSA-RC4-SHA",                /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
+    "AECDH-RC4-SHA",                    /* TLS_ECDH_anon_WITH_RC4_128_SHA */
+    "ECDHE-PSK-RC4-SHA",                /* TLS_ECDHE_PSK_WITH_RC4_128_SHA */
+
+    /* blacklisted AES128 encrpytion ciphers */
+    "AES128-SHA256",                    /* TLS_RSA_WITH_AES_128_CBC_SHA */
+    "DH-DSS-AES128-SHA",                /* TLS_DH_DSS_WITH_AES_128_CBC_SHA */
+    "DH-RSA-AES128-SHA",                /* TLS_DH_RSA_WITH_AES_128_CBC_SHA */
+    "DHE-DSS-AES128-SHA",               /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA */
+    "DHE-RSA-AES128-SHA",               /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA */
+    "ADH-AES128-SHA",                   /* TLS_DH_anon_WITH_AES_128_CBC_SHA */
+    "AES128-SHA256",                    /* TLS_RSA_WITH_AES_128_CBC_SHA256 */
+    "DH-DSS-AES128-SHA256",             /* TLS_DH_DSS_WITH_AES_128_CBC_SHA256 */
+    "DH-RSA-AES128-SHA256",             /* TLS_DH_RSA_WITH_AES_128_CBC_SHA256 */
+    "DHE-DSS-AES128-SHA256",            /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 */
+    "DHE-RSA-AES128-SHA256",            /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 */
+    "ECDH-ECDSA-AES128-SHA",            /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
+    "ECDHE-ECDSA-AES128-SHA",           /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
+    "ECDH-RSA-AES128-SHA",              /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA */
+    "ECDHE-RSA-AES128-SHA",             /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */
+    "AECDH-AES128-SHA",                 /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
+    "ECDHE-ECDSA-AES128-SHA256",        /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 */
+    "ECDH-ECDSA-AES128-SHA256",         /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 */
+    "ECDHE-RSA-AES128-SHA256",          /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 */
+    "ECDH-RSA-AES128-SHA256",           /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 */
+    "ADH-AES128-SHA256",                /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
+    "PSK-AES128-CBC-SHA",               /* TLS_PSK_WITH_AES_128_CBC_SHA */
+    "DHE-PSK-AES128-CBC-SHA",           /* TLS_DHE_PSK_WITH_AES_128_CBC_SHA */
+    "RSA-PSK-AES128-CBC-SHA",           /* TLS_RSA_PSK_WITH_AES_128_CBC_SHA */
+    "PSK-AES128-CBC-SHA256",            /* TLS_PSK_WITH_AES_128_CBC_SHA256 */
+    "DHE-PSK-AES128-CBC-SHA256",        /* TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 */
+    "RSA-PSK-AES128-CBC-SHA256",        /* TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 */
+    "ECDHE-PSK-AES128-CBC-SHA",         /* TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA */
+    "ECDHE-PSK-AES128-CBC-SHA256",      /* TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 */
+    "AES128-CCM",                       /* TLS_RSA_WITH_AES_128_CCM */
+    "AES128-CCM8",                      /* TLS_RSA_WITH_AES_128_CCM_8 */
+    "PSK-AES128-CCM",                   /* TLS_PSK_WITH_AES_128_CCM */
+    "PSK-AES128-CCM8",                  /* TLS_PSK_WITH_AES_128_CCM_8 */
+    "AES128-GCM-SHA256",                /* TLS_RSA_WITH_AES_128_GCM_SHA256 */
+    "DH-RSA-AES128-GCM-SHA256",         /* TLS_DH_RSA_WITH_AES_128_GCM_SHA256 */
+    "DH-DSS-AES128-GCM-SHA256",         /* TLS_DH_DSS_WITH_AES_128_GCM_SHA256 */
+    "ADH-AES128-GCM-SHA256",            /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
+    "PSK-AES128-GCM-SHA256",            /* TLS_PSK_WITH_AES_128_GCM_SHA256 */
+    "RSA-PSK-AES128-GCM-SHA256",        /* TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 */
+    "ECDH-ECDSA-AES128-GCM-SHA256",     /* TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 */
+    "ECDH-RSA-AES128-GCM-SHA256",       /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 */
+    "SRP-AES-128-CBC-SHA",              /* TLS_SRP_SHA_WITH_AES_128_CBC_SHA */
+    "SRP-RSA-AES-128-CBC-SHA",          /* TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA */
+    "SRP-DSS-AES-128-CBC-SHA",          /* TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA */
+    
+    /* blacklisted AES256 encrpytion ciphers */
+    "AES256-SHA",                       /* TLS_RSA_WITH_AES_256_CBC_SHA */
+    "DH-DSS-AES256-SHA",                /* TLS_DH_DSS_WITH_AES_256_CBC_SHA */
+    "DH-RSA-AES256-SHA",                /* TLS_DH_RSA_WITH_AES_256_CBC_SHA */
+    "DHE-DSS-AES256-SHA",               /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA */
+    "DHE-RSA-AES256-SHA",               /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */
+    "ADH-AES256-SHA",                   /* TLS_DH_anon_WITH_AES_256_CBC_SHA */
+    "AES256-SHA256",                    /* TLS_RSA_WITH_AES_256_CBC_SHA256 */
+    "DH-DSS-AES256-SHA256",             /* TLS_DH_DSS_WITH_AES_256_CBC_SHA256 */
+    "DH-RSA-AES256-SHA256",             /* TLS_DH_RSA_WITH_AES_256_CBC_SHA256 */
+    "DHE-DSS-AES256-SHA256",            /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 */
+    "DHE-RSA-AES256-SHA256",            /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 */
+    "ADH-AES256-SHA256",                /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
+    "ECDH-ECDSA-AES256-SHA",            /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
+    "ECDHE-ECDSA-AES256-SHA",           /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
+    "ECDH-RSA-AES256-SHA",              /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA */
+    "ECDHE-RSA-AES256-SHA",             /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */
+    "AECDH-AES256-SHA",                 /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
+    "ECDHE-ECDSA-AES256-SHA384",        /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 */
+    "ECDH-ECDSA-AES256-SHA384",         /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 */
+    "ECDHE-RSA-AES256-SHA384",          /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 */
+    "ECDH-RSA-AES256-SHA384",           /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 */
+    "PSK-AES256-CBC-SHA",               /* TLS_PSK_WITH_AES_256_CBC_SHA */
+    "DHE-PSK-AES256-CBC-SHA",           /* TLS_DHE_PSK_WITH_AES_256_CBC_SHA */
+    "RSA-PSK-AES256-CBC-SHA",           /* TLS_RSA_PSK_WITH_AES_256_CBC_SHA */
+    "PSK-AES256-CBC-SHA384",            /* TLS_PSK_WITH_AES_256_CBC_SHA384 */
+    "DHE-PSK-AES256-CBC-SHA384",        /* TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 */
+    "RSA-PSK-AES256-CBC-SHA384",        /* TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 */
+    "ECDHE-PSK-AES256-CBC-SHA",         /* TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA */
+    "ECDHE-PSK-AES256-CBC-SHA384",      /* TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 */
+    "SRP-AES-256-CBC-SHA",              /* TLS_SRP_SHA_WITH_AES_256_CBC_SHA */
+    "SRP-RSA-AES-256-CBC-SHA",          /* TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA */
+    "SRP-DSS-AES-256-CBC-SHA",          /* TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA */
+    "AES256-CCM",                       /* TLS_RSA_WITH_AES_256_CCM */
+    "AES256-CCM8",                      /* TLS_RSA_WITH_AES_256_CCM_8 */
+    "PSK-AES256-CCM",                   /* TLS_PSK_WITH_AES_256_CCM */
+    "PSK-AES256-CCM8",                  /* TLS_PSK_WITH_AES_256_CCM_8 */
+    "AES256-GCM-SHA384",                /* TLS_RSA_WITH_AES_256_GCM_SHA384 */
+    "DH-RSA-AES256-GCM-SHA384",         /* TLS_DH_RSA_WITH_AES_256_GCM_SHA384 */
+    "DH-DSS-AES256-GCM-SHA384",         /* TLS_DH_DSS_WITH_AES_256_GCM_SHA384 */
+    "ADH-AES256-GCM-SHA384",            /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
+    "PSK-AES256-GCM-SHA384",            /* TLS_PSK_WITH_AES_256_GCM_SHA384 */
+    "RSA-PSK-AES256-GCM-SHA384",        /* TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 */
+    "ECDH-ECDSA-AES256-GCM-SHA384",     /* TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 */
+    "ECDH-RSA-AES256-GCM-SHA384",       /* TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 */
+    
+    /* blacklisted CAMELLIA128 encrpytion ciphers */
+    "CAMELLIA128-SHA",                  /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA */
+    "DH-DSS-CAMELLIA128-SHA",           /* TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA */
+    "DH-RSA-CAMELLIA128-SHA",           /* TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA */
+    "DHE-DSS-CAMELLIA128-SHA",          /* TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA */
+    "DHE-RSA-CAMELLIA128-SHA",          /* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA */
+    "ADH-CAMELLIA128-SHA",              /* TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA */
+    "ECDHE-ECDSA-CAMELLIA128-SHA256",   /* TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "ECDH-ECDSA-CAMELLIA128-SHA256",    /* TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "ECDHE-RSA-CAMELLIA128-SHA256",     /* TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "ECDH-RSA-CAMELLIA128-SHA256",      /* TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "PSK-CAMELLIA128-SHA256",           /* TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 */
+    "DHE-PSK-CAMELLIA128-SHA256",       /* TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 */
+    "RSA-PSK-CAMELLIA128-SHA256",       /* TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 */
+    "ECDHE-PSK-CAMELLIA128-SHA256",     /* TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 */
+    "CAMELLIA128-GCM-SHA256",           /* TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 */
+    "DH-RSA-CAMELLIA128-GCM-SHA256",    /* TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 */
+    "DH-DSS-CAMELLIA128-GCM-SHA256",    /* TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 */
+    "ADH-CAMELLIA128-GCM-SHA256",       /* TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 */
+    "ECDH-ECDSA-CAMELLIA128-GCM-SHA256",/* TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 */
+    "ECDH-RSA-CAMELLIA128-GCM-SHA256",  /* TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 */
+    "PSK-CAMELLIA128-GCM-SHA256",       /* TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 */
+    "RSA-PSK-CAMELLIA128-GCM-SHA256",   /* TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 */
+    "CAMELLIA128-SHA256",               /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "DH-DSS-CAMELLIA128-SHA256",        /* TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 */
+    "DH-RSA-CAMELLIA128-SHA256",        /* TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "DHE-DSS-CAMELLIA128-SHA256",       /* TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 */
+    "DHE-RSA-CAMELLIA128-SHA256",       /* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 */
+    "ADH-CAMELLIA128-SHA256",           /* TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 */
+    
+    /* blacklisted CAMELLIA256 encrpytion ciphers */
+    "CAMELLIA256-SHA",                  /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA */
+    "DH-RSA-CAMELLIA256-SHA",           /* TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA */
+    "DH-DSS-CAMELLIA256-SHA",           /* TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA */
+    "DHE-DSS-CAMELLIA256-SHA",          /* TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA */
+    "DHE-RSA-CAMELLIA256-SHA",          /* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA */
+    "ADH-CAMELLIA256-SHA",              /* TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA */
+    "ECDHE-ECDSA-CAMELLIA256-SHA384",   /* TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 */
+    "ECDH-ECDSA-CAMELLIA256-SHA384",    /* TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 */
+    "ECDHE-RSA-CAMELLIA256-SHA384",     /* TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 */
+    "ECDH-RSA-CAMELLIA256-SHA384",      /* TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 */
+    "PSK-CAMELLIA256-SHA384",           /* TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 */
+    "DHE-PSK-CAMELLIA256-SHA384",       /* TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 */
+    "RSA-PSK-CAMELLIA256-SHA384",       /* TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 */
+    "ECDHE-PSK-CAMELLIA256-SHA384",     /* TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 */
+    "CAMELLIA256-SHA256",               /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 */
+    "DH-DSS-CAMELLIA256-SHA256",        /* TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 */
+    "DH-RSA-CAMELLIA256-SHA256",        /* TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 */
+    "DHE-DSS-CAMELLIA256-SHA256",       /* TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 */
+    "DHE-RSA-CAMELLIA256-SHA256",       /* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 */
+    "ADH-CAMELLIA256-SHA256",           /* TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 */
+    "CAMELLIA256-GCM-SHA384",           /* TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 */
+    "DH-RSA-CAMELLIA256-GCM-SHA384",    /* TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 */
+    "DH-DSS-CAMELLIA256-GCM-SHA384",    /* TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 */
+    "ADH-CAMELLIA256-GCM-SHA384",       /* TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 */
+    "ECDH-ECDSA-CAMELLIA256-GCM-SHA384",/* TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 */
+    "ECDH-RSA-CAMELLIA256-GCM-SHA384",  /* TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 */
+    "PSK-CAMELLIA256-GCM-SHA384",       /* TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 */
+    "RSA-PSK-CAMELLIA256-GCM-SHA384",   /* TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 */
+    
+    /* The blacklisted ARIA encrpytion ciphers */
+    "ARIA128-SHA256",                   /* TLS_RSA_WITH_ARIA_128_CBC_SHA256 */
+    "ARIA256-SHA384",                   /* TLS_RSA_WITH_ARIA_256_CBC_SHA384 */
+    "DH-DSS-ARIA128-SHA256",            /* TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 */
+    "DH-DSS-ARIA256-SHA384",            /* TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 */
+    "DH-RSA-ARIA128-SHA256",            /* TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 */
+    "DH-RSA-ARIA256-SHA384",            /* TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 */
+    "DHE-DSS-ARIA128-SHA256",           /* TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 */
+    "DHE-DSS-ARIA256-SHA384",           /* TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 */
+    "DHE-RSA-ARIA128-SHA256",           /* TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 */
+    "DHE-RSA-ARIA256-SHA384",           /* TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 */
+    "ADH-ARIA128-SHA256",               /* TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 */
+    "ADH-ARIA256-SHA384",               /* TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 */
+    "ECDHE-ECDSA-ARIA128-SHA256",       /* TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 */
+    "ECDHE-ECDSA-ARIA256-SHA384",       /* TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 */
+    "ECDH-ECDSA-ARIA128-SHA256",        /* TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 */
+    "ECDH-ECDSA-ARIA256-SHA384",        /* TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 */
+    "ECDHE-RSA-ARIA128-SHA256",         /* TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 */
+    "ECDHE-RSA-ARIA256-SHA384",         /* TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 */
+    "ECDH-RSA-ARIA128-SHA256",          /* TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 */
+    "ECDH-RSA-ARIA256-SHA384",          /* TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 */
+    "ARIA128-GCM-SHA256",               /* TLS_RSA_WITH_ARIA_128_GCM_SHA256 */
+    "ARIA256-GCM-SHA384",               /* TLS_RSA_WITH_ARIA_256_GCM_SHA384 */
+    "DH-DSS-ARIA128-GCM-SHA256",        /* TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 */
+    "DH-DSS-ARIA256-GCM-SHA384",        /* TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 */
+    "DH-RSA-ARIA128-GCM-SHA256",        /* TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 */
+    "DH-RSA-ARIA256-GCM-SHA384",        /* TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 */
+    "ADH-ARIA128-GCM-SHA256",           /* TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 */
+    "ADH-ARIA256-GCM-SHA384",           /* TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 */
+    "ECDH-ECDSA-ARIA128-GCM-SHA256",    /* TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 */
+    "ECDH-ECDSA-ARIA256-GCM-SHA384",    /* TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 */
+    "ECDH-RSA-ARIA128-GCM-SHA256",      /* TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 */
+    "ECDH-RSA-ARIA256-GCM-SHA384",      /* TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 */
+    "PSK-ARIA128-SHA256",               /* TLS_PSK_WITH_ARIA_128_CBC_SHA256 */
+    "PSK-ARIA256-SHA384",               /* TLS_PSK_WITH_ARIA_256_CBC_SHA384 */
+    "DHE-PSK-ARIA128-SHA256",           /* TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 */
+    "DHE-PSK-ARIA256-SHA384",           /* TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 */
+    "RSA-PSK-ARIA128-SHA256",           /* TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 */
+    "RSA-PSK-ARIA256-SHA384",           /* TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 */
+    "ARIA128-GCM-SHA256",               /* TLS_PSK_WITH_ARIA_128_GCM_SHA256 */
+    "ARIA256-GCM-SHA384",               /* TLS_PSK_WITH_ARIA_256_GCM_SHA384 */
+    "RSA-PSK-ARIA128-GCM-SHA256",       /* TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 */
+    "RSA-PSK-ARIA256-GCM-SHA384",       /* TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 */
+    "ECDHE-PSK-ARIA128-SHA256",         /* TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 */
+    "ECDHE-PSK-ARIA256-SHA384",         /* TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 */
+
+    /* blacklisted SEED encryptions */
+    "SEED-SHA",                         /*TLS_RSA_WITH_SEED_CBC_SHA */
+    "DH-DSS-SEED-SHA",                  /* TLS_DH_DSS_WITH_SEED_CBC_SHA */
+    "DH-RSA-SEED-SHA",                  /* TLS_DH_RSA_WITH_SEED_CBC_SHA */
+    "DHE-DSS-SEED-SHA",                 /* TLS_DHE_DSS_WITH_SEED_CBC_SHA */
+    "DHE-RSA-SEED-SHA",                 /* TLS_DHE_RSA_WITH_SEED_CBC_SHA */               
+    "ADH-SEED-SHA",                     /* TLS_DH_anon_WITH_SEED_CBC_SHA */
+
+    /* blacklisted KRB5 ciphers */
+    "KRB5-DES-CBC-SHA",                 /* TLS_KRB5_WITH_DES_CBC_SHA */
+    "KRB5-DES-CBC3-SHA",                /* TLS_KRB5_WITH_3DES_EDE_CBC_SHA */
+    "KRB5-IDEA-CBC-SHA",                /* TLS_KRB5_WITH_IDEA_CBC_SHA */
+    "KRB5-DES-CBC-MD5",                 /* TLS_KRB5_WITH_DES_CBC_MD5 */
+    "KRB5-DES-CBC3-MD5",                /* TLS_KRB5_WITH_3DES_EDE_CBC_MD5 */
+    "KRB5-IDEA-CBC-MD5",                /* TLS_KRB5_WITH_IDEA_CBC_MD5 */
+    "EXP-KRB5-DES-CBC-SHA",             /* TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA */
+    "EXP-KRB5-DES-CBC-MD5",             /* TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 */
+    "EXP-KRB5-RC2-CBC-SHA",             /* TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA */
+    "EXP-KRB5-RC2-CBC-MD5",             /* TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 */
+  
+    /* blacklisted exoticas */
+    "DHE-DSS-CBC-SHA",                  /* TLS_DHE_DSS_WITH_DES_CBC_SHA */
+    "IDEA-CBC-SHA",                     /* TLS_RSA_WITH_IDEA_CBC_SHA */
+    
+    /* not really sure if the following names are correct */
+    "SSL3_CK_SCSV",                     /* TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
+    "SSL3_CK_FALLBACK_SCSV"
+};
+static size_t RFC7540_names_LEN = sizeof(RFC7540_names)/sizeof(RFC7540_names[0]);
+
+
+static apr_hash_t *BLCNames;
+
+static void cipher_init(apr_pool_t *pool)
+{
+    apr_hash_t *hash = apr_hash_make(pool);
+    const char *source;
+    unsigned int i;
+    
+    source = "rfc7540";
+    for (i = 0; i < RFC7540_names_LEN; ++i) {
+        apr_hash_set(hash, RFC7540_names[i], APR_HASH_KEY_STRING, source);
+    }
+    
+    BLCNames = hash;
+}
+
+static int cipher_is_blacklisted(const char *cipher, const char **psource)
+{   
+    *psource = apr_hash_get(BLCNames, cipher, APR_HASH_KEY_STRING);
+    return !!*psource;
+}
+
+/*******************************************************************************
  * Hooks for processing incoming connections:
  * - pre_conn_before_tls switches SSL off for stream connections
  * - process_conn take over connection in case of h2
@@ -72,12 +449,15 @@ apr_status_t h2_h2_init(apr_pool_t *pool
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "h2_h2, child_init");
     opt_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
     opt_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+    opt_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
     
-    if (!opt_ssl_is_https) {
+    if (!opt_ssl_is_https || !opt_ssl_var_lookup) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
                      APLOGNO(02951) "mod_ssl does not seem to be enabled");
     }
     
+    cipher_init(pool);
+    
     return APR_SUCCESS;
 }
 
@@ -86,18 +466,95 @@ int h2_h2_is_tls(conn_rec *c)
     return opt_ssl_is_https && opt_ssl_is_https(c);
 }
 
-int h2_tls_disable(conn_rec *c)
+int h2_is_acceptable_connection(conn_rec *c, int require_all) 
 {
-    if (opt_ssl_engine_disable) {
-        return opt_ssl_engine_disable(c);
+    int is_tls = h2_h2_is_tls(c);
+    h2_config *cfg = h2_config_get(c);
+
+    if (is_tls && h2_config_geti(cfg, H2_CONF_MODERN_TLS_ONLY) > 0) {
+        /* Check TLS connection for modern TLS parameters, as defined in
+         * RFC 7540 and https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
+         */
+        apr_pool_t *pool = c->pool;
+        server_rec *s = c->base_server;
+        char *val;
+        
+        if (!opt_ssl_var_lookup) {
+            /* unable to check */
+            return 0;
+        }
+        
+        /* Need Tlsv1.2 or higher, rfc 7540, ch. 9.2
+         */
+        val = opt_ssl_var_lookup(pool, s, c, NULL, (char*)"SSL_PROTOCOL");
+        if (val && *val) {
+            if (strncmp("TLS", val, 3) 
+                || !strcmp("TLSv1", val) 
+                || !strcmp("TLSv1.1", val)) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                          "h2_h2(%ld): tls protocol not suitable: %s", 
+                          (long)c->id, val);
+                return 0;
+            }
+        }
+        else if (require_all) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                          "h2_h2(%ld): tls protocol is indetermined", (long)c->id);
+            return 0;
+        }
+
+        /* Check TLS cipher blacklist
+         */
+        val = opt_ssl_var_lookup(pool, s, c, NULL, (char*)"SSL_CIPHER");
+        if (val && *val) {
+            const char *source;
+            if (cipher_is_blacklisted(val, &source)) {
+                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                              "h2_h2(%ld): tls cipher %s blacklisted by %s", 
+                              (long)c->id, val, source);
+                return 0;
+            }
+        }
+        else if (require_all) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                          "h2_h2(%ld): tls cipher is indetermined", (long)c->id);
+            return 0;
+        }
     }
-    return 0;
+    return 1;
+}
+
+int h2_allows_h2_direct(conn_rec *c)
+{
+    h2_config *cfg = h2_config_get(c);
+    int h2_direct = h2_config_geti(cfg, H2_CONF_DIRECT);
+    
+    if (h2_direct < 0) {
+        if (h2_h2_is_tls(c)) {
+            /* disabled by default on TLS */
+            h2_direct = 0;
+        }
+        else {
+            /* enabled if "Protocols h2c" is configured */
+            h2_direct = ap_is_allowed_protocol(c, NULL, NULL, "h2c");
+        }
+    }
+    return !!h2_direct;
+}
+
+int h2_allows_h2_upgrade(conn_rec *c)
+{
+    h2_config *cfg = h2_config_get(c);
+    int h2_upgrade = h2_config_geti(cfg, H2_CONF_UPGRADE);
+    
+    return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(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)
 {
@@ -105,7 +562,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, 
@@ -119,7 +577,7 @@ void h2_h2_register_hooks(void)
     ap_hook_post_read_request(h2_h2_post_read_req, NULL, NULL, APR_HOOK_REALLY_FIRST);
 }
 
-int h2_h2_remove_timeout(conn_rec* c)
+static int h2_h2_remove_timeout(conn_rec* c)
 {
     h2_ctx *ctx = h2_ctx_get(c);
     
@@ -134,9 +592,6 @@ int h2_h2_remove_timeout(conn_rec* c)
 int h2_h2_process_conn(conn_rec* c)
 {
     h2_ctx *ctx = h2_ctx_get(c);
-    h2_config *cfg = h2_config_get(c);
-    apr_bucket_brigade* temp;
-    int is_tls = h2_h2_is_tls(c);
     
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn");
     if (h2_ctx_is_task(ctx)) {
@@ -144,53 +599,50 @@ 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"
-     * -> sniff for the magic PRIamble. On TLS, this might trigger the ALPN.
-     */
-    if (!h2_ctx_protocol_get(c) 
-        && !strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))) {
+    if (h2_ctx_protocol_get(c)) {
+        /* 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) {
-            if (h2_ctx_protocol_get(c) 
-                || strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))) {
-                /* h2 or another protocol has been selected. */
-            }
-            else {
-                /* 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. 
-                 */
-                int direct_mode = h2_config_geti(cfg, H2_CONF_DIRECT);
-                if (direct_mode > 0 || (direct_mode < 0 && !is_tls)) {
-                    char *s = NULL;
-                    apr_size_t slen;
-                    
-                    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);
-                    }
-                }
-            }
-        }
-        else {
+        
+        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;
         }
+        
+        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 {
+            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
      * the connection.
@@ -199,7 +651,7 @@ int h2_h2_process_conn(conn_rec* c)
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                       "h2_h2, connection, h2 active");
         
-        return h2_conn_main(c);
+        return h2_conn_process(c, NULL);
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined");
@@ -209,21 +661,21 @@ int h2_h2_process_conn(conn_rec* c)
 static int h2_h2_post_read_req(request_rec *r)
 {
     h2_ctx *ctx = h2_ctx_rget(r);
-    struct h2_task_env *env = h2_ctx_get_task(ctx);
-    if (env) {
+    struct h2_task *task = h2_ctx_get_task(ctx);
+    if (task) {
         /* h2_task connection for a stream, not for h2c */
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
                       "adding h1_to_h2_resp output filter");
-        if (env->serialize_headers) {
+        if (task->serialize_headers) {
             ap_remove_output_filter_byhandle(r->output_filters, "H1_TO_H2_RESP");
-            ap_add_output_filter("H1_TO_H2_RESP", env, r, r->connection);
+            ap_add_output_filter("H1_TO_H2_RESP", task, r, r->connection);
         }
         else {
             /* replace the core http filter that formats response headers
              * in HTTP/1 with our own that collects status and headers */
             ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
             ap_remove_output_filter_byhandle(r->output_filters, "H2_RESPONSE");
-            ap_add_output_filter("H2_RESPONSE", env, r, r->connection);
+            ap_add_output_filter("H2_RESPONSE", task, r, r->connection);
         }
     }
     return DECLINED;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h Fri Nov 20 15:13:11 2015
@@ -34,6 +34,37 @@ extern const char *h2_tls_protos[];
  */
 extern const char *H2_MAGIC_TOKEN;
 
+#define H2_ERR_NO_ERROR             (0x00)
+#define H2_ERR_PROTOCOL_ERROR       (0x01)
+#define H2_ERR_INTERNAL_ERROR       (0x02)
+#define H2_ERR_FLOW_CONTROL_ERROR   (0x03)
+#define H2_ERR_SETTINGS_TIMEOUT     (0x04)
+#define H2_ERR_STREAM_CLOSED        (0x05)
+#define H2_ERR_FRAME_SIZE_ERROR     (0x06)
+#define H2_ERR_REFUSED_STREAM       (0x07)
+#define H2_ERR_CANCEL               (0x08)
+#define H2_ERR_COMPRESSION_ERROR    (0x09)
+#define H2_ERR_CONNECT_ERROR        (0x0a)
+#define H2_ERR_ENHANCE_YOUR_CALM    (0x0b)
+#define H2_ERR_INADEQUATE_SECURITY  (0x0c)
+#define H2_ERR_HTTP_1_1_REQUIRED    (0x0d)
+
+/* Maximum number of padding bytes in a frame, rfc7540 */
+#define H2_MAX_PADLEN               256
+/* Initial default window size, RFC 7540 ch. 6.5.2 */
+#define H2_INITIAL_WINDOW_SIZE      ((64*1024)-1)
+
+#define H2_HTTP_2XX(a)      ((a) >= 200 && (a) < 300)
+
+#define H2_STREAM_CLIENT_INITIATED(id)      (id&0x01)
+
+/**
+ * Provide a user readable description of the HTTP/2 error code-
+ * @param h2_error http/2 error code, as in rfc 7540, ch. 7
+ * @return textual description of code or that it is unknown.
+ */
+const char *h2_h2_err_description(unsigned int h2_error);
+
 /*
  * One time, post config intialization.
  */
@@ -43,15 +74,35 @@ apr_status_t h2_h2_init(apr_pool_t *pool
  */
 int h2_h2_is_tls(conn_rec *c);
 
-/* Disable SSL for this connection, can only be invoked in a pre-
- * connection hook before mod_ssl.
- * @return != 0 iff disable worked
- */
-int h2_tls_disable(conn_rec *c);
-
 /* Register apache hooks for h2 protocol
  */
 void h2_h2_register_hooks(void);
 
+/**
+ * Check if the given connection fulfills the requirements as configured.
+ * @param c the connection
+ * @param require_all != 0 iff any missing connection properties make
+ *    the test fail. For example, a cipher might not have been selected while
+ *    the handshake is still ongoing.
+ * @return != 0 iff connection requirements are met
+ */
+int h2_is_acceptable_connection(conn_rec *c, int require_all);
+
+/**
+ * Check if the "direct" HTTP/2 mode of protocol handling is enabled
+ * for the given connection.
+ * @param c the connection to check
+ * @return != 0 iff direct mode is enabled
+ */
+int h2_allows_h2_direct(conn_rec *c);
+
+/**
+ * Check if the "Upgrade" HTTP/1.1 mode of protocol switching is enabled
+ * for the given connection.
+ * @param c the connection to check
+ * @return != 0 iff Upgrade switching is enabled
+ */
+int h2_allows_h2_upgrade(conn_rec *c);
+
 
 #endif /* defined(__mod_h2__h2_h2__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_io.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_io.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_io.c Fri Nov 20 15:13:11 2015
@@ -23,6 +23,7 @@
 #include "h2_private.h"
 #include "h2_io.h"
 #include "h2_response.h"
+#include "h2_task.h"
 #include "h2_util.h"
 
 h2_io *h2_io_create(int id, apr_pool_t *pool, apr_bucket_alloc_t *bucket_alloc)
@@ -31,33 +32,50 @@ h2_io *h2_io_create(int id, apr_pool_t *
     if (io) {
         io->id = id;
         io->pool = pool;
+        io->bucket_alloc = bucket_alloc;
         io->bbin = NULL;
-        io->bbout = apr_brigade_create(pool, bucket_alloc);
+        io->bbout = NULL;
     }
     return io;
 }
 
-static void h2_io_cleanup(h2_io *io)
+void h2_io_destroy(h2_io *io)
 {
-    (void)io;
+    if (io->pool) {
+        apr_pool_destroy(io->pool);
+        /* gone */
+    }
 }
 
-void h2_io_destroy(h2_io *io)
+void h2_io_set_response(h2_io *io, h2_response *response) 
+{
+    AP_DEBUG_ASSERT(io->pool);
+    AP_DEBUG_ASSERT(response);
+    AP_DEBUG_ASSERT(!io->response);
+    io->response = h2_response_copy(io->pool, response);
+    if (response->rst_error) {
+        h2_io_rst(io, response->rst_error);
+    }
+}
+
+
+void h2_io_rst(h2_io *io, int error)
 {
-    h2_io_cleanup(io);
+    io->rst_error = error;
+    io->eos_in = 1;
 }
 
 int h2_io_in_has_eos_for(h2_io *io)
 {
-    return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, 0));
+    return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, -1));
 }
 
 int h2_io_out_has_data(h2_io *io)
 {
-    return h2_util_bb_has_data_or_eos(io->bbout);
+    return io->bbout && h2_util_bb_has_data_or_eos(io->bbout);
 }
 
-apr_size_t h2_io_out_length(h2_io *io)
+apr_off_t h2_io_out_length(h2_io *io)
 {
     if (io->bbout) {
         apr_off_t len = 0;
@@ -74,14 +92,17 @@ apr_status_t h2_io_in_read(h2_io *io, ap
     apr_bucket *last;
     apr_status_t status;
 
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
     if (!io->bbin || APR_BRIGADE_EMPTY(io->bbin)) {
         return io->eos_in? APR_EOF : APR_EAGAIN;
     }
     
     apr_brigade_length(bb, 1, &start_len);
     last = APR_BRIGADE_LAST(bb);
-    status = h2_util_move(bb, io->bbin, maxlen, 0, 
-                                       "h2_io_in_read");
+    status = h2_util_move(bb, io->bbin, maxlen, NULL, "h2_io_in_read");
     if (status == APR_SUCCESS) {
         apr_bucket *nlast = APR_BRIGADE_LAST(bb);
         apr_off_t end_len = 0;
@@ -96,22 +117,29 @@ apr_status_t h2_io_in_read(h2_io *io, ap
 
 apr_status_t h2_io_in_write(h2_io *io, apr_bucket_brigade *bb)
 {
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
     if (io->eos_in) {
         return APR_EOF;
     }
-    io->eos_in = h2_util_has_eos(bb, 0);
+    io->eos_in = h2_util_has_eos(bb, -1);
     if (!APR_BRIGADE_EMPTY(bb)) {
         if (!io->bbin) {
-            io->bbin = apr_brigade_create(io->bbout->p, 
-                                          io->bbout->bucket_alloc);
+            io->bbin = apr_brigade_create(io->pool, io->bucket_alloc);
         }
-        return h2_util_move(io->bbin, bb, 0, 0, "h2_io_in_write");
+        return h2_util_move(io->bbin, bb, -1, NULL, "h2_io_in_write");
     }
     return APR_SUCCESS;
 }
 
 apr_status_t h2_io_in_close(h2_io *io)
 {
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
     if (io->bbin) {
         APR_BRIGADE_INSERT_TAIL(io->bbin, 
                                 apr_bucket_eos_create(io->bbin->bucket_alloc));
@@ -122,18 +150,93 @@ apr_status_t h2_io_in_close(h2_io *io)
 
 apr_status_t h2_io_out_readx(h2_io *io,  
                              h2_io_data_cb *cb, void *ctx, 
-                             apr_size_t *plen, int *peos)
+                             apr_off_t *plen, int *peos)
 {
+    apr_status_t status;
+    
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
+    if (io->eos_out) {
+        *plen = 0;
+        *peos = 1;
+        return APR_SUCCESS;
+    }
+    else if (!io->bbout) {
+        *plen = 0;
+        *peos = 0;
+        return APR_EAGAIN;
+    }
+    
     if (cb == NULL) {
         /* just checking length available */
-        return h2_util_bb_avail(io->bbout, plen, peos);
+        status = h2_util_bb_avail(io->bbout, plen, peos);
+    }
+    else {
+        status = h2_util_bb_readx(io->bbout, cb, ctx, plen, peos);
+        if (status == APR_SUCCESS) {
+            io->eos_out = *peos;
+        }
     }
-    return h2_util_bb_readx(io->bbout, cb, ctx, plen, peos);
+    
+    return status;
+}
+
+apr_status_t h2_io_out_read_to(h2_io *io, apr_bucket_brigade *bb, 
+                               apr_off_t *plen, int *peos)
+{
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
+    if (io->eos_out) {
+        *plen = 0;
+        *peos = 1;
+        return APR_SUCCESS;
+    }
+    else if (!io->bbout) {
+        *plen = 0;
+        *peos = 0;
+        return APR_EAGAIN;
+    }
+
+    io->eos_out = *peos = h2_util_has_eos(io->bbout, *plen);
+    return h2_util_move(bb, io->bbout, *plen, NULL, "h2_io_read_to");
 }
 
 apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, 
                              apr_size_t maxlen, int *pfile_handles_allowed)
 {
+    apr_status_t status;
+    int start_allowed;
+    
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+
+    if (io->eos_out) {
+        apr_off_t len;
+        /* We have already delivered an EOS bucket to a reader, no
+         * sense in storing anything more here.
+         */
+        status = apr_brigade_length(bb, 1, &len);
+        if (status == APR_SUCCESS) {
+            if (len > 0) {
+                /* someone tries to write real data after EOS, that
+                 * does not look right. */
+                status = APR_EOF;
+            }
+            /* cleanup, as if we had moved the data */
+            apr_brigade_cleanup(bb);
+        }
+        return status;
+    }
+
+    if (!io->bbout) {
+        io->bbout = apr_brigade_create(io->pool, io->bucket_alloc);
+    }
+    
     /* Let's move the buckets from the request processing in here, so
      * that the main thread can read them when it has time/capacity.
      *
@@ -144,8 +247,7 @@ apr_status_t h2_io_out_write(h2_io *io,
      * many open files already buffered. Otherwise we will run out of
      * file handles.
      */
-    int start_allowed = *pfile_handles_allowed;
-    apr_status_t status;
+    start_allowed = *pfile_handles_allowed;
     status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed, 
                           "h2_io_out_write");
     /* track # file buckets moved into our pool */
@@ -158,7 +260,15 @@ apr_status_t h2_io_out_write(h2_io *io,
 
 apr_status_t h2_io_out_close(h2_io *io)
 {
-    APR_BRIGADE_INSERT_TAIL(io->bbout, 
-                            apr_bucket_eos_create(io->bbout->bucket_alloc));
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    if (!io->bbout) {
+        io->bbout = apr_brigade_create(io->pool, io->bucket_alloc);
+    }
+    if (!io->eos_out && !h2_util_has_eos(io->bbout, -1)) {
+        APR_BRIGADE_INSERT_TAIL(io->bbout, 
+                                apr_bucket_eos_create(io->bbout->bucket_alloc));
+    }
     return APR_SUCCESS;
 }

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_io.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_io.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_io.h Fri Nov 20 15:13:11 2015
@@ -18,11 +18,12 @@
 
 struct h2_response;
 struct apr_thread_cond_t;
-struct h2_task;
+struct h2_request;
 
 
-typedef apr_status_t h2_io_data_cb(void *ctx, 
-                                   const char *data, apr_size_t len);
+typedef apr_status_t h2_io_data_cb(void *ctx, const char *data, apr_off_t len);
+
+typedef int h2_stream_pri_cmp(int stream_id1, int stream_id2, void *ctx);
 
 
 typedef struct h2_io h2_io;
@@ -30,17 +31,24 @@ typedef struct h2_io h2_io;
 struct h2_io {
     int id;                      /* stream identifier */
     apr_pool_t *pool;            /* stream pool */
-    apr_bucket_brigade *bbin;    /* input data for stream */
-    int eos_in;
-    int task_done;
+    int orphaned;                /* h2_stream is gone for this io */
     
-    apr_size_t input_consumed;   /* how many bytes have been read */
+    int task_done;
+    const struct h2_request *request;  /* request on this io */
+    int request_body;            /* == 0 iff request has no body */
+    struct h2_response *response;/* response for submit, once created */
+    int rst_error;
+
+    int eos_in;
+    apr_bucket_brigade *bbin;    /* input data for stream */
     struct apr_thread_cond_t *input_arrived; /* block on reading */
+    apr_size_t input_consumed;   /* how many bytes have been read */
     
+    int eos_out;
     apr_bucket_brigade *bbout;   /* output data from stream */
+    apr_bucket_alloc_t *bucket_alloc;
     struct apr_thread_cond_t *output_drained; /* block on writing */
     
-    struct h2_response *response;/* submittable response created */
     int files_handles_owned;
 };
 
@@ -59,6 +67,16 @@ h2_io *h2_io_create(int id, apr_pool_t *
 void h2_io_destroy(h2_io *io);
 
 /**
+ * Set the response of this stream.
+ */
+void h2_io_set_response(h2_io *io, struct h2_response *response);
+
+/**
+ * Reset the stream with the given error code.
+ */
+void h2_io_rst(h2_io *io, int error);
+
+/**
  * The input data is completely queued. Blocked reads will return immediately
  * and give either data or EOF.
  */
@@ -105,7 +123,11 @@ apr_status_t h2_io_in_close(h2_io *io);
  */
 apr_status_t h2_io_out_readx(h2_io *io,  
                              h2_io_data_cb *cb, void *ctx, 
-                             apr_size_t *plen, int *peos);
+                             apr_off_t *plen, int *peos);
+
+apr_status_t h2_io_out_read_to(h2_io *io, 
+                               apr_bucket_brigade *bb, 
+                               apr_off_t *plen, int *peos);
 
 apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, 
                              apr_size_t maxlen, int *pfile_buckets_allowed);
@@ -120,7 +142,7 @@ apr_status_t h2_io_out_close(h2_io *io);
  * Gives the overall length of the data that is currently queued for
  * output.
  */
-apr_size_t h2_io_out_length(h2_io *io);
+apr_off_t h2_io_out_length(h2_io *io);
 
 
 #endif /* defined(__mod_h2__h2_io__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.c Fri Nov 20 15:13:11 2015
@@ -78,19 +78,6 @@ h2_io *h2_io_set_get(h2_io_set *sp, int
     return ps? *ps : NULL;
 }
 
-h2_io *h2_io_set_get_highest_prio(h2_io_set *set)
-{
-    h2_io *highest = NULL;
-    int i;
-    for (i = 0; i < set->list->nelts; ++i) {
-        h2_io *io = h2_io_IDX(set->list, i);
-        if (!highest /*|| io-prio even higher */ ) {
-            highest = io;
-        }
-    }
-    return highest;
-}
-
 static void h2_io_set_sort(h2_io_set *sp)
 {
     qsort(sp->list->elts, sp->list->nelts, sp->list->elt_size, 
@@ -118,27 +105,45 @@ apr_status_t h2_io_set_add(h2_io_set *sp
     return APR_SUCCESS;
 }
 
+static void remove_idx(h2_io_set *sp, int idx)
+{
+    int n;
+    --sp->list->nelts;
+    n = sp->list->nelts - idx;
+    if (n > 0) {
+        /* Close the hole in the array by moving the upper
+         * parts down one step.
+         */
+        h2_io **selts = (h2_io**)sp->list->elts;
+        memmove(selts + idx, selts + idx + 1, n * sizeof(h2_io*));
+    }
+}
+
 h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io)
 {
     int i;
     for (i = 0; i < sp->list->nelts; ++i) {
         h2_io *e = h2_io_IDX(sp->list, i);
         if (e == io) {
-            int n;
-            --sp->list->nelts;
-            n = sp->list->nelts - i;
-            if (n > 0) {
-                /* Close the hole in the array by moving the upper
-                 * parts down one step.
-                 */
-                h2_io **selts = (h2_io**)sp->list->elts;
-                memmove(selts+i, selts+i+1, n * sizeof(h2_io*));
-            }
+            remove_idx(sp, i);
             return e;
         }
     }
     return NULL;
 }
+
+h2_io *h2_io_set_pop_highest_prio(h2_io_set *set)
+{
+    /* For now, this just removes the first element in the set.
+     * the name is misleading...
+     */
+    if (set->list->nelts > 0) {
+        h2_io *io = h2_io_IDX(set->list, 0);
+        remove_idx(set, 0);
+        return io;
+    }
+    return NULL;
+}
 
 void h2_io_set_destroy_all(h2_io_set *sp)
 {

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.h Fri Nov 20 15:13:11 2015
@@ -30,7 +30,6 @@ void h2_io_set_destroy(h2_io_set *set);
 
 apr_status_t h2_io_set_add(h2_io_set *set, struct h2_io *io);
 h2_io *h2_io_set_get(h2_io_set *set, int stream_id);
-h2_io *h2_io_set_get_highest_prio(h2_io_set *set);
 h2_io *h2_io_set_remove(h2_io_set *set, struct h2_io *io);
 
 void h2_io_set_remove_all(h2_io_set *set);
@@ -44,4 +43,6 @@ typedef int h2_io_set_iter_fn(void *ctx,
 void h2_io_set_iter(h2_io_set *set,
                            h2_io_set_iter_fn *iter, void *ctx);
 
+h2_io *h2_io_set_pop_highest_prio(h2_io_set *set);
+
 #endif /* defined(__mod_h2__h2_io_set__) */

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -29,6 +29,7 @@
 #include "h2_private.h"
 #include "h2_config.h"
 #include "h2_conn.h"
+#include "h2_h2.h"
 #include "h2_io.h"
 #include "h2_io_set.h"
 #include "h2_response.h"
@@ -40,7 +41,22 @@
 #include "h2_task_input.h"
 #include "h2_task_output.h"
 #include "h2_task_queue.h"
+#include "h2_worker.h"
 #include "h2_workers.h"
+#include "h2_util.h"
+
+
+#define H2_MPLX_IO_OUT(lvl,m,io,msg) \
+    do { \
+        if (APLOG_C_IS_LEVEL((m)->c,lvl)) \
+        h2_util_bb_log((m)->c,(io)->id,lvl,msg,(io)->bbout); \
+    } while(0)
+    
+#define H2_MPLX_IO_IN(lvl,m,io,msg) \
+    do { \
+        if (APLOG_C_IS_LEVEL((m)->c,lvl)) \
+        h2_util_bb_log((m)->c,(io)->id,lvl,msg,(io)->bbin); \
+    } while(0)
 
 
 static int is_aborted(h2_mplx *m, apr_status_t *pstatus) {
@@ -58,10 +74,6 @@ static void h2_mplx_destroy(h2_mplx *m)
 {
     AP_DEBUG_ASSERT(m);
     m->aborted = 1;
-    if (m->q) {
-        h2_tq_destroy(m->q);
-        m->q = NULL;
-    }
     if (m->ready_ios) {
         h2_io_set_destroy(m->ready_ios);
         m->ready_ios = NULL;
@@ -76,6 +88,10 @@ static void h2_mplx_destroy(h2_mplx *m)
         m->lock = NULL;
     }
     
+    if (m->spare_pool) {
+        apr_pool_destroy(m->spare_pool);
+        m->spare_pool = NULL;
+    }
     if (m->pool) {
         apr_pool_destroy(m->pool);
     }
@@ -109,7 +125,7 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
     if (m) {
         m->id = c->id;
         APR_RING_ELEM_INIT(m, link);
-        apr_atomic_set32(&m->refs, 1);
+        m->refs = 1;
         m->c = c;
         apr_pool_create_ex(&m->pool, parent, NULL, allocator);
         if (!m->pool) {
@@ -126,10 +142,9 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
         
         m->bucket_alloc = apr_bucket_alloc_create(m->pool);
         
-        m->q = h2_tq_create(m->id, m->pool);
+        m->q = h2_tq_create(m->pool, h2_config_geti(conf, H2_CONF_MAX_STREAMS));
         m->stream_ios = h2_io_set_create(m->pool);
         m->ready_ios = h2_io_set_create(m->pool);
-        m->closed = h2_stream_set_create(m->pool);
         m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM);
         m->workers = workers;
         
@@ -138,27 +153,31 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
     return m;
 }
 
-static void reference(h2_mplx *m)
+static void release(h2_mplx *m, int lock)
 {
-    apr_atomic_inc32(&m->refs);
-}
-
-static void release(h2_mplx *m)
-{
-    if (!apr_atomic_dec32(&m->refs)) {
+    if (lock) {
+        apr_thread_mutex_lock(m->lock);
+        --m->refs;
         if (m->join_wait) {
             apr_thread_cond_signal(m->join_wait);
         }
+        apr_thread_mutex_unlock(m->lock);
+    }
+    else {
+        --m->refs;
     }
 }
 
 void h2_mplx_reference(h2_mplx *m)
 {
-    reference(m);
+    apr_thread_mutex_lock(m->lock);
+    ++m->refs;
+    apr_thread_mutex_unlock(m->lock);
 }
+
 void h2_mplx_release(h2_mplx *m)
 {
-    release(m);
+    release(m, 1);
 }
 
 static void workers_register(h2_mplx *m) {
@@ -187,29 +206,17 @@ apr_status_t h2_mplx_release_and_join(h2
 
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        int attempts = 0;
-        
-        release(m);
-        while (apr_atomic_read32(&m->refs) > 0) {
+        release(m, 0);
+        while (m->refs > 0) {
             m->join_wait = wait;
-            ap_log_cerror(APLOG_MARK, (attempts? APLOG_INFO : APLOG_DEBUG), 
-                          0, m->c,
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
                           "h2_mplx(%ld): release_join, refs=%d, waiting...", 
                           m->id, m->refs);
-            apr_thread_cond_timedwait(wait, m->lock, apr_time_from_sec(10));
-            if (++attempts >= 6) {
-                ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c,
-                              APLOGNO(02952) 
-                              "h2_mplx(%ld): join attempts exhausted, refs=%d", 
-                              m->id, m->refs);
-                break;
-            }
+            apr_thread_cond_wait(wait, m->lock);
         }
-        if (m->join_wait) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
-                          "h2_mplx(%ld): release_join -> destroy", m->id);
-        }
-        m->join_wait = NULL;
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
+                      "h2_mplx(%ld): release_join -> destroy", m->id);
+        m->pool = NULL;
         apr_thread_mutex_unlock(m->lock);
         h2_mplx_destroy(m);
     }
@@ -230,43 +237,19 @@ void h2_mplx_abort(h2_mplx *m)
 }
 
 
-h2_stream *h2_mplx_open_io(h2_mplx *m, int stream_id)
+static void io_destroy(h2_mplx *m, h2_io *io)
 {
-    h2_stream *stream = NULL;
-    apr_status_t status; 
-    h2_io *io;
-
-    if (m->aborted) {
-        return NULL;
-    }
-    status = apr_thread_mutex_lock(m->lock);
-    if (APR_SUCCESS == status) {
-        apr_pool_t *stream_pool = m->spare_pool;
-        
-        if (!stream_pool) {
-            apr_pool_create(&stream_pool, m->pool);
-        }
-        else {
-            m->spare_pool = NULL;
-        }
-        
-        stream = h2_stream_create(stream_id, stream_pool, m);
-        stream->state = H2_STREAM_ST_OPEN;
-        
-        io = h2_io_set_get(m->stream_ios, stream_id);
-        if (!io) {
-            io = h2_io_create(stream_id, stream_pool, m->bucket_alloc);
-            h2_io_set_add(m->stream_ios, io);
-        }
-        status = io? APR_SUCCESS : APR_ENOMEM;
-        apr_thread_mutex_unlock(m->lock);
-    }
-    return stream;
-}
-
-static void stream_destroy(h2_mplx *m, h2_stream *stream, h2_io *io)
-{
-    apr_pool_t *pool = h2_stream_detach_pool(stream);
+    apr_pool_t *pool = io->pool;
+    
+    io->pool = NULL;    
+    /* The pool is cleared/destroyed which also closes all
+     * allocated file handles. Give this count back to our
+     * file handle pool. */
+    m->file_handles_allowed += io->files_handles_owned;
+    h2_io_set_remove(m->stream_ios, io);
+    h2_io_set_remove(m->ready_ios, io);
+    h2_io_destroy(io);
+    
     if (pool) {
         apr_pool_clear(pool);
         if (m->spare_pool) {
@@ -274,33 +257,40 @@ static void stream_destroy(h2_mplx *m, h
         }
         m->spare_pool = pool;
     }
-    h2_stream_destroy(stream);
-    if (io) {
-        /* The pool is cleared/destroyed which also closes all
-         * allocated file handles. Give this count back to our
-         * file handle pool. */
-        m->file_handles_allowed += io->files_handles_owned;
-        h2_io_set_remove(m->stream_ios, io);
-        h2_io_set_remove(m->ready_ios, io);
-        h2_io_destroy(io);
-    }
 }
 
-apr_status_t h2_mplx_cleanup_stream(h2_mplx *m, h2_stream *stream)
+apr_status_t h2_mplx_stream_done(h2_mplx *m, int stream_id, int rst_error)
 {
     apr_status_t status;
+    
     AP_DEBUG_ASSERT(m);
+    if (m->aborted) {
+        return APR_ECONNABORTED;
+    }
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        h2_io *io = h2_io_set_get(m->stream_ios, stream->id);
-        if (!io || io->task_done) {
-            /* No more io or task already done -> cleanup immediately */
-            stream_destroy(m, stream, io);
-        }
-        else {
-            /* Add stream to closed set for cleanup when task is done */
-            h2_stream_set_add(m->closed, stream);
+        h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
+
+        /* there should be an h2_io, once the stream has been scheduled
+         * for processing, e.g. when we received all HEADERs. But when
+         * a stream is cancelled very early, it will not exist. */
+        if (io) {
+            /* Remove io from ready set, we will never submit it */
+            h2_io_set_remove(m->ready_ios, io);
+            if (io->task_done || h2_tq_remove(m->q, io->id)) {
+                /* already finished or not even started yet */
+                io_destroy(m, io);
+            }
+            else {
+                /* cleanup once task is done */
+                io->orphaned = 1;
+                if (rst_error) {
+                    h2_io_rst(io, rst_error);
+                }
+            }
+            
         }
+        
         apr_thread_mutex_unlock(m->lock);
     }
     return status;
@@ -310,21 +300,17 @@ void h2_mplx_task_done(h2_mplx *m, int s
 {
     apr_status_t status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        h2_stream *stream = h2_stream_set_get(m->closed, stream_id);
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
                       "h2_mplx(%ld): task(%d) done", m->id, stream_id);
-        if (stream) {
-            /* stream was already closed by main connection and is in 
-             * zombie state. Now that the task is done with it, we
-             * can free its resources. */
-            h2_stream_set_remove(m->closed, stream);
-            stream_destroy(m, stream, io);
-        }
-        else if (io) {
-            /* main connection has not finished stream. Mark task as done
-             * so that eventual cleanup can start immediately. */
+        if (io) {
             io->task_done = 1;
+            if (io->orphaned) {
+                io_destroy(m, io);
+            }
+            else {
+                /* hang around until the stream deregisteres */
+            }
         }
         apr_thread_mutex_unlock(m->lock);
     }
@@ -342,15 +328,17 @@ apr_status_t h2_mplx_in_read(h2_mplx *m,
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-        if (io) {
+        if (io && !io->orphaned) {
             io->input_arrived = iowait;
-            status = h2_io_in_read(io, bb, 0);
-            while (status == APR_EAGAIN 
+            H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_read_pre");
+            status = h2_io_in_read(io, bb, -1);
+            while (APR_STATUS_IS_EAGAIN(status) 
                    && !is_aborted(m, &status)
                    && block == APR_BLOCK_READ) {
                 apr_thread_cond_wait(io->input_arrived, m->lock);
-                status = h2_io_in_read(io, bb, 0);
+                status = h2_io_in_read(io, bb, -1);
             }
+            H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_read_post");
             io->input_arrived = NULL;
         }
         else {
@@ -372,8 +360,10 @@ apr_status_t h2_mplx_in_write(h2_mplx *m
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-        if (io) {
+        if (io && !io->orphaned) {
+            H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_write_pre");
             status = h2_io_in_write(io, bb);
+            H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_write_post");
             if (io->input_arrived) {
                 apr_thread_cond_signal(io->input_arrived);
             }
@@ -396,8 +386,9 @@ apr_status_t h2_mplx_in_close(h2_mplx *m
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-        if (io) {
+        if (io && !io->orphaned) {
             status = h2_io_in_close(io);
+            H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_close");
             if (io->input_arrived) {
                 apr_thread_cond_signal(io->input_arrived);
             }
@@ -456,7 +447,7 @@ apr_status_t h2_mplx_in_update_windows(h
 
 apr_status_t h2_mplx_out_readx(h2_mplx *m, int stream_id, 
                                h2_io_data_cb *cb, void *ctx, 
-                               apr_size_t *plen, int *peos)
+                               apr_off_t *plen, int *peos)
 {
     apr_status_t status;
     AP_DEBUG_ASSERT(m);
@@ -466,8 +457,42 @@ apr_status_t h2_mplx_out_readx(h2_mplx *
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-        if (io) {
+        if (io && !io->orphaned) {
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_readx_pre");
+            
             status = h2_io_out_readx(io, cb, ctx, plen, peos);
+            
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_readx_post");
+            if (status == APR_SUCCESS && cb && io->output_drained) {
+                apr_thread_cond_signal(io->output_drained);
+            }
+        }
+        else {
+            status = APR_ECONNABORTED;
+        }
+        apr_thread_mutex_unlock(m->lock);
+    }
+    return status;
+}
+
+apr_status_t h2_mplx_out_read_to(h2_mplx *m, int stream_id, 
+                                 apr_bucket_brigade *bb, 
+                                 apr_off_t *plen, int *peos)
+{
+    apr_status_t status;
+    AP_DEBUG_ASSERT(m);
+    if (m->aborted) {
+        return APR_ECONNABORTED;
+    }
+    status = apr_thread_mutex_lock(m->lock);
+    if (APR_SUCCESS == status) {
+        h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
+        if (io && !io->orphaned) {
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_pre");
+            
+            status = h2_io_out_read_to(io, bb, plen, peos);
+            
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_post");
             if (status == APR_SUCCESS && io->output_drained) {
                 apr_thread_cond_signal(io->output_drained);
             }
@@ -490,24 +515,42 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
     }
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        h2_io *io = h2_io_set_get_highest_prio(m->ready_ios);
+        h2_io *io = h2_io_set_pop_highest_prio(m->ready_ios);
         if (io) {
-            h2_response *response = io->response;
-            
-            AP_DEBUG_ASSERT(response);
-            h2_io_set_remove(m->ready_ios, io);
-            
-            stream = h2_stream_set_get(streams, response->stream_id);
+            stream = h2_stream_set_get(streams, io->id);
             if (stream) {
-                h2_stream_set_response(stream, response, io->bbout);
-                if (io->output_drained) {
-                    apr_thread_cond_signal(io->output_drained);
+                if (io->rst_error) {
+                    h2_stream_rst(stream, io->rst_error);
+                }
+                else {
+                    AP_DEBUG_ASSERT(io->response);
+                    H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_pre");
+                    h2_stream_set_response(stream, io->response, io->bbout);
+                    H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_post");
                 }
+                
             }
             else {
-                ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_NOTFOUND, m->c,
-                              APLOGNO(02953) "h2_mplx(%ld): stream for response %d",
-                              m->id, response->stream_id);
+                /* We have the io ready, but the stream has gone away, maybe
+                 * reset by the client. Should no longer happen since such
+                 * streams should clear io's from the ready queue.
+                 */
+                ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c, APLOGNO(02953) 
+                              "h2_mplx(%ld): stream for response %d closed, "
+                              "resetting io to close request processing",
+                              m->id, io->id);
+                io->orphaned = 1;
+                if (io->task_done) {
+                    io_destroy(m, io);
+                }
+                else {
+                    /* hang around until the h2_task is done */
+                    h2_io_rst(io, H2_ERR_STREAM_CLOSED);
+                }
+            }
+            
+            if (io->output_drained) {
+                apr_thread_cond_signal(io->output_drained);
             }
         }
         apr_thread_mutex_unlock(m->lock);
@@ -531,7 +574,6 @@ static apr_status_t out_write(h2_mplx *m
         
         status = h2_io_out_write(io, bb, m->stream_max_mem, 
                                  &m->file_handles_allowed);
-        
         /* Wait for data to drain until there is room again */
         while (!APR_BRIGADE_EMPTY(bb) 
                && iowait
@@ -549,6 +591,7 @@ static apr_status_t out_write(h2_mplx *m
         }
     }
     apr_brigade_cleanup(bb);
+    
     return status;
 }
 
@@ -559,15 +602,15 @@ static apr_status_t out_open(h2_mplx *m,
     apr_status_t status = APR_SUCCESS;
     
     h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-    if (io) {
+    if (io && !io->orphaned) {
         if (f) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
-                          "h2_mplx(%ld-%d): open response: %s",
-                          m->id, stream_id, response->status);
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
+                          "h2_mplx(%ld-%d): open response: %d, rst=%d",
+                          m->id, stream_id, response->http_status, 
+                          response->rst_error);
         }
         
-        io->response = h2_response_copy(io->pool, response);
-        AP_DEBUG_ASSERT(io->response);
+        h2_io_set_response(io, response);
         h2_io_set_add(m->ready_ios, io);
         if (bb) {
             status = out_write(m, io, f, bb, iowait);
@@ -592,6 +635,9 @@ apr_status_t h2_mplx_out_open(h2_mplx *m
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         status = out_open(m, stream_id, response, f, bb, iowait);
+        if (APLOGctrace1(m->c)) {
+            h2_util_bb_log(m->c, stream_id, APLOG_TRACE1, "h2_mplx_out_open", bb);
+        }
         if (m->aborted) {
             return APR_ECONNABORTED;
         }
@@ -614,8 +660,10 @@ apr_status_t h2_mplx_out_write(h2_mplx *
     if (APR_SUCCESS == status) {
         if (!m->aborted) {
             h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-            if (io) {
+            if (io && !io->orphaned) {
                 status = out_write(m, io, f, bb, iowait);
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write");
+                
                 have_out_data_for(m, stream_id);
                 if (m->aborted) {
                     return APR_ECONNABORTED;
@@ -644,17 +692,22 @@ apr_status_t h2_mplx_out_close(h2_mplx *
     if (APR_SUCCESS == status) {
         if (!m->aborted) {
             h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
-            if (io) {
-                if (!io->response || !io->response->ngheader) {
+            if (io && !io->orphaned) {
+                if (!io->response && !io->rst_error) {
                     /* In case a close comes before a response was created,
                      * insert an error one so that our streams can properly
                      * reset.
                      */
-                    h2_response *r = h2_response_create(stream_id, 
-                                                        "500", NULL, m->pool);
+                    h2_response *r = h2_response_create(stream_id, 0, 
+                                                        500, NULL, m->pool);
                     status = out_open(m, stream_id, r, NULL, NULL, NULL);
+                    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
+                                  "h2_mplx(%ld-%d): close, no response, no rst", 
+                                  m->id, io->id);
                 }
                 status = h2_io_out_close(io);
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close");
+                
                 have_out_data_for(m, stream_id);
                 if (m->aborted) {
                     /* if we were the last output, the whole session might
@@ -672,6 +725,38 @@ apr_status_t h2_mplx_out_close(h2_mplx *
     return status;
 }
 
+apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error)
+{
+    apr_status_t status;
+    AP_DEBUG_ASSERT(m);
+    if (m->aborted) {
+        return APR_ECONNABORTED;
+    }
+    status = apr_thread_mutex_lock(m->lock);
+    if (APR_SUCCESS == status) {
+        if (!m->aborted) {
+            h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
+            if (io && !io->rst_error && !io->orphaned) {
+                h2_io_rst(io, error);
+                if (!io->response) {
+                        h2_io_set_add(m->ready_ios, io);
+                }
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_rst");
+                
+                have_out_data_for(m, stream_id);
+                if (io->output_drained) {
+                    apr_thread_cond_signal(io->output_drained);
+                }
+            }
+            else {
+                status = APR_ECONNABORTED;
+            }
+        }
+        apr_thread_mutex_unlock(m->lock);
+    }
+    return status;
+}
+
 int h2_mplx_in_has_eos_for(h2_mplx *m, int stream_id)
 {
     int has_eos = 0;
@@ -684,7 +769,7 @@ int h2_mplx_in_has_eos_for(h2_mplx *m, i
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
         if (io) {
-            has_eos = h2_io_in_has_eos_for(io);
+            has_eos = io->orphaned || h2_io_in_has_eos_for(io);
         }
         apr_thread_mutex_unlock(m->lock);
     }
@@ -742,61 +827,104 @@ static void have_out_data_for(h2_mplx *m
     }
 }
 
-apr_status_t h2_mplx_do_task(h2_mplx *m, struct h2_task *task)
+apr_status_t h2_mplx_reprioritize(h2_mplx *m, h2_stream_pri_cmp *cmp, void *ctx)
 {
     apr_status_t status;
+    
     AP_DEBUG_ASSERT(m);
     if (m->aborted) {
         return APR_ECONNABORTED;
     }
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        /* TODO: needs to sort queue by priority */
+        h2_tq_sort(m->q, cmp, ctx);
+        
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
-                      "h2_mplx: do task(%s)", task->id);
-        h2_tq_append(m->q, task);
+                      "h2_mplx(%ld): reprioritize tasks", m->id);
         apr_thread_mutex_unlock(m->lock);
     }
     workers_register(m);
     return status;
 }
 
-h2_task *h2_mplx_pop_task(h2_mplx *m, int *has_more)
+static h2_io *open_io(h2_mplx *m, int stream_id)
+{
+    apr_pool_t *io_pool = m->spare_pool;
+    h2_io *io;
+    
+    if (!io_pool) {
+        apr_pool_create(&io_pool, m->pool);
+    }
+    else {
+        m->spare_pool = NULL;
+    }
+    
+    io = h2_io_create(stream_id, io_pool, m->bucket_alloc);
+    h2_io_set_add(m->stream_ios, io);
+    
+    return io;
+}
+
+
+apr_status_t h2_mplx_process(h2_mplx *m, int stream_id,
+                             const h2_request *req, int eos, 
+                             h2_stream_pri_cmp *cmp, void *ctx)
 {
-    h2_task *task = NULL;
     apr_status_t status;
+    
     AP_DEBUG_ASSERT(m);
     if (m->aborted) {
-        *has_more = 0;
-        return NULL;
+        return APR_ECONNABORTED;
     }
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        task = h2_tq_pop_first(m->q);
-        if (task) {
-            h2_task_set_started(task);
+        h2_io *io = open_io(m, stream_id);
+        io->request = req;
+        io->request_body = !eos;
+
+        if (eos) {
+            status = h2_io_in_close(io);
         }
-        *has_more = !h2_tq_empty(m->q);
+        
+        h2_tq_add(m->q, io->id, cmp, ctx);
+
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
+                      "h2_mplx(%ld-%d): process", m->c->id, stream_id);
+        H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_process");
         apr_thread_mutex_unlock(m->lock);
     }
-    return task;
+    
+    if (status == APR_SUCCESS) {
+        workers_register(m);
+    }
+    return status;
 }
 
-apr_status_t h2_mplx_create_task(h2_mplx *m, struct h2_stream *stream)
+h2_task *h2_mplx_pop_task(h2_mplx *m, h2_worker *w, int *has_more)
 {
+    h2_task *task = NULL;
     apr_status_t status;
+    
     AP_DEBUG_ASSERT(m);
     if (m->aborted) {
-        return APR_ECONNABORTED;
+        *has_more = 0;
+        return NULL;
     }
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
-        conn_rec *c = h2_conn_create(m->c, stream->pool);
-        stream->task = h2_task_create(m->id, stream->id, 
-                                      stream->pool, m, c);
-        
+        int sid;
+        while (!task && (sid = h2_tq_shift(m->q)) > 0) {
+            /* Anything not already setup correctly in the task
+             * needs to be so now, as task will be executed right about 
+             * when this method returns. */
+            h2_io *io = h2_io_set_get(m->stream_ios, sid);
+            if (io) {
+                task = h2_worker_create_task(w, m, io->request, !io->request_body);
+            }
+        }
+        *has_more = !h2_tq_empty(m->q);
         apr_thread_mutex_unlock(m->lock);
     }
-    return status;
+    return task;
 }
 

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -41,8 +41,10 @@ struct h2_config;
 struct h2_response;
 struct h2_task;
 struct h2_stream;
+struct h2_request;
 struct h2_io_set;
 struct apr_thread_cond_t;
+struct h2_worker;
 struct h2_workers;
 struct h2_stream_set;
 struct h2_task_queue;
@@ -54,7 +56,7 @@ typedef struct h2_mplx h2_mplx;
 struct h2_mplx {
     long id;
     APR_RING_ENTRY(h2_mplx) link;
-    volatile apr_uint32_t refs;
+    volatile int refs;
     conn_rec *c;
     apr_pool_t *pool;
     apr_bucket_alloc_t *bucket_alloc;
@@ -70,12 +72,13 @@ struct h2_mplx {
     int aborted;
     apr_size_t stream_max_mem;
     
-    apr_pool_t *spare_pool;           /* spare pool, ready for next stream */
-    struct h2_stream_set *closed;     /* streams closed, but task ongoing */
+    apr_pool_t *spare_pool;           /* spare pool, ready for next io */
     struct h2_workers *workers;
     int file_handles_allowed;
 };
 
+
+
 /*******************************************************************************
  * Object lifecycle and information.
  ******************************************************************************/
@@ -96,6 +99,7 @@ void h2_mplx_reference(h2_mplx *m);
  * Decreases the reference counter of this mplx.
  */
 void h2_mplx_release(h2_mplx *m);
+
 /**
  * Decreases the reference counter of this mplx and waits for it
  * to reached 0, destroy the mplx afterwards.
@@ -117,15 +121,16 @@ void h2_mplx_task_done(h2_mplx *m, int s
 /*******************************************************************************
  * IO lifetime of streams.
  ******************************************************************************/
-/**
- * Prepares the multiplexer to handle in-/output on the given stream id.
- */
-struct h2_stream *h2_mplx_open_io(h2_mplx *mplx, int stream_id);
 
 /**
- * Ends cleanup of a stream in sync with execution thread.
+ * Notifies mplx that a stream has finished processing.
+ * 
+ * @param m the mplx itself
+ * @param stream_id the id of the stream being done
+ * @param rst_error if != 0, the stream was reset with the error given
+ *
  */
-apr_status_t h2_mplx_cleanup_stream(h2_mplx *m, struct h2_stream *stream);
+apr_status_t h2_mplx_stream_done(h2_mplx *m, int stream_id, int rst_error);
 
 /* Return != 0 iff the multiplexer has data for the given stream. 
  */
@@ -143,13 +148,29 @@ apr_status_t h2_mplx_out_trywait(h2_mplx
  ******************************************************************************/
 
 /**
- * Perform the task on the given stream.
+ * Process a stream request.
+ * 
+ * @param m the multiplexer
+ * @param stream_id the identifier of the stream
+ * @param r the request to be processed
+ * @param eos if input is complete
+ * @param cmp the stream priority compare function
+ * @param ctx context data for the compare function
+ */
+apr_status_t h2_mplx_process(h2_mplx *m, int stream_id,
+                             const struct h2_request *r, int eos, 
+                             h2_stream_pri_cmp *cmp, void *ctx);
+
+/**
+ * Stream priorities have changed, reschedule pending tasks.
+ * 
+ * @param m the multiplexer
+ * @param cmp the stream priority compare function
+ * @param ctx context data for the compare function
  */
-apr_status_t h2_mplx_do_task(h2_mplx *mplx, struct h2_task *task);
-
-struct h2_task *h2_mplx_pop_task(h2_mplx *mplx, int *has_more);
+apr_status_t h2_mplx_reprioritize(h2_mplx *m, h2_stream_pri_cmp *cmp, void *ctx);
 
-apr_status_t h2_mplx_create_task(h2_mplx *mplx, struct h2_stream *stream);
+struct h2_task *h2_mplx_pop_task(h2_mplx *mplx, struct h2_worker *w, int *has_more);
 
 /*******************************************************************************
  * Input handling of streams.
@@ -188,7 +209,7 @@ int h2_mplx_in_has_eos_for(h2_mplx *m, i
  * Callback invoked for every stream that had input data read since
  * the last invocation.
  */
-typedef void h2_mplx_consumed_cb(void *ctx, int stream_id, apr_size_t consumed);
+typedef void h2_mplx_consumed_cb(void *ctx, int stream_id, apr_off_t consumed);
 
 /**
  * Invoke the callback for all streams that had bytes read since the last
@@ -219,7 +240,15 @@ struct h2_stream *h2_mplx_next_submit(h2
  */
 apr_status_t h2_mplx_out_readx(h2_mplx *mplx, int stream_id, 
                                h2_io_data_cb *cb, void *ctx, 
-                               apr_size_t *plen, int *peos);
+                               apr_off_t *plen, int *peos);
+
+/**
+ * Reads output data into the given brigade. Will never block, but
+ * return APR_EAGAIN until data arrives or the stream is closed.
+ */
+apr_status_t h2_mplx_out_read_to(h2_mplx *mplx, int stream_id, 
+                                 apr_bucket_brigade *bb, 
+                                 apr_off_t *plen, int *peos);
 
 /**
  * Opens the output for the given stream with the specified response.
@@ -247,6 +276,8 @@ apr_status_t h2_mplx_out_write(h2_mplx *
  */
 apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id);
 
+apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error);
+
 /*******************************************************************************
  * h2_mplx list Manipulation.
  ******************************************************************************/



Mime
View raw message