You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2015/11/20 16:13:11 UTC
svn commit: r1715371 [2/6] - in /httpd/httpd/branches/2.4.x: ./
docs/manual/mod/ modules/http2/
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.
******************************************************************************/