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/04 16:45:25 UTC

svn commit: r1712570 [11/13] - in /httpd/httpd/branches/2.4-http2-alpha: ./ docs/conf/ docs/manual/mod/ include/ modules/cache/ modules/http2/ modules/ssl/ server/

Modified: httpd/httpd/branches/2.4-http2-alpha/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/include/ap_mmn.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/include/ap_mmn.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/include/ap_mmn.h Wed Nov  4 15:44:24 2015
@@ -456,6 +456,7 @@
  *                          ap_select_protocol(), ap_switch_protocol(),
  *                          ap_get_protocol(). Add HTTP_MISDIRECTED_REQUEST.
  *                          Added ap_parse_token_list_strict() to httpd.h
+ * 20120211.52 (2.4.17-dev) Add master conn_rec* member in conn_rec.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -463,7 +464,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20120211
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 51                   /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 52                   /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/branches/2.4-http2-alpha/include/http_core.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/include/http_core.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/include/http_core.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/include/http_core.h Wed Nov  4 15:44:24 2015
@@ -465,6 +465,17 @@ typedef unsigned long etag_components_t;
 /* This is the default value used */
 #define ETAG_BACKWARD (ETAG_MTIME | ETAG_SIZE)
 
+/* Generic ON/OFF/UNSET for unsigned int foo :2 */
+#define AP_CORE_CONFIG_OFF   (0)
+#define AP_CORE_CONFIG_ON    (1)
+#define AP_CORE_CONFIG_UNSET (2)
+
+/* Generic merge of flag */
+#define AP_CORE_MERGE_FLAG(field, to, base, over) to->field = \
+               over->field != AP_CORE_CONFIG_UNSET            \
+               ? over->field                                  \
+               : base->field                                   
+
 /**
  * @brief Server Signature Enumeration
  */
@@ -630,6 +641,8 @@ typedef struct {
      * advice
      */
     unsigned int cgi_pass_auth : 2;
+    unsigned int qualify_redirect_url :2;
+
 } core_dir_config;
 
 /* macro to implement off by default behaviour */

Modified: httpd/httpd/branches/2.4-http2-alpha/include/http_protocol.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/include/http_protocol.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/include/http_protocol.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/include/http_protocol.h Wed Nov  4 15:44:24 2015
@@ -782,7 +782,27 @@ AP_DECLARE_HOOK(int,protocol_switch,(con
  * @return The identifier of the protocol in place or NULL
  */
 AP_DECLARE_HOOK(const char *,protocol_get,(const conn_rec *c))
-    
+
+/**
+ * Get the protocols that the connection and optional request may
+ * upgrade to - besides the protocol currently active on the connection. These
+ * values may be used to announce to a client what choices it has.
+ *
+ * If report_all == 0, only protocols more preferable than the one currently
+ * being used, are reported. Otherwise, all available protocols beside the
+ * current one are being reported.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected or NULL
+ * @param report_all include also protocols less preferred than the current one
+ * @param pupgrades on return, possible protocols to upgrade to in descending order 
+ *                 of preference. Maybe NULL if none are available.    
+ */
+AP_DECLARE(apr_status_t) ap_get_protocol_upgrades(conn_rec *c, request_rec *r, 
+                                                  server_rec *s, int report_all, 
+                                                  const apr_array_header_t **pupgrades);
+                                                  
 /**
  * Select a protocol for the given connection and optional request. Will return
  * the protocol identifier selected which may be the protocol already in place
@@ -833,6 +853,23 @@ AP_DECLARE(apr_status_t) ap_switch_proto
  */
 AP_DECLARE(const char *) ap_get_protocol(conn_rec *c);
 
+/**
+ * Check if the given protocol is an allowed choice on the given
+ * combination of connection, request and server. 
+ *
+ * When server is NULL, it is taken from request_rec, unless
+ * request_rec is NULL. Then it is taken from the connection base
+ * server.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected or NULL
+ * @param protocol the protocol to switch to
+ * @return != 0 iff protocol is allowed
+ */
+AP_DECLARE(int) ap_is_allowed_protocol(conn_rec *c, request_rec *r,
+                                       server_rec *s, const char *protocol);
+
 /** @see ap_bucket_type_error */
 typedef struct ap_bucket_error ap_bucket_error;
 

Modified: httpd/httpd/branches/2.4-http2-alpha/include/httpd.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/include/httpd.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/include/httpd.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/include/httpd.h Wed Nov  4 15:44:24 2015
@@ -1167,6 +1167,9 @@ struct conn_rec {
 #if APR_HAS_THREADS
     apr_thread_t *current_thread;
 #endif
+
+    /** The "real" master connection. NULL if I am the master. */
+    conn_rec *master;
 };
 
 /**

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/cache/cache_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/cache/cache_util.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/cache/cache_util.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/cache/cache_util.h Wed Nov  4 15:44:24 2015
@@ -99,7 +99,7 @@ extern "C" {
 #define CACHE_LOCKNAME_KEY "mod_cache-lockname"
 #define CACHE_LOCKFILE_KEY "mod_cache-lockfile"
 #define CACHE_CTX_KEY "mod_cache-ctx"
-#define CACHE_SEPARATOR ",   "
+#define CACHE_SEPARATOR ", \t"
 
 /**
  * cache_util.c

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/config.m4?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/config.m4 (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/config.m4 Wed Nov  4 15:44:24 2015
@@ -20,6 +20,8 @@ dnl #  list of module object files
 http2_objs="dnl
 mod_http2.lo dnl
 h2_alt_svc.lo dnl
+h2_bucket_eoc.lo dnl
+h2_bucket_eos.lo dnl
 h2_config.lo dnl
 h2_conn.lo dnl
 h2_conn_io.lo dnl

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.c Wed Nov  4 15:44:24 2015
@@ -49,6 +49,10 @@ static h2_config defconf = {
     0,                /* serialize headers */
     -1,               /* h2 direct mode */
     -1,               /* # session extra files */
+    1,                /* modern TLS only */
+    -1,               /* HTTP/1 Upgrade support */
+    1024*1024,        /* TLS warmup size */
+    1,                /* TLS cooldown secs */
 };
 
 static int files_per_session = 0;
@@ -100,6 +104,11 @@ static void *h2_config_create(apr_pool_t
     conf->serialize_headers    = DEF_VAL;
     conf->h2_direct            = DEF_VAL;
     conf->session_extra_files  = DEF_VAL;
+    conf->modern_tls_only      = DEF_VAL;
+    conf->h2_upgrade           = DEF_VAL;
+    conf->tls_warmup_size      = DEF_VAL;
+    conf->tls_cooldown_secs    = DEF_VAL;
+    
     return conf;
 }
 
@@ -127,23 +136,32 @@ void *h2_config_merge(apr_pool_t *pool,
     strcat(name, "]");
     n->name = name;
 
-    n->h2_max_streams = H2_CONFIG_GET(add, base, h2_max_streams);
-    n->h2_window_size = H2_CONFIG_GET(add, base, h2_window_size);
-    n->min_workers    = H2_CONFIG_GET(add, base, min_workers);
-    n->max_workers    = H2_CONFIG_GET(add, base, max_workers);
+    n->h2_max_streams       = H2_CONFIG_GET(add, base, h2_max_streams);
+    n->h2_window_size       = H2_CONFIG_GET(add, base, h2_window_size);
+    n->min_workers          = H2_CONFIG_GET(add, base, min_workers);
+    n->max_workers          = H2_CONFIG_GET(add, base, max_workers);
     n->max_worker_idle_secs = H2_CONFIG_GET(add, base, max_worker_idle_secs);
-    n->stream_max_mem_size = H2_CONFIG_GET(add, base, stream_max_mem_size);
-    n->alt_svcs = add->alt_svcs? add->alt_svcs : base->alt_svcs;
-    n->alt_svc_max_age = H2_CONFIG_GET(add, base, alt_svc_max_age);
-    n->serialize_headers = H2_CONFIG_GET(add, base, serialize_headers);
-    n->h2_direct      = H2_CONFIG_GET(add, base, h2_direct);
-    n->session_extra_files = H2_CONFIG_GET(add, base, session_extra_files);
+    n->stream_max_mem_size  = H2_CONFIG_GET(add, base, stream_max_mem_size);
+    n->alt_svcs             = add->alt_svcs? add->alt_svcs : base->alt_svcs;
+    n->alt_svc_max_age      = H2_CONFIG_GET(add, base, alt_svc_max_age);
+    n->serialize_headers    = H2_CONFIG_GET(add, base, serialize_headers);
+    n->h2_direct            = H2_CONFIG_GET(add, base, h2_direct);
+    n->session_extra_files  = H2_CONFIG_GET(add, base, session_extra_files);
+    n->modern_tls_only      = H2_CONFIG_GET(add, base, modern_tls_only);
+    n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
+    n->tls_warmup_size      = H2_CONFIG_GET(add, base, tls_warmup_size);
+    n->tls_cooldown_secs    = H2_CONFIG_GET(add, base, tls_cooldown_secs);
     
     return n;
 }
 
 int h2_config_geti(h2_config *conf, h2_config_var_t var)
 {
+    return (int)h2_config_geti64(conf, var);
+}
+
+apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var)
+{
     int n;
     switch(var) {
         case H2_CONF_MAX_STREAMS:
@@ -162,6 +180,10 @@ int h2_config_geti(h2_config *conf, h2_c
             return H2_CONFIG_GET(conf, &defconf, alt_svc_max_age);
         case H2_CONF_SER_HEADERS:
             return H2_CONFIG_GET(conf, &defconf, serialize_headers);
+        case H2_CONF_MODERN_TLS_ONLY:
+            return H2_CONFIG_GET(conf, &defconf, modern_tls_only);
+        case H2_CONF_UPGRADE:
+            return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
         case H2_CONF_DIRECT:
             return H2_CONFIG_GET(conf, &defconf, h2_direct);
         case H2_CONF_SESSION_FILES:
@@ -170,6 +192,10 @@ int h2_config_geti(h2_config *conf, h2_c
                 n = files_per_session;
             }
             return n;
+        case H2_CONF_TLS_WARMUP_SIZE:
+            return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
+        case H2_CONF_TLS_COOLDOWN_SECS:
+            return H2_CONFIG_GET(conf, &defconf, tls_cooldown_secs);
         default:
             return DEF_VAL;
     }
@@ -290,8 +316,8 @@ static const char *h2_conf_set_session_e
 {
     h2_config *cfg = h2_config_sget(parms->server);
     apr_int64_t max = (int)apr_atoi64(value);
-    if (max <= 0) {
-        return "value must be a positive number";
+    if (max < 0) {
+        return "value must be a non-negative number";
     }
     cfg->session_extra_files = (int)max;
     (void)arg;
@@ -332,8 +358,60 @@ static const char *h2_conf_set_direct(cm
     return "value must be On or Off";
 }
 
-#define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
+static const char *h2_conf_set_modern_tls_only(cmd_parms *parms,
+                                               void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    if (!strcasecmp(value, "On")) {
+        cfg->modern_tls_only = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->modern_tls_only = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
 
+static const char *h2_conf_set_upgrade(cmd_parms *parms,
+                                       void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    if (!strcasecmp(value, "On")) {
+        cfg->h2_upgrade = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->h2_upgrade = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
+
+static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms,
+                                               void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->tls_warmup_size = apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms,
+                                                 void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->tls_cooldown_secs = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+
+#define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
 
 const command_rec h2_cmds[] = {
     AP_INIT_TAKE1("H2MaxSessionStreams", h2_conf_set_max_streams, NULL,
@@ -354,10 +432,18 @@ const command_rec h2_cmds[] = {
                   RSRC_CONF, "set the maximum age (in seconds) that client can rely on alt-svc information"),
     AP_INIT_TAKE1("H2SerializeHeaders", h2_conf_set_serialize_headers, NULL,
                   RSRC_CONF, "on to enable header serialization for compatibility"),
+    AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
+                  RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
+    AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
+                  RSRC_CONF, "on to allow HTTP/1 Upgrades to h2/h2c"),
     AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
                   RSRC_CONF, "on to enable direct HTTP/2 mode"),
     AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
                   RSRC_CONF, "number of extra file a session might keep open"),
+    AP_INIT_TAKE1("H2TLSWarmUpSize", h2_conf_set_tls_warmup_size, NULL,
+                  RSRC_CONF, "number of bytes on TLS connection before doing max writes"),
+    AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
+                  RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
     AP_END_CMD
 };
 

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_config.h Wed Nov  4 15:44:24 2015
@@ -34,6 +34,10 @@ typedef enum {
     H2_CONF_SER_HEADERS,
     H2_CONF_DIRECT,
     H2_CONF_SESSION_FILES,
+    H2_CONF_MODERN_TLS_ONLY,
+    H2_CONF_UPGRADE,
+    H2_CONF_TLS_WARMUP_SIZE,
+    H2_CONF_TLS_COOLDOWN_SECS,
 } h2_config_var_t;
 
 /* Apache httpd module configuration for h2. */
@@ -51,6 +55,10 @@ typedef struct h2_config {
                                      processing, better compatibility */
     int h2_direct;                /* if mod_h2 is active directly */
     int session_extra_files;      /* # of extra files a session may keep open */  
+    int modern_tls_only;          /* Accept only modern TLS in HTTP/2 connections */  
+    int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
+    apr_int64_t tls_warmup_size;  /* Amount of TLS data to send before going full write size */
+    int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
 } h2_config;
 
 
@@ -67,6 +75,7 @@ h2_config *h2_config_sget(server_rec *s)
 h2_config *h2_config_rget(request_rec *r);
 
 int h2_config_geti(h2_config *conf, h2_config_var_t var);
+apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var);
 
 void h2_config_init(apr_pool_t *pool);
 

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.c Wed Nov  4 15:44:24 2015
@@ -32,6 +32,7 @@
 #include "h2_session.h"
 #include "h2_stream.h"
 #include "h2_stream_set.h"
+#include "h2_h2.h"
 #include "h2_task.h"
 #include "h2_worker.h"
 #include "h2_workers.h"
@@ -43,7 +44,6 @@ static apr_status_t h2_conn_loop(h2_sess
 
 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
 static module *mpm_module;
-static module *ssl_module;
 static int checked;
 
 static void check_modules(void) 
@@ -64,9 +64,6 @@ static void check_modules(void)
                 mpm_type = H2_MPM_PREFORK;
                 mpm_module = m;
             }
-            else if (!strcmp("mod_ssl.c", m->name)) {
-                ssl_module = m;
-            }
         }
         checked = 1;
     }
@@ -103,9 +100,6 @@ apr_status_t h2_conn_child_init(apr_pool
             mpm_type = H2_MPM_PREFORK;
             mpm_module = m;
         }
-        else if (!strcmp("mod_ssl.c", m->name)) {
-            ssl_module = m;
-        }
     }
     
     if (minw <= 0) {
@@ -177,6 +171,11 @@ apr_status_t h2_conn_main(conn_rec *c)
         return APR_EGENERAL;
     }
     
+    if (!h2_is_acceptable_connection(c, 1)) {
+        nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE, 0,
+                              NGHTTP2_INADEQUATE_SECURITY, NULL, 0);
+    } 
+
     status = h2_conn_loop(session);
 
     /* Make sure this connection gets closed properly. */
@@ -241,7 +240,7 @@ static apr_status_t h2_conn_loop(h2_sess
                   session->c->local_addr->port);
     if (status != APR_SUCCESS) {
         h2_session_abort(session, status, rv);
-        h2_session_destroy(session);
+        h2_session_cleanup(session);
         return status;
     }
     
@@ -344,12 +343,9 @@ static apr_status_t h2_conn_loop(h2_sess
     ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
                   "h2_session(%ld): done", session->id);
     
+    h2_session_close(session);
     ap_update_child_status_from_conn(session->c->sbh, SERVER_CLOSING, 
                                      session->c);
-
-    h2_session_close(session);
-    h2_session_destroy(session);
-    
     return DONE;
 }
 
@@ -412,11 +408,11 @@ conn_rec *h2_conn_create(conn_rec *maste
     return c;
 }
 
-apr_status_t h2_conn_setup(h2_task_env *env, struct h2_worker *worker)
+apr_status_t h2_conn_setup(h2_task *task, struct h2_worker *worker)
 {
-    conn_rec *master = env->mplx->c;
+    conn_rec *master = task->mplx->c;
     
-    ap_log_perror(APLOG_MARK, APLOG_TRACE3, 0, env->pool,
+    ap_log_perror(APLOG_MARK, APLOG_TRACE3, 0, task->pool,
                   "h2_conn(%ld): created from master", master->id);
     
     /* Ok, we are just about to start processing the connection and
@@ -425,28 +421,18 @@ apr_status_t h2_conn_setup(h2_task_env *
      * sub-resources from it, so that we get a nice reuse of
      * pools.
      */
-    env->c.pool = env->pool;
-    env->c.bucket_alloc = h2_worker_get_bucket_alloc(worker);
-    env->c.current_thread = h2_worker_get_thread(worker);
+    task->c->pool = task->pool;
+    task->c->bucket_alloc = h2_worker_get_bucket_alloc(worker);
+    task->c->current_thread = h2_worker_get_thread(worker);
     
-    env->c.conn_config = ap_create_conn_config(env->pool);
-    env->c.notes = apr_table_make(env->pool, 5);
+    task->c->conn_config = ap_create_conn_config(task->pool);
+    task->c->notes = apr_table_make(task->pool, 5);
     
-    ap_set_module_config(env->c.conn_config, &core_module, 
-                         h2_worker_get_socket(worker));
+    /* In order to do this in 2.4.x, we need to add a member to conn_rec */
+    task->c->master = master;
     
-    /* If we serve http:// requests over a TLS connection, we do
-     * not want any mod_ssl vars to be visible.
-     */
-    if (ssl_module && (!env->scheme || strcmp("http", env->scheme))) {
-        /* See #19, there is a range of SSL variables to be gotten from
-         * the main connection that should be available in request handlers
-         */
-        void *sslcfg = ap_get_module_config(master->conn_config, ssl_module);
-        if (sslcfg) {
-            ap_set_module_config(env->c.conn_config, ssl_module, sslcfg);
-        }
-    }
+    ap_set_module_config(task->c->conn_config, &core_module, 
+                         h2_worker_get_socket(worker));
     
     /* This works for mpm_worker so far. Other mpm modules have 
      * different needs, unfortunately. The most interesting one 
@@ -457,7 +443,7 @@ apr_status_t h2_conn_setup(h2_task_env *
             /* all fine */
             break;
         case H2_MPM_EVENT: 
-            fix_event_conn(&env->c, master);
+            fix_event_conn(task->c, master);
             break;
         default:
             /* fingers crossed */
@@ -469,7 +455,7 @@ apr_status_t h2_conn_setup(h2_task_env *
      * 400 Bad Request
      * when names do not match. We prefer a predictable 421 status.
      */
-    env->c.keepalives = 1;
+    task->c->keepalives = 1;
     
     return APR_SUCCESS;
 }

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn.h Wed Nov  4 15:44:24 2015
@@ -17,7 +17,6 @@
 #define __mod_h2__h2_conn__
 
 struct h2_task;
-struct h2_task_env;
 struct h2_worker;
 
 /* Process the connection that is now starting the HTTP/2
@@ -52,7 +51,7 @@ h2_mpm_type_t h2_conn_mpm_type(void);
 
 conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *stream_pool);
 
-apr_status_t h2_conn_setup(struct h2_task_env *env, struct h2_worker *worker);
+apr_status_t h2_conn_setup(struct h2_task *task, struct h2_worker *worker);
 apr_status_t h2_conn_post(conn_rec *c, struct h2_worker *worker);
 
 apr_status_t h2_conn_process(conn_rec *c, apr_socket_t *socket);

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.c Wed Nov  4 15:44:24 2015
@@ -28,31 +28,33 @@
 #include "h2_h2.h"
 #include "h2_util.h"
 
-#define WRITE_BUFFER_SIZE     (64*1024)
+#define TLS_DATA_MAX          (16*1024) 
+
+/* Calculated like this: assuming MTU 1500 bytes
+ * 1500 - 40 (IP) - 20 (TCP) - 40 (TCP options) 
+ *      - TLS overhead (60-100) 
+ * ~= 1300 bytes */
 #define WRITE_SIZE_INITIAL    1300
-#define WRITE_SIZE_MAX        (16*1024)
-#define WRITE_SIZE_IDLE_USEC  (1*APR_USEC_PER_SEC)
-#define WRITE_SIZE_THRESHOLD  (1*1024*1024)
+/* Calculated like this: max TLS record size 16*1024
+ *   - 40 (IP) - 20 (TCP) - 40 (TCP options) 
+ *    - TLS overhead (60-100) 
+ * which seems to create less TCP packets overall
+ */
+#define WRITE_SIZE_MAX        (TLS_DATA_MAX - 100) 
+
+#define WRITE_BUFFER_SIZE     (8*WRITE_SIZE_MAX)
 
 apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c)
 {
-    io->connection = c;
-    io->input = apr_brigade_create(c->pool, c->bucket_alloc);
-    io->output = apr_brigade_create(c->pool, c->bucket_alloc);
-    io->buflen = 0;
-    /* That is where we start with, 
-     * see https://issues.apache.org/jira/browse/TS-2503 */
-    io->write_size = WRITE_SIZE_INITIAL; 
-    io->last_write = 0;
-    io->buffer_output = h2_h2_is_tls(c);
-
-    /* Currently we buffer only for TLS output. The reason this gives
-     * improved performance is that buckets send to the mod_ssl network
-     * filter will be encrypted in chunks. There is a special filter
-     * that tries to aggregate data, but that does not work well when
-     * bucket sizes alternate between tiny frame headers and large data
-     * chunks.
-     */
+    h2_config *cfg = h2_config_get(c);
+    
+    io->connection         = c;
+    io->input              = apr_brigade_create(c->pool, c->bucket_alloc);
+    io->output             = apr_brigade_create(c->pool, c->bucket_alloc);
+    io->buflen             = 0;
+    io->is_tls             = h2_h2_is_tls(c);
+    io->buffer_output      = io->is_tls;
+    
     if (io->buffer_output) {
         io->bufsize = WRITE_BUFFER_SIZE;
         io->buffer = apr_pcalloc(c->pool, io->bufsize);
@@ -61,13 +63,33 @@ apr_status_t h2_conn_io_init(h2_conn_io
         io->bufsize = 0;
     }
     
+    if (io->is_tls) {
+        /* That is where we start with, 
+         * see https://issues.apache.org/jira/browse/TS-2503 */
+        io->warmup_size    = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE);
+        io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS) 
+                              * APR_USEC_PER_SEC);
+        io->write_size     = WRITE_SIZE_INITIAL; 
+    }
+    else {
+        io->warmup_size    = 0;
+        io->cooldown_usecs = 0;
+        io->write_size     = io->bufsize;
+    }
+
+    if (APLOGctrace1(c)) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+                      "h2_conn_io(%ld): init, buffering=%d, warmup_size=%ld, cd_secs=%f",
+                      io->connection->id, io->buffer_output, (long)io->warmup_size,
+                      ((float)io->cooldown_usecs/APR_USEC_PER_SEC));
+    }
+
     return APR_SUCCESS;
 }
 
-void h2_conn_io_destroy(h2_conn_io *io)
+int h2_conn_io_is_buffered(h2_conn_io *io)
 {
-    io->input = NULL;
-    io->output = NULL;
+    return io->bufsize > 0;
 }
 
 static apr_status_t h2_conn_io_bucket_read(h2_conn_io *io,
@@ -159,7 +181,7 @@ apr_status_t h2_conn_io_read(h2_conn_io
 
     status = ap_get_brigade(io->connection->input_filters,
                             io->input, AP_MODE_READBYTES,
-                            block, 16 * 4096);
+                            block, 64 * 4096);
     switch (status) {
         case APR_SUCCESS:
             return h2_conn_io_bucket_read(io, block, on_read_cb, puser, &done);
@@ -174,15 +196,22 @@ apr_status_t h2_conn_io_read(h2_conn_io
     return status;
 }
 
-static apr_status_t flush_out(apr_bucket_brigade *bb, void *ctx) 
+static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) 
 {
     h2_conn_io *io = (h2_conn_io*)ctx;
     apr_status_t status;
     apr_off_t bblen;
     
+    if (APR_BRIGADE_EMPTY(bb)) {
+        return APR_SUCCESS;
+    }
+    
     ap_update_child_status(io->connection->sbh, SERVER_BUSY_WRITE, NULL);
-    status = apr_brigade_length(bb, 1, &bblen);
+    status = apr_brigade_length(bb, 0, &bblen);
     if (status == APR_SUCCESS) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+                      "h2_conn_io(%ld): pass_out brigade %ld bytes",
+                      io->connection->id, (long)bblen);
         status = ap_pass_brigade(io->connection->output_filters, bb);
         if (status == APR_SUCCESS) {
             io->bytes_written += (apr_size_t)bblen;
@@ -193,14 +222,18 @@ static apr_status_t flush_out(apr_bucket
     return status;
 }
 
+/* Bring the current buffer content into the output brigade, appropriately
+ * chunked.
+ */
 static apr_status_t bucketeer_buffer(h2_conn_io *io) {
     const char *data = io->buffer;
     apr_size_t remaining = io->buflen;
     apr_bucket *b;
     int bcount, i;
 
-    if (io->write_size > WRITE_SIZE_INITIAL
-        && (apr_time_now() - io->last_write) >= WRITE_SIZE_IDLE_USEC) {
+    if (io->write_size > WRITE_SIZE_INITIAL 
+        && (io->cooldown_usecs > 0)
+        && (apr_time_now() - io->last_write) >= io->cooldown_usecs) {
         /* long time not written, reset write size */
         io->write_size = WRITE_SIZE_INITIAL;
         io->bytes_written = 0;
@@ -209,7 +242,7 @@ static apr_status_t bucketeer_buffer(h2_
                       (long)io->connection->id, (long)io->write_size);
     }
     else if (io->write_size < WRITE_SIZE_MAX 
-             && io->bytes_written >= WRITE_SIZE_THRESHOLD) {
+             && io->bytes_written >= io->warmup_size) {
         /* connection is hot, use max size */
         io->write_size = WRITE_SIZE_MAX;
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
@@ -238,16 +271,22 @@ apr_status_t h2_conn_io_write(h2_conn_io
                               const char *buf, size_t length)
 {
     apr_status_t status = APR_SUCCESS;
-    io->unflushed = 1;
     
-    if (io->buffer_output) {
+    io->unflushed = 1;
+    if (io->bufsize > 0) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
                       "h2_conn_io: buffering %ld bytes", (long)length);
+                      
+        if (!APR_BRIGADE_EMPTY(io->output)) {
+            status = h2_conn_io_flush(io);
+            io->unflushed = 1;
+        }
+        
         while (length > 0 && (status == APR_SUCCESS)) {
             apr_size_t avail = io->bufsize - io->buflen;
             if (avail <= 0) {
                 bucketeer_buffer(io);
-                status = flush_out(io->output, io);
+                status = pass_out(io->output, io);
                 io->buflen = 0;
             }
             else if (length > avail) {
@@ -266,46 +305,72 @@ apr_status_t h2_conn_io_write(h2_conn_io
         
     }
     else {
-        status = apr_brigade_write(io->output, flush_out, io, buf, length);
-        if (status != APR_SUCCESS) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
-                          "h2_conn_io: write error");
-        }
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, io->connection,
+                      "h2_conn_io: writing %ld bytes to brigade", (long)length);
+        status = apr_brigade_write(io->output, pass_out, io, buf, length);
     }
     
     return status;
 }
 
+apr_status_t h2_conn_io_writeb(h2_conn_io *io, apr_bucket *b)
+{
+    APR_BRIGADE_INSERT_TAIL(io->output, b);
+    io->unflushed = 1;
+    return APR_SUCCESS;
+}
+
+apr_status_t h2_conn_io_consider_flush(h2_conn_io *io)
+{
+    apr_status_t status = APR_SUCCESS;
+    int flush_now = 0;
+    
+    /* The HTTP/1.1 network output buffer/flush behaviour does not
+     * give optimal performance in the HTTP/2 case, as the pattern of
+     * buckets (data/eor/eos) is different.
+     * As long as we do not have found out the "best" way to deal with
+     * this, force a flush at least every WRITE_BUFFER_SIZE amount
+     * of data which seems to work nicely.
+     */
+    if (io->unflushed) {
+        apr_off_t len = 0;
+        if (!APR_BRIGADE_EMPTY(io->output)) {
+            apr_brigade_length(io->output, 0, &len);
+        }
+        len += io->buflen;
+        flush_now = (len >= WRITE_BUFFER_SIZE);
+    }
+    
+    if (flush_now) {
+        return h2_conn_io_flush(io);
+    }
+    return status;
+}
 
 apr_status_t h2_conn_io_flush(h2_conn_io *io)
 {
     if (io->unflushed) {
         apr_status_t status; 
         if (io->buflen > 0) {
+            /* something in the buffer, put it in the output brigade */
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
                           "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen);
             bucketeer_buffer(io);
             io->buflen = 0;
         }
-        /* Append flush.
-         */
+        
         APR_BRIGADE_INSERT_TAIL(io->output,
                                 apr_bucket_flush_create(io->output->bucket_alloc));
+        /* Send it out */
+        status = pass_out(io->output, io);
         
-        /* Send it out through installed filters (TLS) to the client */
-        status = flush_out(io->output, io);
-        
-        if (status == APR_SUCCESS) {
-            /* These are all fine and no reason for concern. Everything else
-             * is interesting. */
-            io->unflushed = 0;
-        }
-        else {
+        if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
-                          "h2_conn_io: flush error");
+                          "h2_conn_io: flush");
+            return status;
         }
-        
-        return status;
+
+        io->unflushed = 0;
     }
     return APR_SUCCESS;
 }

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_conn_io.h Wed Nov  4 15:44:24 2015
@@ -26,11 +26,16 @@ typedef struct {
     conn_rec *connection;
     apr_bucket_brigade *input;
     apr_bucket_brigade *output;
-    int buffer_output;
+
+    int is_tls;
+    apr_time_t cooldown_usecs;
+    apr_int64_t warmup_size;
+    
     int write_size;
     apr_time_t last_write;
-    apr_size_t bytes_written;
+    apr_int64_t bytes_written;
     
+    int buffer_output;
     char *buffer;
     apr_size_t buflen;
     apr_size_t bufsize;
@@ -38,7 +43,8 @@ typedef struct {
 } h2_conn_io;
 
 apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c);
-void h2_conn_io_destroy(h2_conn_io *io);
+
+int h2_conn_io_is_buffered(h2_conn_io *io);
 
 typedef apr_status_t (*h2_conn_io_on_read_cb)(const char *data, apr_size_t len,
                                          apr_size_t *readlen, int *done,
@@ -52,6 +58,10 @@ apr_status_t h2_conn_io_read(h2_conn_io
 apr_status_t h2_conn_io_write(h2_conn_io *io,
                          const char *buf,
                          size_t length);
+                         
+apr_status_t h2_conn_io_writeb(h2_conn_io *io, apr_bucket *b);
+
+apr_status_t h2_conn_io_consider_flush(h2_conn_io *io);
 
 apr_status_t h2_conn_io_flush(h2_conn_io *io);
 

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.c Wed Nov  4 15:44:24 2015
@@ -32,11 +32,11 @@ static h2_ctx *h2_ctx_create(const conn_
     return ctx;
 }
 
-h2_ctx *h2_ctx_create_for(const conn_rec *c, h2_task_env *env)
+h2_ctx *h2_ctx_create_for(const conn_rec *c, h2_task *task)
 {
     h2_ctx *ctx = h2_ctx_create(c);
     if (ctx) {
-        ctx->task_env = env;
+        ctx->task = task;
     }
     return ctx;
 }
@@ -76,7 +76,7 @@ h2_ctx *h2_ctx_server_set(h2_ctx *ctx, s
 
 int h2_ctx_is_task(h2_ctx *ctx)
 {
-    return ctx && !!ctx->task_env;
+    return ctx && !!ctx->task;
 }
 
 int h2_ctx_is_active(h2_ctx *ctx)
@@ -84,7 +84,7 @@ int h2_ctx_is_active(h2_ctx *ctx)
     return ctx && ctx->is_h2;
 }
 
-struct h2_task_env *h2_ctx_get_task(h2_ctx *ctx)
+struct h2_task *h2_ctx_get_task(h2_ctx *ctx)
 {
-    return ctx->task_env;
+    return ctx->task;
 }

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_ctx.h Wed Nov  4 15:44:24 2015
@@ -16,7 +16,7 @@
 #ifndef __mod_h2__h2_ctx__
 #define __mod_h2__h2_ctx__
 
-struct h2_task_env;
+struct h2_task;
 struct h2_config;
 
 /**
@@ -30,7 +30,7 @@ struct h2_config;
 typedef struct h2_ctx {
     int is_h2;                    /* h2 engine is used */
     const char *protocol;         /* the protocol negotiated */
-    struct h2_task_env *task_env; /* the h2_task environment or NULL */
+    struct h2_task *task;         /* the h2_task executing or NULL */
     const char *hostname;         /* hostname negotiated via SNI, optional */
     server_rec *server;           /* httpd server config selected. */
     struct h2_config *config;     /* effective config in this context */
@@ -38,7 +38,7 @@ typedef struct h2_ctx {
 
 h2_ctx *h2_ctx_get(const conn_rec *c);
 h2_ctx *h2_ctx_rget(const request_rec *r);
-h2_ctx *h2_ctx_create_for(const conn_rec *c, struct h2_task_env *env);
+h2_ctx *h2_ctx_create_for(const conn_rec *c, struct h2_task *task);
 
 
 /* Set the h2 protocol established on this connection context or
@@ -58,6 +58,6 @@ const char *h2_ctx_protocol_get(const co
 int h2_ctx_is_task(h2_ctx *ctx);
 int h2_ctx_is_active(h2_ctx *ctx);
 
-struct h2_task_env *h2_ctx_get_task(h2_ctx *ctx);
+struct h2_task *h2_ctx_get_task(h2_ctx *ctx);
 
 #endif /* defined(__mod_h2__h2_ctx__) */

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_from_h1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_from_h1.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_from_h1.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_from_h1.c Wed Nov  4 15:44:24 2015
@@ -78,9 +78,9 @@ h2_response *h2_from_h1_get_response(h2_
 
 static apr_status_t make_h2_headers(h2_from_h1 *from_h1, request_rec *r)
 {
-    from_h1->response = h2_response_create(from_h1->stream_id, 
-                                       from_h1->status, from_h1->hlines,
-                                       from_h1->pool);
+    from_h1->response = h2_response_create(from_h1->stream_id, 0,
+                                           from_h1->status, from_h1->hlines,
+                                           from_h1->pool);
     if (from_h1->response == NULL) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, r->connection,
                       APLOGNO(02915) 
@@ -492,8 +492,8 @@ static h2_response *create_response(h2_f
 
 apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 {
-    h2_task_env *env = f->ctx;
-    h2_from_h1 *from_h1 = env->output? env->output->from_h1 : NULL;
+    h2_task *task = f->ctx;
+    h2_from_h1 *from_h1 = task->output? task->output->from_h1 : NULL;
     request_rec *r = f->r;
     apr_bucket *b;
     ap_bucket_error *eb = NULL;
@@ -503,7 +503,7 @@ apr_status_t h2_response_output_filter(a
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
                   "h2_from_h1(%d): output_filter called", from_h1->stream_id);
     
-    if (r->header_only && env->output && from_h1->response) {
+    if (r->header_only && task->output && from_h1->response) {
         /* throw away any data after we have compiled the response */
         apr_brigade_cleanup(bb);
         return OK;

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.c Wed Nov  4 15:44:24 2015
@@ -54,6 +54,384 @@ 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(int h2_error)
+{
+    if (h2_error >= 0 
+        && 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;
+    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 +450,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,19 +467,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) 
+{
+    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, "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, "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 1;
+}
+
+int h2_allows_h2_direct(conn_rec *c)
 {
-    if (opt_ssl_engine_disable) {
-        return opt_ssl_engine_disable(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 0;
+    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)
 {
@@ -106,7 +563,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, 
@@ -135,9 +593,6 @@ static int h2_h2_remove_timeout(conn_rec
 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)) {
@@ -145,53 +600,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.
@@ -210,21 +662,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,
                       "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-http2-alpha/modules/http2/h2_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_h2.h Wed Nov  4 15:44:24 2015
@@ -34,6 +34,31 @@ 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
+
+/**
+ * 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(int h2_error);
+
 /*
  * One time, post config intialization.
  */
@@ -43,15 +68,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-http2-alpha/modules/http2/h2_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.c?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.c (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.c Wed Nov  4 15:44:24 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)
@@ -39,7 +40,10 @@ h2_io *h2_io_create(int id, apr_pool_t *
 
 static void h2_io_cleanup(h2_io *io)
 {
-    (void)io;
+    if (io->task) {
+        h2_task_destroy(io->task);
+        io->task = NULL;
+    }
 }
 
 void h2_io_destroy(h2_io *io)
@@ -47,6 +51,17 @@ void h2_io_destroy(h2_io *io)
     h2_io_cleanup(io);
 }
 
+void h2_io_set_response(h2_io *io, h2_response *response) 
+{
+    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)
 {
     io->rst_error = error;
@@ -90,8 +105,7 @@ apr_status_t h2_io_in_read(h2_io *io, ap
     
     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;
@@ -119,7 +133,7 @@ apr_status_t h2_io_in_write(h2_io *io, a
             io->bbin = apr_brigade_create(io->bbout->p, 
                                           io->bbout->bucket_alloc);
         }
-        return h2_util_move(io->bbin, bb, 0, 0, "h2_io_in_write");
+        return h2_util_move(io->bbin, bb, 0, NULL, "h2_io_in_write");
     }
     return APR_SUCCESS;
 }
@@ -168,6 +182,24 @@ apr_status_t h2_io_out_readx(h2_io *io,
     return status;
 }
 
+apr_status_t h2_io_out_read_to(h2_io *io, apr_bucket_brigade *bb, 
+                               apr_size_t *plen, int *peos)
+{
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
+    
+    if (io->eos_out) {
+        *plen = 0;
+        *peos = 1;
+        return APR_SUCCESS;
+    }
+    
+
+    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)
 {

Modified: httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.h?rev=1712570&r1=1712569&r2=1712570&view=diff
==============================================================================
--- httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.h (original)
+++ httpd/httpd/branches/2.4-http2-alpha/modules/http2/h2_io.h Wed Nov  4 15:44:24 2015
@@ -21,8 +21,9 @@ struct apr_thread_cond_t;
 struct h2_task;
 
 
-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_size_t len);
+
+typedef int h2_stream_pri_cmp(int stream_id1, int stream_id2, void *ctx);
 
 
 typedef struct h2_io h2_io;
@@ -34,7 +35,10 @@ struct h2_io {
     int eos_in;
     int task_done;
     int rst_error;
+    int zombie;
     
+    struct h2_task *task;       /* task created for this io */
+
     apr_size_t input_consumed;   /* how many bytes have been read */
     struct apr_thread_cond_t *input_arrived; /* block on reading */
     
@@ -61,6 +65,11 @@ 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);
@@ -114,6 +123,10 @@ apr_status_t h2_io_out_readx(h2_io *io,
                              h2_io_data_cb *cb, void *ctx, 
                              apr_size_t *plen, int *peos);
 
+apr_status_t h2_io_out_read_to(h2_io *io, 
+                               apr_bucket_brigade *bb, 
+                               apr_size_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);