httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ic...@apache.org
Subject svn commit: r1725301 [1/6] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ modules/http2/
Date Mon, 18 Jan 2016 16:22:58 GMT
Author: icing
Date: Mon Jan 18 16:22:57 2016
New Revision: 1725301

URL: http://svn.apache.org/viewvc?rev=1725301&view=rev
Log:
mod_http2 v1.2.2 from trunk

Added:
    httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_filter.h
    httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h
Modified:
    httpd/httpd/branches/2.4.x/CMakeLists.txt
    httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml
    httpd/httpd/branches/2.4.x/modules/http2/config.m4
    httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_config.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_config.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_io.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_io.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_private.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_push.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_push.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_request.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_request.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_response.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_response.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_session.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_session.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_stream.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_task_input.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task_output.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_util.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_util.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_version.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h
    httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c

Modified: httpd/httpd/branches/2.4.x/CMakeLists.txt
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CMakeLists.txt?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CMakeLists.txt (original)
+++ httpd/httpd/branches/2.4.x/CMakeLists.txt Mon Jan 18 16:22:57 2016
@@ -382,16 +382,17 @@ SET(mod_http2_extra_sources
   modules/http2/h2_alt_svc.c         modules/http2/h2_bucket_eoc.c
   modules/http2/h2_bucket_eos.c      modules/http2/h2_config.c
   modules/http2/h2_conn.c            modules/http2/h2_conn_io.c
-  modules/http2/h2_ctx.c             modules/http2/h2_from_h1.c
-  modules/http2/h2_h2.c              modules/http2/h2_io.c
-  modules/http2/h2_io_set.c          modules/http2/h2_mplx.c
-  modules/http2/h2_push.c            modules/http2/h2_request.c
-  modules/http2/h2_response.c        modules/http2/h2_session.c
-  modules/http2/h2_stream.c          modules/http2/h2_stream_set.c
-  modules/http2/h2_switch.c          modules/http2/h2_task.c
-  modules/http2/h2_task_input.c      modules/http2/h2_task_output.c
-  modules/http2/h2_task_queue.c      modules/http2/h2_util.c
-  modules/http2/h2_worker.c          modules/http2/h2_workers.c
+  modules/http2/h2_ctx.c             modules/http2/h2_filter.c
+  modules/http2/h2_from_h1.c         modules/http2/h2_h2.c
+  modules/http2/h2_io.c              modules/http2/h2_io_set.c
+  modules/http2/h2_mplx.c            modules/http2/h2_push.c
+  modules/http2/h2_request.c         modules/http2/h2_response.c
+  modules/http2/h2_session.c         modules/http2/h2_stream.c 
+  modules/http2/h2_stream_set.c      modules/http2/h2_switch.c
+  modules/http2/h2_task.c            modules/http2/h2_task_input.c
+  modules/http2/h2_task_output.c     modules/http2/h2_task_queue.c
+  modules/http2/h2_util.c            modules/http2/h2_worker.c
+  modules/http2/h2_workers.c
 )
 SET(mod_ldap_extra_defines           LDAP_DECLARE_EXPORT)
 SET(mod_ldap_extra_libs              wldap32)

Modified: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml Mon Jan 18 16:22:57 2016
@@ -53,6 +53,26 @@
 
     </summary>
     
+    <section id="envvars"><title>Environment Variables</title>
+        
+        <p>This module can be configured to provide HTTP/2 related information
+            as additional environment variables to the SSI and CGI namespace.
+        </p>
+        
+        <table border="1">
+            <columnspec><column width=".3"/><column width=".2"/><column width=".5"/>
+            </columnspec>
+            <tr>
+                <th><a name="table3">Variable Name:</a></th>
+                <th>Value Type:</th>
+                <th>Description:</th>
+            </tr>
+            <tr><td><code>HTTPe</code></td>                         <td>flag</td>      <td>HTTP/2 is being used.</td></tr>
+            <tr><td><code>H2PUSH</code></td>                        <td>flag</td>      <td>HTTP/2 Server Push is enabled for this request and also supported by the client.</td></tr>
+        </table>
+        
+    </section>
+
     <directivesynopsis>
         <name>H2Direct</name>
         <description>H2 Direct Protocol Switch</description>
@@ -174,6 +194,43 @@
     </directivesynopsis>
 
     <directivesynopsis>
+        <name>H2PushDiarySize</name>
+        <description>H2 Server Push Diary Size</description>
+        <syntax>H2PushDiarySize n</syntax>
+        <default>H2PushDiarySize 256</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.19 and later.</compatibility>
+        
+        <usage>
+            <p>
+                This directive toggles the maximum number of HTTP/2 server pushes 
+                that are remembered per HTTP/2 connection. This can be used inside the
+                <directive module="core" type="section">VirtualHost</directive> 
+                section to influence the number for all connections to that virtual host. 
+            </p>
+            <p>
+                The push diary records a digest (currently using a 64 bit number) of pushed
+                resources (their URL) to avoid duplicate pushes on the same connection.
+                These value are not persisted, so clients openeing a new connection
+                will experience known pushes again. There is ongoing work to enable
+                a client to disclose a digest of the resources it already has, so
+                the diary maybe initialized by the client on each connection setup.
+            </p>
+            <p>
+                If the maximum size is reached, newer entries replace the oldest
+                ones. A diary entry uses 8 bytes, letting a
+                default diary with 256 entries consume around 2 KB of memory.
+            </p>
+            <p>
+                A size of 0 will effectively disable the push diary.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
         <name>H2PushPriority</name>
         <description>H2 Server Push Priority</description>
         <syntax>H2PushPriority mime-type [after|before|interleaved] [weight]</syntax>
@@ -404,7 +461,7 @@ H2PushPriority text/css   interleaved
         <name>H2WindowSize</name>
         <description>Size of Stream Window for upstream data.</description>
         <syntax>H2WindowSize <em>bytes</em></syntax>
-        <default>H2WindowSize 65536</default>
+        <default>H2WindowSize 65535</default>
         <contextlist>
             <context>server config</context>
             <context>virtual host</context>
@@ -498,7 +555,6 @@ H2PushPriority text/css   interleaved
         <name>H2SessionExtraFiles</name>
         <description>Number of Extra File Handles</description>
         <syntax>H2SessionExtraFiles <em>n</em></syntax>
-        <default>H2SessionExtraFiles 5</default>
         <contextlist>
             <context>server config</context>
             <context>virtual host</context>
@@ -528,6 +584,11 @@ H2PushPriority text/css   interleaved
                     H2SessionExtraFiles 10
                 </highlight>
             </example>
+            <p>
+                If nothing is configured, the module tries to make a conservative
+                guess how many files are safe to use. This depends largely on the 
+                MPM chosen.
+            </p>
         </usage>
     </directivesynopsis>
 
@@ -705,4 +766,99 @@ H2PushPriority text/css   interleaved
         </usage>
     </directivesynopsis>
     
+    <directivesynopsis>
+        <name>H2Timeout</name>
+        <description>Timeout (in seconds) for HTTP/2 connections</description>
+        <syntax>H2Timeout seconds</syntax>
+        <default>H2Timeout 5</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+        <usage>
+            <p>
+                This directive sets the timeout for read/write operations on
+                connections where HTTP/2 is negotiated. This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                This directive is similar to the 
+                <directive module="core" type="section">Timeout</directive>, but
+                applies only to HTTP/2 connections.
+            </p>
+            <p>
+                A value of 0 enforces no timeout.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
+        <name>H2KeepAliveTimeout</name>
+        <description>Timeout (in seconds) for idle HTTP/2 connections</description>
+        <syntax>H2KeepAliveTimeout seconds</syntax>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+        <usage>
+            <p>
+                This directive sets the timeout for read/write operations on
+                idle connections where HTTP/2 is negotiated. This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                This directive is similar to the 
+                <directive module="core" type="section">KeepAliveTimeout</directive>, but
+                applies only to HTTP/2 connections. A HTTP/2 connection is considered
+                idle when no streams are open, e.g. no requests are ongoing.
+            </p>
+            <p>
+                By default, for non-async MPMs (prefork, worker) the keepalive timeout
+                will be the same as H2Timeout. For async MPMs, the keepalive handling for
+                HTTP/1 connections applies as no special action is taken.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
+        <name>H2StreamTimeout</name>
+        <description>Timeout (in seconds) for idle HTTP/2 connections</description>
+        <syntax>H2StreamTimeout seconds</syntax>
+        <default>H2StreamTimeout 0</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+        <usage>
+            <p>
+                This directive sets the timeout for read/write operations on
+                HTTP/2 streams, e.g. individual requests. This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                Due to the nature of HTTP/2, which sends multiple requests over a single
+                connection and has priority scheduling, individual streams might not
+                see input for much longer times than HTTP/1.1 requests would. 
+            </p>
+            <p>
+                A value of 0 enforces no timeout, so could wait on chances to receive
+                input or write data indefinitely. This expose a server to
+                risks of thread exhaustion. 
+            </p>
+            <p>
+                Depending on your handling of pushed streams,
+                priorities and general responsiveness, a site might need to increase
+                this value. For example, if you PUSH a large resource <em>before</em>
+                the requested one, the initial stream will not write until the
+                pushed resource is fully sent.
+            </p>
+        </usage>
+    </directivesynopsis>
+
 </modulesynopsis>

Modified: httpd/httpd/branches/2.4.x/modules/http2/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/config.m4?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/config.m4 (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/config.m4 Mon Jan 18 16:22:57 2016
@@ -26,6 +26,7 @@ h2_config.lo dnl
 h2_conn.lo dnl
 h2_conn_io.lo dnl
 h2_ctx.lo dnl
+h2_filter.lo dnl
 h2_from_h1.lo dnl
 h2_h2.lo dnl
 h2_io.lo dnl
@@ -180,6 +181,11 @@ APACHE_MODULE(http2, [HTTP/2 protocol ha
 handling. Implemented by mod_http2. This module requires a libnghttp2 installation. 
 See --with-nghttp2 on how to manage non-standard locations. This module
 is usually linked shared and requires loading. ], $http2_objs, , most, [
+    APACHE_CHECK_OPENSSL
+    if test "$ac_cv_openssl" = "yes" ; then
+        APR_ADDTO(MOD_CPPFLAGS, ["-DH2_OPENSSL"])
+    fi
+
     APACHE_CHECK_NGHTTP2
     if test "$ac_cv_nghttp2" = "yes" ; then
         if test "x$enable_http2" = "xshared"; then
@@ -192,6 +198,9 @@ is usually linked shared and requires lo
     fi
 ])
 
+# Ensure that other modules can pick up mod_http2.h
+APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
+
 dnl #  end of module specific part
 APACHE_MODPATH_FINISH
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c Mon Jan 18 16:22:57 2016
@@ -41,17 +41,18 @@ void h2_alt_svc_register_hooks(void)
  * - do not percent encode token values
  * - do not use quotation marks
  */
-h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) {
+h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool)
+{
     const char *sep = ap_strchr_c(s, '=');
     if (sep) {
-        const char *alpn = apr_pstrndup(pool, s, sep - s);
+        const char *alpn = apr_pstrmemdup(pool, s, sep - s);
         const char *host = NULL;
         int port = 0;
         s = sep + 1;
         sep = ap_strchr_c(s, ':');  /* mandatory : */
         if (sep) {
             if (sep != s) {    /* optional host */
-                host = apr_pstrndup(pool, s, sep - s);
+                host = apr_pstrmemdup(pool, s, sep - s);
             }
             s = sep + 1;
             if (*s) {          /* must be a port number */
@@ -73,7 +74,6 @@ h2_alt_svc *h2_alt_svc_parse(const char
 
 static int h2_alt_svc_handler(request_rec *r)
 {
-    h2_ctx *ctx;
     const h2_config *cfg;
     int i;
     
@@ -82,8 +82,7 @@ static int h2_alt_svc_handler(request_re
         return DECLINED;
     }
     
-    ctx = h2_ctx_rget(r);
-    if (h2_ctx_is_active(ctx) || h2_ctx_is_task(ctx)) {
+    if (h2_ctx_rget(r)) {
         return DECLINED;
     }
     
@@ -122,11 +121,10 @@ static int h2_alt_svc_handler(request_re
                 }
             }
             if (*alt_svc) {
-                apr_table_set(r->headers_out, "Alt-Svc", alt_svc);
+                apr_table_setn(r->headers_out, "Alt-Svc", alt_svc);
             }
         }
     }
     
     return DECLINED;
 }
-

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_config.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_config.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_config.c Mon Jan 18 16:22:57 2016
@@ -59,32 +59,16 @@ static h2_config defconf = {
     1,                      /* TLS cooldown secs */
     1,                      /* HTTP/2 server push enabled */
     NULL,                   /* map of content-type to priorities */
+    -1,                     /* connection timeout */
+    -1,                     /* keepalive timeout */
+    0,                      /* stream timeout */
+    256,                    /* push diary size */
+    
 };
 
-static int files_per_session = 0;
-
-void h2_config_init(apr_pool_t *pool) {
-    /* Determine a good default for this platform and mpm?
-     * TODO: not sure how APR wants to hand out this piece of 
-     * information.
-     */
-    int max_files = 256;
-    int conn_threads = 1;
-    int tx_files = max_files / 4;
-    
+void h2_config_init(apr_pool_t *pool)
+{
     (void)pool;
-    ap_mpm_query(AP_MPMQ_MAX_THREADS, &conn_threads);
-    switch (h2_conn_mpm_type()) {
-        case H2_MPM_PREFORK:
-        case H2_MPM_WORKER:
-        case H2_MPM_EVENT:
-            /* allow that many transfer open files per mplx */
-            files_per_session = (tx_files / conn_threads);
-            break;
-        default:
-            /* don't know anything about it, stay safe */
-            break;
-    }
 }
 
 static void *h2_config_create(apr_pool_t *pool,
@@ -93,11 +77,7 @@ static void *h2_config_create(apr_pool_t
     h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
     
     const char *s = x? x : "unknown";
-    char *name = apr_pcalloc(pool, strlen(prefix) + strlen(s) + 20);
-    strcpy(name, prefix);
-    strcat(name, "[");
-    strcat(name, s);
-    strcat(name, "]");
+    char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL);
     
     conf->name                 = name;
     conf->h2_max_streams       = DEF_VAL;
@@ -116,6 +96,10 @@ static void *h2_config_create(apr_pool_t
     conf->tls_cooldown_secs    = DEF_VAL;
     conf->h2_push              = DEF_VAL;
     conf->priorities           = NULL;
+    conf->h2_timeout           = DEF_VAL;
+    conf->h2_keepalive         = DEF_VAL;
+    conf->h2_stream_timeout    = DEF_VAL;
+    conf->push_diary_size      = DEF_VAL;
     
     return conf;
 }
@@ -136,12 +120,7 @@ void *h2_config_merge(apr_pool_t *pool,
     h2_config *add = (h2_config *)addv;
     h2_config *n = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
 
-    char *name = apr_pcalloc(pool, 20 + strlen(add->name) + strlen(base->name));
-    strcpy(name, "merged[");
-    strcat(name, add->name);
-    strcat(name, ", ");
-    strcat(name, base->name);
-    strcat(name, "]");
+    char *name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
     n->name = name;
 
     n->h2_max_streams       = H2_CONFIG_GET(add, base, h2_max_streams);
@@ -166,6 +145,10 @@ void *h2_config_merge(apr_pool_t *pool,
     else {
         n->priorities       = add->priorities? add->priorities : base->priorities;
     }
+    n->h2_timeout           = H2_CONFIG_GET(add, base, h2_timeout);
+    n->h2_keepalive = H2_CONFIG_GET(add, base, h2_keepalive);
+    n->h2_stream_timeout    = H2_CONFIG_GET(add, base, h2_stream_timeout);
+    n->push_diary_size      = H2_CONFIG_GET(add, base, push_diary_size);
     
     return n;
 }
@@ -177,7 +160,6 @@ int h2_config_geti(const h2_config *conf
 
 apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
 {
-    int n;
     switch(var) {
         case H2_CONF_MAX_STREAMS:
             return H2_CONFIG_GET(conf, &defconf, h2_max_streams);
@@ -202,17 +184,21 @@ apr_int64_t h2_config_geti64(const h2_co
         case H2_CONF_DIRECT:
             return H2_CONFIG_GET(conf, &defconf, h2_direct);
         case H2_CONF_SESSION_FILES:
-            n = H2_CONFIG_GET(conf, &defconf, session_extra_files);
-            if (n < 0) {
-                n = files_per_session;
-            }
-            return n;
+            return H2_CONFIG_GET(conf, &defconf, session_extra_files);
         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);
         case H2_CONF_PUSH:
             return H2_CONFIG_GET(conf, &defconf, h2_push);
+        case H2_CONF_TIMEOUT_SECS:
+            return H2_CONFIG_GET(conf, &defconf, h2_timeout);
+        case H2_CONF_KEEPALIVE_SECS:
+            return H2_CONFIG_GET(conf, &defconf, h2_keepalive);
+        case H2_CONF_STREAM_TIMEOUT_SECS:
+            return H2_CONFIG_GET(conf, &defconf, h2_stream_timeout);
+        case H2_CONF_PUSH_DIARY_SIZE:
+            return H2_CONFIG_GET(conf, &defconf, push_diary_size);
         default:
             return DEF_VAL;
     }
@@ -256,7 +242,7 @@ static const char *h2_conf_set_window_si
     cfg->h2_window_size = (int)apr_atoi64(value);
     (void)arg;
     if (cfg->h2_window_size < 1024) {
-        return "value must be > 1k";
+        return "value must be >= 1024";
     }
     return NULL;
 }
@@ -268,7 +254,7 @@ static const char *h2_conf_set_min_worke
     cfg->min_workers = (int)apr_atoi64(value);
     (void)arg;
     if (cfg->min_workers < 1) {
-        return "value must be > 1";
+        return "value must be > 0";
     }
     return NULL;
 }
@@ -280,7 +266,7 @@ static const char *h2_conf_set_max_worke
     cfg->max_workers = (int)apr_atoi64(value);
     (void)arg;
     if (cfg->max_workers < 1) {
-        return "value must be > 1";
+        return "value must be > 0";
     }
     return NULL;
 }
@@ -292,7 +278,7 @@ static const char *h2_conf_set_max_worke
     cfg->max_worker_idle_secs = (int)apr_atoi64(value);
     (void)arg;
     if (cfg->max_worker_idle_secs < 1) {
-        return "value must be > 1";
+        return "value must be > 0";
     }
     return NULL;
 }
@@ -306,7 +292,7 @@ static const char *h2_conf_set_stream_ma
     cfg->stream_max_mem_size = (int)apr_atoi64(value);
     (void)arg;
     if (cfg->stream_max_mem_size < 1024) {
-        return "value must be > 1k";
+        return "value must be >= 1024";
     }
     return NULL;
 }
@@ -510,6 +496,59 @@ static const char *h2_conf_set_tls_coold
     return NULL;
 }
 
+static const char *h2_conf_set_timeout(cmd_parms *parms,
+                                       void *arg, const char *value)
+{
+    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+    (void)arg;
+    cfg->h2_timeout = (int)apr_atoi64(value);
+    if (cfg->h2_timeout < 0) {
+        return "value must be >= 0";
+    }
+    return NULL;
+}
+
+static const char *h2_conf_set_keepalive(cmd_parms *parms,
+                                                 void *arg, const char *value)
+{
+    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+    (void)arg;
+    cfg->h2_keepalive = (int)apr_atoi64(value);
+    if (cfg->h2_keepalive < 0) {
+        return "value must be >= 0";
+    }
+    return NULL;
+}
+
+static const char *h2_conf_set_stream_timeout(cmd_parms *parms,
+                                              void *arg, const char *value)
+{
+    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+    (void)arg;
+    cfg->h2_stream_timeout = (int)apr_atoi64(value);
+    if (cfg->h2_stream_timeout < 0) {
+        return "value must be >= 0";
+    }
+    return NULL;
+}
+
+static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
+                                               void *arg, const char *value)
+{
+    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+    (void)arg;
+    cfg->push_diary_size = (int)apr_atoi64(value);
+    if (cfg->push_diary_size < 0) {
+        return "value must be >= 0";
+    }
+    if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) {
+        return "value must a power of 2";
+    }
+    if (cfg->push_diary_size > (1 << 15)) {
+        return "value must <= 65536";
+    }
+    return NULL;
+}
 
 #define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
 
@@ -548,6 +587,14 @@ const command_rec h2_cmds[] = {
                   RSRC_CONF, "off to disable HTTP/2 server push"),
     AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
                   RSRC_CONF, "define priority of PUSHed resources per content type"),
+    AP_INIT_TAKE1("H2Timeout", h2_conf_set_timeout, NULL,
+                  RSRC_CONF, "read/write timeout (seconds) for HTTP/2 connections"),
+    AP_INIT_TAKE1("H2KeepAliveTimeout", h2_conf_set_keepalive, NULL,
+                  RSRC_CONF, "timeout (seconds) for idle HTTP/2 connections, no streams open"),
+    AP_INIT_TAKE1("H2StreamTimeout", h2_conf_set_stream_timeout, NULL,
+                  RSRC_CONF, "read/write timeout (seconds) for HTTP/2 streams"),
+    AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
+                  RSRC_CONF, "size of push diary"),
     AP_END_CMD
 };
 
@@ -561,16 +608,17 @@ const h2_config *h2_config_rget(request_
 
 const h2_config *h2_config_get(conn_rec *c)
 {
-    h2_ctx *ctx = h2_ctx_get(c);
+    h2_ctx *ctx = h2_ctx_get(c, 0);
     
-    if (ctx->config) {
-        return ctx->config;
-    }
-    else if (ctx->server) {
-        ctx->config = h2_config_sget(ctx->server);
-        return ctx->config;
+    if (ctx) {
+        if (ctx->config) {
+            return ctx->config;
+        }
+        else if (ctx->server) {
+            ctx->config = h2_config_sget(ctx->server);
+            return ctx->config;
+        }
     }
     
     return h2_config_sget(c->base_server);
 }
-

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_config.h?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_config.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_config.h Mon Jan 18 16:22:57 2016
@@ -39,6 +39,10 @@ typedef enum {
     H2_CONF_TLS_WARMUP_SIZE,
     H2_CONF_TLS_COOLDOWN_SECS,
     H2_CONF_PUSH,
+    H2_CONF_TIMEOUT_SECS,
+    H2_CONF_KEEPALIVE_SECS,
+    H2_CONF_STREAM_TIMEOUT_SECS,
+    H2_CONF_PUSH_DIARY_SIZE,
 } h2_config_var_t;
 
 struct apr_hash_t;
@@ -65,6 +69,11 @@ typedef struct h2_config {
     int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
     int h2_push;                  /* if HTTP/2 server push is enabled */
     struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
+    
+    int h2_timeout;               /* timeout for http/2 connections */
+    int h2_keepalive;             /* timeout for idle connections, no streams */
+    int h2_stream_timeout;        /* timeout for http/2 streams, slave connections */
+    int push_diary_size;          /* # of entries in push diary */
 } h2_config;
 
 
@@ -87,6 +96,6 @@ void h2_config_init(apr_pool_t *pool);
 
 const struct h2_priority *h2_config_get_priority(const h2_config *conf, 
                                                  const char *content_type);
-                                                 
+       
 #endif /* __mod_h2__h2_config_h__ */
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c Mon Jan 18 16:22:57 2016
@@ -28,6 +28,7 @@
 #include "h2_private.h"
 #include "h2_config.h"
 #include "h2_ctx.h"
+#include "h2_filter.h"
 #include "h2_mplx.h"
 #include "h2_session.h"
 #include "h2_stream.h"
@@ -37,30 +38,37 @@
 #include "h2_worker.h"
 #include "h2_workers.h"
 #include "h2_conn.h"
+#include "h2_version.h"
 
 static struct h2_workers *workers;
 
 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
 static module *mpm_module;
-static int checked;
+static int async_mpm;
 
-static void check_modules(void) 
+static void check_modules(int force) 
 {
+    static int checked = 0;
     int i;
-    if (!checked) {
+
+    if (force || !checked) {
         for (i = 0; ap_loaded_modules[i]; ++i) {
             module *m = ap_loaded_modules[i];
+            
             if (!strcmp("event.c", m->name)) {
                 mpm_type = H2_MPM_EVENT;
                 mpm_module = m;
+                break;
             }
             else if (!strcmp("worker.c", m->name)) {
                 mpm_type = H2_MPM_WORKER;
                 mpm_module = m;
+                break;
             }
             else if (!strcmp("prefork.c", m->name)) {
                 mpm_type = H2_MPM_PREFORK;
                 mpm_module = m;
+                break;
             }
         }
         checked = 1;
@@ -71,72 +79,80 @@ apr_status_t h2_conn_child_init(apr_pool
 {
     const h2_config *config = h2_config_sget(s);
     apr_status_t status = APR_SUCCESS;
-    int minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
-    int maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);
-    
+    int minw, maxw, max_tx_handles, n;
     int max_threads_per_child = 0;
-    int threads_limit = 0;
     int idle_secs = 0;
-    int i;
 
-    h2_config_init(pool);
+    check_modules(1);
     
     ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads_per_child);
-    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &threads_limit);
     
-    for (i = 0; ap_loaded_modules[i]; ++i) {
-        module *m = ap_loaded_modules[i];
-        if (!strcmp("event.c", m->name)) {
-            mpm_type = H2_MPM_EVENT;
-            mpm_module = m;
-        }
-        else if (!strcmp("worker.c", m->name)) {
-            mpm_type = H2_MPM_WORKER;
-            mpm_module = m;
-        }
-        else if (!strcmp("prefork.c", m->name)) {
-            mpm_type = H2_MPM_PREFORK;
-            mpm_module = m;
-        }
+    status = ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm);
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_TRACE1, status, s, "querying MPM for async");
+        /* some MPMs do not implemnent this */
+        async_mpm = 0;
+        status = APR_SUCCESS;
     }
+
+    h2_config_init(pool);
     
+    minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
+    maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);    
     if (minw <= 0) {
         minw = max_threads_per_child;
     }
     if (maxw <= 0) {
-        maxw = threads_limit;
-        if (maxw < minw) {
-            maxw = minw;
-        }
+        maxw = minw;
+    }
+    
+    /* How many file handles is it safe to use for transfer
+     * to the master connection to be streamed out? 
+     * Is there a portable APR rlimit on NOFILES? Have not
+     * found it. And if, how many of those would we set aside?
+     * This leads all into a process wide handle allocation strategy
+     * which ultimately would limit the number of accepted connections
+     * with the assumption of implicitly reserving n handles for every 
+     * connection and requiring modules with excessive needs to allocate
+     * from a central pool.
+     */
+    n = h2_config_geti(config, H2_CONF_SESSION_FILES);
+    if (n < 0) {
+        max_tx_handles = maxw * 2;
+    }
+    else {
+        max_tx_handles = maxw * n;
     }
     
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                 "h2_workers: min=%d max=%d, mthrpchild=%d, thr_limit=%d", 
-                 minw, maxw, max_threads_per_child, threads_limit);
+    ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
+                 "h2_workers: min=%d max=%d, mthrpchild=%d, tx_files=%d", 
+                 minw, maxw, max_threads_per_child, max_tx_handles);
+    workers = h2_workers_create(s, pool, minw, maxw, max_tx_handles);
     
-    workers = h2_workers_create(s, pool, minw, maxw);
     idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
     h2_workers_set_max_idle_secs(workers, idle_secs);
-    
+ 
+    ap_register_input_filter("H2_IN", h2_filter_core_input,
+                             NULL, AP_FTYPE_CONNECTION);
+   
     return status;
 }
 
-h2_mpm_type_t h2_conn_mpm_type(void) {
-    check_modules();
+h2_mpm_type_t h2_conn_mpm_type(void)
+{
+    check_modules(0);
     return mpm_type;
 }
 
-static module *h2_conn_mpm_module(void) {
-    check_modules();
+static module *h2_conn_mpm_module(void)
+{
+    check_modules(0);
     return mpm_module;
 }
 
-apr_status_t h2_conn_process(conn_rec *c, request_rec *r, server_rec *s)
+apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
 {
-    apr_status_t status;
     h2_session *session;
-    const h2_config *config;
-    int rv;
     
     if (!workers) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911) 
@@ -144,109 +160,100 @@ apr_status_t h2_conn_process(conn_rec *c
         return APR_EGENERAL;
     }
     
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_process start");
-    
-    if (!s && r) {
-        s = r->server;
-    }
-    
-    config = s? h2_config_sget(s) : h2_config_get(c);
     if (r) {
-        session = h2_session_rcreate(r, config, workers);
+        session = h2_session_rcreate(r, ctx, workers);
     }
     else {
-        session = h2_session_create(c, config, workers);
+        session = h2_session_create(c, ctx, workers);
     }
-    
-    if (!h2_is_acceptable_connection(c, 1)) {
-        nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE, 0,
-                              NGHTTP2_INADEQUATE_SECURITY, NULL, 0);
-    } 
 
-    ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
-    status = h2_session_start(session, &rv);
+    h2_ctx_session_set(ctx, session);
+    return APR_SUCCESS;
+}
+
+apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
+{
+    apr_status_t status;
+    int mpm_state = 0;
     
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
-                  "h2_session(%ld): starting on %s:%d", session->id,
-                  session->c->base_server->server_hostname,
-                  session->c->local_addr->port);
-    if (status != APR_SUCCESS) {
-        h2_session_abort(session, status, rv);
-        h2_session_eoc_callback(session);
-        return status;
-    }
+    do {
+        if (c->cs) {
+            c->cs->sense = CONN_SENSE_DEFAULT;
+        }
+        status = h2_session_process(h2_ctx_session_get(ctx), async_mpm);
+        
+        if (c->cs) {
+            c->cs->state = CONN_STATE_WRITE_COMPLETION;
+        }
+        if (APR_STATUS_IS_EOF(status)) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
+                          "h2_session(%ld): process, closing conn", c->id);
+            c->keepalive = AP_CONN_CLOSE;
+        }
+        else {
+            c->keepalive = AP_CONN_KEEPALIVE;
+        }
+        
+        if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
+            break;
+        }
+    } while (!async_mpm
+             && c->keepalive == AP_CONN_KEEPALIVE 
+             && mpm_state != AP_MPMQ_STOPPING);
     
-    status = h2_session_process(session);
-
-    ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
-                  "h2_session(%ld): done", session->id);
-    /* Make sure this connection gets closed properly. */
-    ap_update_child_status_from_conn(c->sbh, SERVER_CLOSING, c);
-    c->keepalive = AP_CONN_CLOSE;
-    if (c->cs) {
-        c->cs->state = CONN_STATE_WRITE_COMPLETION;
-    }
-
-    h2_session_close(session);
-    /* hereafter session will be gone */
-    return status;
+    return DONE;
 }
 
 
 static void fix_event_conn(conn_rec *c, conn_rec *master);
 
-conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
+conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *p, 
+                          apr_thread_t *thread, apr_socket_t *socket)
 {
     conn_rec *c;
     
     AP_DEBUG_ASSERT(master);
-
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, master,
+                  "h2_conn(%ld): created from master", master->id);
+    
     /* This is like the slave connection creation from 2.5-DEV. A
      * very efficient way - not sure how compatible this is, since
      * the core hooks are no longer run.
      * But maybe it's is better this way, not sure yet.
      */
-    c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
+    c = (conn_rec *) apr_palloc(p, sizeof(conn_rec));
     if (c == NULL) {
-        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool, 
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master, 
                       APLOGNO(02913) "h2_task: creating conn");
         return NULL;
     }
     
     memcpy(c, master, sizeof(conn_rec));
-    c->id = (master->id & (long)pool);
-    c->master = master;
-    c->input_filters = NULL;
-    c->output_filters = NULL;
-    c->pool = pool;        
-    return c;
-}
-
-apr_status_t h2_conn_setup(h2_task *task, apr_bucket_alloc_t *bucket_alloc,
-                           apr_thread_t *thread, apr_socket_t *socket)
-{
-    conn_rec *master = task->mplx->c;
+           
+    /* Replace these */
+    c->id                     = (master->id & (long)p);
+    c->master                 = master;
+    c->pool                   = p;        
+    c->current_thread         = thread;
+    c->conn_config            = ap_create_conn_config(p);
+    c->notes                  = apr_table_make(p, 5);
+    c->input_filters          = NULL;
+    c->output_filters         = NULL;
+    c->bucket_alloc           = apr_bucket_alloc_create(p);
+    c->cs                     = NULL;
+    c->data_in_input_filters  = 0;
+    c->data_in_output_filters = 0;
+    c->clogging_input_filters = 1;
+    c->log                    = NULL;
+    c->log_id                 = NULL;
     
-    ap_log_perror(APLOG_MARK, APLOG_TRACE3, 0, task->pool,
-                  "h2_conn(%ld): created from master", master->id);
+    /* TODO: these should be unique to this thread */
+    c->sbh                    = master->sbh;
     
-    /* Ok, we are just about to start processing the connection and
-     * the worker is calling us to setup all necessary resources.
-     * We can borrow some from the worker itself and some we do as
-     * sub-resources from it, so that we get a nice reuse of
-     * pools.
-     */
-    task->c->pool = task->pool;
-    task->c->current_thread = thread;
-    task->c->bucket_alloc = bucket_alloc;
+    /* Simulate that we had already a request on this connection. */
+    c->keepalives             = 1;
     
-    task->c->conn_config = ap_create_conn_config(task->pool);
-    task->c->notes = apr_table_make(task->pool, 5);
-    
-    /* In order to do this in 2.4.x, we need to add a member to conn_rec */
-    task->c->master = master;
-    
-    ap_set_module_config(task->c->conn_config, &core_module, socket);
+    ap_set_module_config(c->conn_config, &core_module, socket);
     
     /* This works for mpm_worker so far. Other mpm modules have 
      * different needs, unfortunately. The most interesting one 
@@ -257,21 +264,14 @@ apr_status_t h2_conn_setup(h2_task *task
             /* all fine */
             break;
         case H2_MPM_EVENT: 
-            fix_event_conn(task->c, master);
+            fix_event_conn(c, master);
             break;
         default:
             /* fingers crossed */
             break;
     }
     
-    /* TODO: we simulate that we had already a request on this connection.
-     * This keeps the mod_ssl SNI vs. Host name matcher from answering 
-     * 400 Bad Request
-     * when names do not match. We prefer a predictable 421 status.
-     */
-    task->c->keepalives = 1;
-    
-    return APR_SUCCESS;
+    return c;
 }
 
 /* This is an internal mpm event.c struct which is disguised

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h Mon Jan 18 16:22:57 2016
@@ -16,18 +16,27 @@
 #ifndef __mod_h2__h2_conn__
 #define __mod_h2__h2_conn__
 
+struct h2_ctx;
 struct h2_task;
 
 /**
- * Process the connection that is now starting the HTTP/2
- * conversation. Return when the HTTP/2 session is done
- * and the connection will close.
+ * Setup the connection and our context for HTTP/2 processing
  *
+ * @param ctx the http2 context to setup
  * @param c the connection HTTP/2 is starting on
  * @param r the upgrade request that still awaits an answer, optional
- * @param s the server selected by request or, if NULL, connection
  */
-apr_status_t h2_conn_process(conn_rec *c, request_rec *r, server_rec *s);
+apr_status_t h2_conn_setup(struct h2_ctx *ctx, conn_rec *c, request_rec *r);
+
+/**
+ * Run the HTTP/2 connection in synchronous fashion. 
+ * Return when the HTTP/2 session is done
+ * and the connection will close or a fatal error occured.
+ *
+ * @param ctx the http2 context to run
+ * @return APR_SUCCESS when session is done.
+ */
+apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c);
 
 /* Initialize this child process for h2 connection work,
  * to be called once during child init before multi processing
@@ -47,9 +56,7 @@ typedef enum {
 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 *task, apr_bucket_alloc_t *bucket_alloc,
-                           apr_thread_t *thread, apr_socket_t *socket);
+conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *p, 
+                          apr_thread_t *thread, apr_socket_t *socket);
 
 #endif /* defined(__mod_h2__h2_conn__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c Mon Jan 18 16:22:57 2016
@@ -27,6 +27,7 @@
 #include "h2_config.h"
 #include "h2_conn_io.h"
 #include "h2_h2.h"
+#include "h2_session.h"
 #include "h2_util.h"
 
 #define TLS_DATA_MAX          (16*1024) 
@@ -50,7 +51,6 @@ apr_status_t h2_conn_io_init(h2_conn_io
                              apr_pool_t *pool)
 {
     io->connection         = c;
-    io->input              = apr_brigade_create(pool, c->bucket_alloc);
     io->output             = apr_brigade_create(pool, c->bucket_alloc);
     io->buflen             = 0;
     io->is_tls             = h2_h2_is_tls(c);
@@ -79,7 +79,7 @@ apr_status_t h2_conn_io_init(h2_conn_io
     }
 
     if (APLOGctrace1(c)) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 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));
@@ -93,116 +93,15 @@ int h2_conn_io_is_buffered(h2_conn_io *i
     return io->bufsize > 0;
 }
 
-static apr_status_t h2_conn_io_bucket_read(h2_conn_io *io,
-                                           apr_read_type_e block,
-                                           h2_conn_io_on_read_cb on_read_cb,
-                                           void *puser, int *pdone)
-{
-    apr_status_t status = APR_SUCCESS;
-    apr_size_t readlen = 0;
-    *pdone = 0;
-    
-    while (status == APR_SUCCESS && !*pdone
-           && !APR_BRIGADE_EMPTY(io->input)) {
-        
-        apr_bucket* bucket = APR_BRIGADE_FIRST(io->input);
-        if (APR_BUCKET_IS_METADATA(bucket)) {
-            /* we do nothing regarding any meta here */
-        }
-        else {
-            const char *bucket_data = NULL;
-            apr_size_t bucket_length = 0;
-            status = apr_bucket_read(bucket, &bucket_data,
-                                     &bucket_length, block);
-            
-            if (status == APR_SUCCESS && bucket_length > 0) {
-                apr_size_t consumed = 0;
-
-                if (APLOGctrace2(io->connection)) {
-                    char buffer[32];
-                    h2_util_hex_dump(buffer, sizeof(buffer)/sizeof(buffer[0]),
-                                     bucket_data, bucket_length);
-                    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
-                                  "h2_conn_io(%ld): read %d bytes: %s",
-                                  io->connection->id, (int)bucket_length, buffer);
-                }
-                
-                status = on_read_cb(bucket_data, bucket_length, &consumed, 
-                                    pdone, puser);
-                if (status == APR_SUCCESS && bucket_length > consumed) {
-                    /* We have data left in the bucket. Split it. */
-                    status = apr_bucket_split(bucket, consumed);
-                }
-                readlen += consumed;
-            }
-        }
-        apr_bucket_delete(bucket);
-    }
-    
-    if (readlen == 0 && status == APR_SUCCESS && block == APR_NONBLOCK_READ) {
-        return APR_EAGAIN;
-    }
-    return status;
-}
-
-apr_status_t h2_conn_io_read(h2_conn_io *io,
-                             apr_read_type_e block,
-                             h2_conn_io_on_read_cb on_read_cb,
-                             void *puser)
-{
-    apr_status_t status;
-    int done = 0;
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
-                  "h2_conn_io: try read, block=%d", block);
-    
-    if (!APR_BRIGADE_EMPTY(io->input)) {
-        /* Seems something is left from a previous read, lets
-         * satisfy our caller with the data we already have. */
-        status = h2_conn_io_bucket_read(io, block, on_read_cb, puser, &done);
-        apr_brigade_cleanup(io->input);
-        if (status != APR_SUCCESS || done) {
-            return status;
-        }
-    }
-
-    /* We only do a blocking read when we have no streams to process. So,
-     * in httpd scoreboard lingo, we are in a KEEPALIVE connection state.
-     * When reading non-blocking, we do have streams to process and update
-     * child with NULL request. That way, any current request information
-     * in the scoreboard is preserved.
-     */
-    if (block == APR_BLOCK_READ) {
-        ap_update_child_status_from_conn(io->connection->sbh, 
-                                         SERVER_BUSY_KEEPALIVE, 
-                                         io->connection);
-    }
-    else {
-        ap_update_child_status(io->connection->sbh, SERVER_BUSY_READ, NULL);
-    }
-
-    /* TODO: replace this with a connection filter itself, so that we
-     * no longer need to transfer incoming buckets to our own brigade. 
-     */
-    status = ap_get_brigade(io->connection->input_filters,
-                            io->input, AP_MODE_READBYTES,
-                            block, 64 * 4096);
-    switch (status) {
-        case APR_SUCCESS:
-            return h2_conn_io_bucket_read(io, block, on_read_cb, puser, &done);
-        case APR_EOF:
-        case APR_EAGAIN:
-            break;
-        default:
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
-                          "h2_conn_io: error reading");
-            break;
-    }
-    return status;
-}
+typedef struct {
+    conn_rec *c;
+    h2_conn_io *io;
+} pass_out_ctx;
 
 static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) 
 {
-    h2_conn_io *io = (h2_conn_io*)ctx;
+    pass_out_ctx *pctx = ctx;
+    conn_rec *c = pctx->c;
     apr_status_t status;
     apr_off_t bblen;
     
@@ -210,26 +109,27 @@ static apr_status_t pass_out(apr_bucket_
         return APR_SUCCESS;
     }
     
-    ap_update_child_status(io->connection->sbh, SERVER_BUSY_WRITE, NULL);
+    ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, NULL);
     status = apr_brigade_length(bb, 0, &bblen);
     if (status == APR_SUCCESS) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
                       "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;
-            io->last_write = apr_time_now();
+                      c->id, (long)bblen);
+        status = ap_pass_brigade(c->output_filters, bb);
+        if (status == APR_SUCCESS && pctx->io) {
+            pctx->io->bytes_written += (apr_size_t)bblen;
+            pctx->io->last_write = apr_time_now();
         }
-        apr_brigade_cleanup(bb);
     }
+    apr_brigade_cleanup(bb);
     return status;
 }
 
 /* Bring the current buffer content into the output brigade, appropriately
  * chunked.
  */
-static apr_status_t bucketeer_buffer(h2_conn_io *io) {
+static apr_status_t bucketeer_buffer(h2_conn_io *io)
+{
     const char *data = io->buffer;
     apr_size_t remaining = io->buflen;
     apr_bucket *b;
@@ -241,7 +141,7 @@ static apr_status_t bucketeer_buffer(h2_
         /* long time not written, reset write size */
         io->write_size = WRITE_SIZE_INITIAL;
         io->bytes_written = 0;
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
                       "h2_conn_io(%ld): timeout write size reset to %ld", 
                       (long)io->connection->id, (long)io->write_size);
     }
@@ -249,7 +149,7 @@ static apr_status_t bucketeer_buffer(h2_
              && 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,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
                       "h2_conn_io(%ld): threshold reached, write size now %ld", 
                       (long)io->connection->id, (long)io->write_size);
     }
@@ -275,10 +175,13 @@ apr_status_t h2_conn_io_write(h2_conn_io
                               const char *buf, size_t length)
 {
     apr_status_t status = APR_SUCCESS;
+    pass_out_ctx ctx;
     
+    ctx.c = io->connection;
+    ctx.io = io;
     io->unflushed = 1;
     if (io->bufsize > 0) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
                       "h2_conn_io: buffering %ld bytes", (long)length);
                       
         if (!APR_BRIGADE_EMPTY(io->output)) {
@@ -289,8 +192,9 @@ apr_status_t h2_conn_io_write(h2_conn_io
         while (length > 0 && (status == APR_SUCCESS)) {
             apr_size_t avail = io->bufsize - io->buflen;
             if (avail <= 0) {
+                
                 bucketeer_buffer(io);
-                status = pass_out(io->output, io);
+                status = pass_out(io->output, &ctx);
                 io->buflen = 0;
             }
             else if (length > avail) {
@@ -309,9 +213,9 @@ apr_status_t h2_conn_io_write(h2_conn_io
         
     }
     else {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->connection,
                       "h2_conn_io: writing %ld bytes to brigade", (long)length);
-        status = apr_brigade_write(io->output, pass_out, io, buf, length);
+        status = apr_brigade_write(io->output, pass_out, &ctx, buf, length);
     }
     
     return status;
@@ -348,12 +252,14 @@ apr_status_t h2_conn_io_consider_flush(h
     return status;
 }
 
-static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force)
+static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force, int eoc)
 {
     if (io->unflushed || force) {
+        pass_out_ctx ctx;
+        
         if (io->buflen > 0) {
             /* something in the buffer, put it in the output brigade */
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
                           "h2_conn_io: flush, flushing %ld bytes", (long)io->buflen);
             bucketeer_buffer(io);
             io->buflen = 0;
@@ -364,38 +270,33 @@ static apr_status_t h2_conn_io_flush_int
                                     apr_bucket_flush_create(io->output->bucket_alloc));
         }
         
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
                       "h2_conn_io: flush");
         /* Send it out */
         io->unflushed = 0;
-        return pass_out(io->output, io);
+        
+        ctx.c = io->connection;
+        ctx.io = eoc? NULL : io;
+        return pass_out(io->output, &ctx);
         /* no more access after this, as we might have flushed an EOC bucket
          * that de-allocated us all. */
     }
     return APR_SUCCESS;
 }
 
-apr_status_t h2_conn_io_flush(h2_conn_io *io)
+apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, apr_bucket *b)
 {
-    return h2_conn_io_flush_int(io, 1);
+    APR_BRIGADE_INSERT_TAIL(io->output, b);
+    return h2_conn_io_flush_int(io, 1, 1);
 }
 
-apr_status_t h2_conn_io_pass(h2_conn_io *io)
+apr_status_t h2_conn_io_flush(h2_conn_io *io)
 {
-    return h2_conn_io_flush_int(io, 0);
+    return h2_conn_io_flush_int(io, 1, 0);
 }
 
-apr_status_t h2_conn_io_close(h2_conn_io *io, void *session)
+apr_status_t h2_conn_io_pass(h2_conn_io *io)
 {
-    apr_bucket *b;
+    return h2_conn_io_flush_int(io, 0, 0);
+}
 
-    /* Send out anything in our buffers */
-    h2_conn_io_flush_int(io, 0);
-    
-    b = h2_bucket_eoc_create(io->connection->bucket_alloc, session);
-    APR_BRIGADE_INSERT_TAIL(io->output, b);
-    b = apr_bucket_flush_create(io->connection->bucket_alloc);
-    APR_BRIGADE_INSERT_TAIL(io->output, b);
-    return ap_pass_brigade(io->connection->output_filters, io->output);
-    /* and all is gone */
-}
\ No newline at end of file

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h Mon Jan 18 16:22:57 2016
@@ -17,6 +17,7 @@
 #define __mod_h2__h2_conn_io__
 
 struct h2_config;
+struct h2_session;
 
 /* h2_io is the basic handler of a httpd connection. It keeps two brigades,
  * one for input, one for output and works with the installed connection
@@ -26,7 +27,6 @@ struct h2_config;
  */
 typedef struct {
     conn_rec *connection;
-    apr_bucket_brigade *input;
     apr_bucket_brigade *output;
 
     int is_tls;
@@ -35,6 +35,7 @@ typedef struct {
     
     apr_size_t write_size;
     apr_time_t last_write;
+    apr_int64_t bytes_read;
     apr_int64_t bytes_written;
     
     int buffer_output;
@@ -50,15 +51,6 @@ apr_status_t h2_conn_io_init(h2_conn_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,
-                                         void *puser);
-
-apr_status_t h2_conn_io_read(h2_conn_io *io,
-                        apr_read_type_e block,
-                        h2_conn_io_on_read_cb on_read_cb,
-                        void *puser);
-
 apr_status_t h2_conn_io_write(h2_conn_io *io,
                          const char *buf,
                          size_t length);
@@ -69,6 +61,6 @@ apr_status_t h2_conn_io_consider_flush(h
 
 apr_status_t h2_conn_io_pass(h2_conn_io *io);
 apr_status_t h2_conn_io_flush(h2_conn_io *io);
-apr_status_t h2_conn_io_close(h2_conn_io *io, void *session);
+apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, apr_bucket *b);
 
 #endif /* defined(__mod_h2__h2_conn_io__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c Mon Jan 18 16:22:57 2016
@@ -20,6 +20,7 @@
 #include <http_config.h>
 
 #include "h2_private.h"
+#include "h2_session.h"
 #include "h2_task.h"
 #include "h2_ctx.h"
 #include "h2_private.h"
@@ -29,9 +30,16 @@ static h2_ctx *h2_ctx_create(const conn_
     h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
     AP_DEBUG_ASSERT(ctx);
     ap_set_module_config(c->conn_config, &http2_module, ctx);
+    h2_ctx_server_set(ctx, c->base_server);
     return ctx;
 }
 
+void h2_ctx_clear(const conn_rec *c)
+{
+    AP_DEBUG_ASSERT(c);
+    ap_set_module_config(c->conn_config, &http2_module, NULL);
+}
+
 h2_ctx *h2_ctx_create_for(const conn_rec *c, h2_task *task)
 {
     h2_ctx *ctx = h2_ctx_create(c);
@@ -41,10 +49,10 @@ h2_ctx *h2_ctx_create_for(const conn_rec
     return ctx;
 }
 
-h2_ctx *h2_ctx_get(const conn_rec *c)
+h2_ctx *h2_ctx_get(const conn_rec *c, int create)
 {
     h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &http2_module);
-    if (ctx == NULL) {
+    if (ctx == NULL && create) {
         ctx = h2_ctx_create(c);
     }
     return ctx;
@@ -52,7 +60,7 @@ h2_ctx *h2_ctx_get(const conn_rec *c)
 
 h2_ctx *h2_ctx_rget(const request_rec *r)
 {
-    return h2_ctx_get(r->connection);
+    return h2_ctx_get(r->connection, 0);
 }
 
 const char *h2_ctx_protocol_get(const conn_rec *c)
@@ -64,10 +72,24 @@ const char *h2_ctx_protocol_get(const co
 h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto)
 {
     ctx->protocol = proto;
-    ctx->is_h2 = (proto != NULL);
     return ctx;
 }
 
+h2_session *h2_ctx_session_get(h2_ctx *ctx)
+{
+    return ctx? ctx->session : NULL;
+}
+
+void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session)
+{
+    ctx->session = session;
+}
+
+server_rec *h2_ctx_server_get(h2_ctx *ctx)
+{
+    return ctx? ctx->server : NULL;
+}
+
 h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s)
 {
     ctx->server = s;
@@ -76,15 +98,10 @@ h2_ctx *h2_ctx_server_set(h2_ctx *ctx, s
 
 int h2_ctx_is_task(h2_ctx *ctx)
 {
-    return ctx && !!ctx->task;
-}
-
-int h2_ctx_is_active(h2_ctx *ctx)
-{
-    return ctx && ctx->is_h2;
+    return ctx && ctx->task;
 }
 
 struct h2_task *h2_ctx_get_task(h2_ctx *ctx)
 {
-    return ctx->task;
+    return ctx? ctx->task : NULL;
 }

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h Mon Jan 18 16:22:57 2016
@@ -16,6 +16,7 @@
 #ifndef __mod_h2__h2_ctx__
 #define __mod_h2__h2_ctx__
 
+struct h2_session;
 struct h2_task;
 struct h2_config;
 
@@ -28,15 +29,23 @@ struct h2_config;
  * - those created by ourself to perform work on HTTP/2 streams
  */
 typedef struct h2_ctx {
-    int is_h2;                      /* h2 engine is used */
     const char *protocol;           /* the protocol negotiated */
+    struct h2_session *session;     /* the session established */
     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. */
     const struct h2_config *config; /* effective config in this context */
 } h2_ctx;
 
-h2_ctx *h2_ctx_get(const conn_rec *c);
+/**
+ * Get (or create) a h2 context record for this connection.
+ * @param c the connection to look at
+ * @param create != 0 iff missing context shall be created
+ * @return h2 context of this connection
+ */
+h2_ctx *h2_ctx_get(const conn_rec *c, int create);
+void h2_ctx_clear(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 *task);
 
@@ -49,6 +58,10 @@ h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx,
 /* Set the server_rec relevant for this context.
  */
 h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s);
+server_rec *h2_ctx_server_get(h2_ctx *ctx);
+
+struct h2_session *h2_ctx_session_get(h2_ctx *ctx);
+void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session);
 
 /**
  * Get the h2 protocol negotiated for this connection, or NULL.
@@ -56,7 +69,6 @@ h2_ctx *h2_ctx_server_set(h2_ctx *ctx, s
 const char *h2_ctx_protocol_get(const conn_rec *c);
 
 int h2_ctx_is_task(h2_ctx *ctx);
-int h2_ctx_is_active(h2_ctx *ctx);
 
 struct h2_task *h2_ctx_get_task(h2_ctx *ctx);
 

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c?rev=1725301&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c Mon Jan 18 16:22:57 2016
@@ -0,0 +1,313 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_log.h>
+#include <http_connection.h>
+#include <scoreboard.h>
+
+#include "h2_private.h"
+#include "h2_conn_io.h"
+#include "h2_ctx.h"
+#include "h2_mplx.h"
+#include "h2_push.h"
+#include "h2_task.h"
+#include "h2_stream.h"
+#include "h2_stream_set.h"
+#include "h2_request.h"
+#include "h2_response.h"
+#include "h2_session.h"
+#include "h2_util.h"
+#include "h2_version.h"
+
+#include "h2_filter.h"
+
+#define UNSET       -1
+#define H2MIN(x,y) ((x) < (y) ? (x) : (y))
+
+static apr_status_t consume_brigade(h2_filter_cin *cin, 
+                                    apr_bucket_brigade *bb, 
+                                    apr_read_type_e block)
+{
+    apr_status_t status = APR_SUCCESS;
+    apr_size_t readlen = 0;
+    
+    while (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
+        
+        apr_bucket* bucket = APR_BRIGADE_FIRST(bb);
+        if (APR_BUCKET_IS_METADATA(bucket)) {
+            /* we do nothing regarding any meta here */
+        }
+        else {
+            const char *bucket_data = NULL;
+            apr_size_t bucket_length = 0;
+            status = apr_bucket_read(bucket, &bucket_data,
+                                     &bucket_length, block);
+            
+            if (status == APR_SUCCESS && bucket_length > 0) {
+                apr_size_t consumed = 0;
+
+                status = cin->cb(cin->cb_ctx, bucket_data, bucket_length, &consumed);
+                if (status == APR_SUCCESS && bucket_length > consumed) {
+                    /* We have data left in the bucket. Split it. */
+                    status = apr_bucket_split(bucket, consumed);
+                }
+                readlen += consumed;
+                cin->start_read = apr_time_now();
+            }
+        }
+        apr_bucket_delete(bucket);
+    }
+    
+    if (readlen == 0 && status == APR_SUCCESS && block == APR_NONBLOCK_READ) {
+        return APR_EAGAIN;
+    }
+    return status;
+}
+
+h2_filter_cin *h2_filter_cin_create(apr_pool_t *p, h2_filter_cin_cb *cb, void *ctx)
+{
+    h2_filter_cin *cin;
+    
+    cin = apr_pcalloc(p, sizeof(*cin));
+    cin->pool      = p;
+    cin->cb        = cb;
+    cin->cb_ctx    = ctx;
+    cin->start_read = UNSET;
+    return cin;
+}
+
+void h2_filter_cin_timeout_set(h2_filter_cin *cin, int timeout_secs)
+{
+    cin->timeout_secs = timeout_secs;
+}
+
+apr_status_t h2_filter_core_input(ap_filter_t* f,
+                                  apr_bucket_brigade* brigade,
+                                  ap_input_mode_t mode,
+                                  apr_read_type_e block,
+                                  apr_off_t readbytes) 
+{
+    h2_filter_cin *cin = f->ctx;
+    apr_status_t status = APR_SUCCESS;
+    apr_time_t saved_timeout = UNSET;
+    
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
+                  "core_input(%ld): read, %s, mode=%d, readbytes=%ld, timeout=%d", 
+                  (long)f->c->id, (block == APR_BLOCK_READ)? "BLOCK_READ" : "NONBLOCK_READ", 
+                  mode, (long)readbytes, cin->timeout_secs);
+    
+    if (mode == AP_MODE_INIT || mode == AP_MODE_SPECULATIVE) {
+        return ap_get_brigade(f->next, brigade, mode, block, readbytes);
+    }
+    
+    if (mode != AP_MODE_READBYTES) {
+        return (block == APR_BLOCK_READ)? APR_SUCCESS : APR_EAGAIN;
+    }
+    
+    if (!cin->bb) {
+        cin->bb = apr_brigade_create(cin->pool, f->c->bucket_alloc);
+    }
+
+    if (!cin->socket) {
+        cin->socket = ap_get_conn_socket(f->c);
+    }
+    
+    cin->start_read = apr_time_now();
+    if (APR_BRIGADE_EMPTY(cin->bb)) {
+        /* We only do a blocking read when we have no streams to process. So,
+         * in httpd scoreboard lingo, we are in a KEEPALIVE connection state.
+         * When reading non-blocking, we do have streams to process and update
+         * child with NULL request. That way, any current request information
+         * in the scoreboard is preserved.
+         */
+        if (block == APR_BLOCK_READ) {
+            if (cin->timeout_secs > 0) {
+                apr_time_t t = apr_time_from_sec(cin->timeout_secs);
+                apr_socket_timeout_get(cin->socket, &saved_timeout);
+                apr_socket_timeout_set(cin->socket, t);
+            }
+        }
+        status = ap_get_brigade(f->next, cin->bb, AP_MODE_READBYTES,
+                                block, readbytes);
+        if (saved_timeout != UNSET) {
+            apr_socket_timeout_set(cin->socket, saved_timeout);
+        }
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
+                      "core_input(%ld): got_brigade", (long)f->c->id);
+    }
+    
+    switch (status) {
+        case APR_SUCCESS:
+            status = consume_brigade(cin, cin->bb, block);
+            break;
+        case APR_EOF:
+        case APR_EAGAIN:
+        case APR_TIMEUP:
+            break;
+        default:
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, f->c,
+                          "h2_conn_io: error reading");
+            break;
+    }
+    return status;
+}
+
+/*******************************************************************************
+ * http2 connection status handler + stream out source
+ ******************************************************************************/
+
+static const char *H2_SOS_H2_STATUS = "http2-status";
+
+int h2_filter_h2_status_handler(request_rec *r)
+{
+    h2_ctx *ctx = h2_ctx_rget(r);
+    h2_task *task;
+    
+    if (strcmp(r->handler, "http2-status")) {
+        return DECLINED;
+    }
+    if (r->method_number != M_GET) {
+        return DECLINED;
+    }
+
+    task = ctx? h2_ctx_get_task(ctx) : NULL;
+    if (task) {
+        /* We need to handle the actual output on the main thread, as
+         * we need to access h2_session information. */
+        apr_table_setn(r->notes, H2_RESP_SOS_NOTE, H2_SOS_H2_STATUS);
+        apr_table_setn(r->headers_out, "Content-Type", "application/json");
+        r->status = 200;
+        return DONE;
+    }
+    return DECLINED;
+}
+
+#define bbout(...)   apr_brigade_printf(bb, NULL, NULL, __VA_ARGS__)
+static apr_status_t h2_sos_h2_status_buffer(h2_sos *sos, apr_bucket_brigade *bb)
+{
+    h2_stream *stream = sos->stream;
+    h2_session *session = stream->session;
+    h2_mplx *mplx = session->mplx;
+    h2_push_diary *diary;
+    apr_status_t status;
+    
+    if (!bb) {
+        bb = apr_brigade_create(stream->pool, session->c->bucket_alloc);
+    }
+    
+    bbout("{\n");
+    bbout("  \"HTTP2\": \"on\",\n");
+    bbout("  \"H2PUSH\": \"%s\",\n", h2_session_push_enabled(session)? "on" : "off");
+    bbout("  \"mod_http2_version\": \"%s\",\n", MOD_HTTP2_VERSION);
+    bbout("  \"session_id\": %ld,\n", (long)session->id);
+    bbout("  \"streams_max\": %d,\n", (int)session->max_stream_count);
+    bbout("  \"this_stream\": %d,\n", stream->id);
+    bbout("  \"streams_open\": %d,\n", (int)h2_stream_set_size(session->streams));
+    bbout("  \"max_stream_started\": %d,\n", mplx->max_stream_started);
+    bbout("  \"requests_received\": %d,\n", session->requests_received);
+    bbout("  \"responses_submitted\": %d,\n", session->responses_submitted);
+    bbout("  \"streams_reset\": %d, \n", session->streams_reset);
+    bbout("  \"pushes_promised\": %d,\n", session->pushes_promised);
+    bbout("  \"pushes_submitted\": %d,\n", session->pushes_submitted);
+    bbout("  \"pushes_reset\": %d,\n", session->pushes_reset);
+    
+    diary = session->push_diary;
+    if (diary) {
+        const char *data;
+        const char *base64_digest;
+        apr_size_t len;
+        
+        status = h2_push_diary_digest_get(diary, stream->pool, 256, 
+                                          stream->request->authority, &data, &len);
+        if (status == APR_SUCCESS) {
+            base64_digest = h2_util_base64url_encode(data, len, stream->pool);
+            bbout("  \"cache_digest\": \"%s\",\n", base64_digest);
+        }
+        
+        /* try the reverse for testing purposes */
+        status = h2_push_diary_digest_set(diary, stream->request->authority, data, len);
+        if (status == APR_SUCCESS) {
+            status = h2_push_diary_digest_get(diary, stream->pool, 256, 
+                                              stream->request->authority, &data, &len);
+            if (status == APR_SUCCESS) {
+                base64_digest = h2_util_base64url_encode(data, len, stream->pool);
+                bbout("  \"cache_digest^2\": \"%s\",\n", base64_digest);
+            }
+        }
+    }
+    bbout("  \"frames_received\": %ld,\n", (long)session->frames_received);
+    bbout("  \"frames_sent\": %ld,\n", (long)session->frames_sent);
+    bbout("  \"bytes_received\": %"APR_UINT64_T_FMT",\n", session->io.bytes_read);
+    bbout("  \"bytes_sent\": %"APR_UINT64_T_FMT"\n", session->io.bytes_written);
+    bbout("}\n");
+    
+    return sos->prev->buffer(sos->prev, bb);
+}
+
+static apr_status_t h2_sos_h2_status_read_to(h2_sos *sos, apr_bucket_brigade *bb, 
+                                             apr_off_t *plen, int *peos)
+{
+    return sos->prev->read_to(sos->prev, bb, plen, peos);
+}
+
+static apr_status_t h2_sos_h2_status_prep_read(h2_sos *sos, apr_off_t *plen, int *peos)
+{
+    return sos->prev->prep_read(sos->prev, plen, peos);
+}
+
+static apr_status_t h2_sos_h2_status_readx(h2_sos *sos, h2_io_data_cb *cb, void *ctx,
+                                           apr_off_t *plen, int *peos)
+{
+    return sos->prev->readx(sos->prev, cb, ctx, plen, peos);
+}
+
+static apr_table_t *h2_sos_h2_status_get_trailers(h2_sos *sos)
+{
+    return sos->prev->get_trailers(sos->prev);
+}
+
+static h2_sos *h2_sos_h2_status_create(h2_sos *prev) 
+{
+    h2_sos *sos;
+    h2_response *response = prev->response;
+    
+    apr_table_unset(response->headers, "Content-Length");
+    response->content_length = -1;
+
+    sos = apr_pcalloc(prev->stream->pool, sizeof(*sos));
+    sos->prev         = prev;
+    sos->response     = response;
+    sos->stream       = prev->stream;
+    sos->buffer       = h2_sos_h2_status_buffer;
+    sos->prep_read    = h2_sos_h2_status_prep_read;
+    sos->readx        = h2_sos_h2_status_readx;
+    sos->read_to      = h2_sos_h2_status_read_to;
+    sos->get_trailers = h2_sos_h2_status_get_trailers;
+    
+    return sos;
+}
+
+h2_sos *h2_filter_sos_create(const char *name, struct h2_sos *prev)
+{
+    if (!strcmp(H2_SOS_H2_STATUS, name)) {
+        return h2_sos_h2_status_create(prev);
+    }
+    return prev;
+}
+

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_filter.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_filter.h?rev=1725301&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_filter.h (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_filter.h Mon Jan 18 16:22:57 2016
@@ -0,0 +1,77 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __mod_h2__h2_filter__
+#define __mod_h2__h2_filter__
+
+struct h2_stream;
+struct h2_session;
+
+typedef apr_status_t h2_filter_cin_cb(void *ctx, 
+                                      const char *data, apr_size_t len,
+                                      apr_size_t *readlen);
+
+typedef struct h2_filter_cin {
+    apr_pool_t *pool;
+    apr_bucket_brigade *bb;
+    h2_filter_cin_cb *cb;
+    void *cb_ctx;
+    apr_socket_t *socket;
+    int timeout_secs;
+    apr_time_t start_read;
+} h2_filter_cin;
+
+h2_filter_cin *h2_filter_cin_create(apr_pool_t *p, h2_filter_cin_cb *cb, void *ctx);
+
+void h2_filter_cin_timeout_set(h2_filter_cin *cin, int timeout_secs);
+
+apr_status_t h2_filter_core_input(ap_filter_t* filter,
+                                  apr_bucket_brigade* brigade,
+                                  ap_input_mode_t mode,
+                                  apr_read_type_e block,
+                                  apr_off_t readbytes);
+
+typedef struct h2_sos h2_sos;
+typedef apr_status_t h2_sos_data_cb(void *ctx, const char *data, apr_off_t len);
+
+typedef apr_status_t h2_sos_buffer(h2_sos *sos, apr_bucket_brigade *bb);
+typedef apr_status_t h2_sos_prep_read(h2_sos *sos, apr_off_t *plen, int *peos);
+typedef apr_status_t h2_sos_readx(h2_sos *sos, h2_sos_data_cb *cb, 
+                                  void *ctx, apr_off_t *plen, int *peos);
+typedef apr_status_t h2_sos_read_to(h2_sos *sos, apr_bucket_brigade *bb, 
+                                    apr_off_t *plen, int *peos);
+typedef apr_table_t *h2_sos_get_trailers(h2_sos *sos);
+
+
+#define H2_RESP_SOS_NOTE     "h2-sos-filter"
+
+struct h2_sos {
+    struct h2_stream *stream;
+    h2_sos           *prev;
+    struct h2_response *response;
+    void             *ctx;
+    h2_sos_buffer    *buffer;
+    h2_sos_prep_read *prep_read;
+    h2_sos_readx     *readx;
+    h2_sos_read_to   *read_to;
+    h2_sos_get_trailers *get_trailers;
+};
+
+h2_sos *h2_filter_sos_create(const char *name, struct h2_sos *prev); 
+
+int h2_filter_h2_status_handler(request_rec *r);
+
+
+#endif /* __mod_h2__h2_filter__ */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c?rev=1725301&r1=1725300&r2=1725301&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c Mon Jan 18 16:22:57 2016
@@ -70,7 +70,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, 0,
-                                           from_h1->http_status, from_h1->hlines,
+                                           from_h1->http_status, 
+                                           from_h1->hlines,
+                                           r->notes,
                                            from_h1->pool);
     from_h1->content_length = from_h1->response->content_length;
     from_h1->chunked = r->chunked;
@@ -258,7 +260,7 @@ static int uniq_field_values(void *d, co
          */
         for (i = 0, strpp = (char **) values->elts; i < values->nelts;
              ++i, ++strpp) {
-            if (*strpp && strcasecmp(*strpp, start) == 0) {
+            if (*strpp && apr_strnatcasecmp(*strpp, start) == 0) {
                 break;
             }
         }
@@ -408,7 +410,7 @@ static h2_response *create_response(h2_f
         
         while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) {
             for (i = 0; i < r->content_languages->nelts; ++i) {
-                if (!strcasecmp(token, languages[i]))
+                if (!apr_strnatcasecmp(token, languages[i]))
                     break;
             }
             if (i == r->content_languages->nelts) {
@@ -507,7 +509,7 @@ apr_status_t h2_response_output_filter(a
          */
         if (AP_BUCKET_IS_EOC(b)) {
             ap_remove_output_filter(f);
-            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
                           "h2_from_h1(%d): eoc bucket passed", 
                           from_h1->stream_id);
             return ap_pass_brigade(f->next, bb);
@@ -526,7 +528,7 @@ apr_status_t h2_response_output_filter(a
     
     from_h1->response = create_response(from_h1, r);
     if (from_h1->response == NULL) {
-        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
+        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, f->c,
                       "h2_from_h1(%d): unable to create response", 
                       from_h1->stream_id);
         return APR_ENOMEM;



Mime
View raw message