You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2015/11/20 16:13:11 UTC

svn commit: r1715371 [1/6] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ modules/http2/

Author: icing
Date: Fri Nov 20 15:13:11 2015
New Revision: 1715371

URL: http://svn.apache.org/viewvc?rev=1715371&view=rev
Log:
update of mod_http2 with current trunk version

Added:
    httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_push.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_push.h
Removed:
    httpd/httpd/branches/2.4.x/modules/http2/h2_to_h1.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_to_h1.h
Modified:
    httpd/httpd/branches/2.4.x/CHANGES
    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_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_from_h1.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h
    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_io_set.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_io_set.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_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_stream_set.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_stream_set.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_input.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_task_output.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.dsp

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Fri Nov 20 15:13:11 2015
@@ -2,6 +2,47 @@
 
 Changes with Apache 2.4.18
 
+  *) mod_http2: incoming trailers (headers after request body) are properly
+     forwarded to the processing engine. [Stefan Eissing]
+
+  *) mod_http2: new directive 'H2Push' to en-/disable HTTP/2 server
+     pushes a server/virtual host. Pushes are initiated by the presence
+     of 'Link:' headers with relation 'preload' on a response. [Stefan Eissing]
+     
+  *) mod_http2: write performance of http2 improved for larger resources,
+     especially static files. [Stefan Eissing]
+     
+  *) core: if the first HTTP/1.1 request on a connection goes to a server that
+     prefers different protocols, these protocols are announced in a Upgrade:
+     header on the response, mentioning the preferred protocols.
+     [Stefan Eissing]
+     
+  *) mod_http2: new directives 'H2TLSWarmUpSize' and 'H2TLSCoolDownSecs'
+     to control TLS record sizes during connection lifetime.
+     [Stefan Eissing]
+     
+  *) mod_http2: new directive 'H2ModernTLSOnly' to enforce security
+     requirements of RFC 7540 on TLS connections. [Stefan Eissing]
+     
+  *) core: add ap_get_protocol_upgrades() to retrieve the list of protocols
+     that a client could possibly upgrade to. Use in first request on a 
+     connection to announce protocol choices. [Stefan Eissing]
+
+  *) mod_http2: reworked deallocation on connection shutdown and worker
+     abort. Separate parent pool for all workers. worker threads are joined
+     on planned worker shutdown. [Yann Ylavic, Stefan Eissing]
+     
+  *) mod_ssl: when receiving requests for other virtual hosts than the handshake
+     server, the SSL parameters are checked for equality. With equal 
+     configuration, requests are passed for processing. Any change will trigger
+     the old behaviour of "421 Misdirected Request".
+     SSL now remembers the cipher suite that was used for the last handshake.
+     This is compared against for any vhost/directory cipher specification. 
+     Detailed examination of renegotiation is only done when these do not
+     match.
+     Renegotiation is 403ed when a master connection is present. Exact reason
+     is given additionally in a request note. [Stefan Eissing]
+
   *) core: Fix scoreboard crash (SIGBUS) on hardware requiring strict 64bit
      alignment (SPARC64, PPC64).  [Yann Ylavic]
 

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -42,13 +42,22 @@
           release relative to other standard modules. Users are encouraged to 
           consult the "CHANGES" file for potential updates.</p>
         </note>
+
+        <p>You must enable HTTP/2 via <directive
+        module="core">Protocols</directive> in order to use the
+        functionality described in this document:</p>
+
+        <highlight language="config">
+            Protocols h2 http/1.1
+        </highlight>
+
     </summary>
     
     <directivesynopsis>
         <name>H2Direct</name>
         <description>H2 Direct Protocol Switch</description>
         <syntax>H2Direct on|off</syntax>
-        <default>H2Direct on (for non TLS)</default>
+        <default>H2Direct on for h2c, off for h2 protocol</default>
         <contextlist>
             <context>server config</context>
             <context>virtual host</context>
@@ -60,12 +69,31 @@
                 should be used inside a 
                 <directive module="core" type="section">VirtualHost</directive> 
                 section to enable direct HTTP/2 communication for that virtual host. 
+            </p>
+            <p>
                 Direct communication means that if the first bytes received by the 
                 server on a connection match the HTTP/2 preamble, the HTTP/2
                 protocol is switched to immediately without further negotiation.
-                This mode falls outside the RFC 7540 but has become widely implemented
-                as it is very convenient for development and testing. 
-                By default the direct HTTP/2 mode is enabled.
+                This mode is defined in RFC 7540 for the cleartext (h2c) case. Its
+                use on TLS connections not mandated by the standard.
+            </p>
+            <p>
+                When a server/vhost does not have h2 or h2c enabled via
+                <directive module="core" type="section">Protocols</directive>,
+                the connection is never inspected for a HTTP/2 preamble. H2Direct
+                does not matter then. This is important for connections that
+                use protocols where an initial read might hang indefinitely, such
+                as NNTP.
+            </p>
+            <p>
+                For clients that have out-of-band knowledge about a server
+                supporting h2c, direct HTTP/2 saves the client from having to
+                perform an HTTP/1.1 upgrade, resulting in better performance
+                and avoiding the Upgrade restrictions on request bodies.
+            </p>
+            <p>
+                This makes direct h2c attractive for server to server communication
+                as well, when the connection can be trusted or is secured by other means.
             </p>
             <example><title>Example</title>
                 <highlight language="config">
@@ -74,6 +102,122 @@
             </example>
         </usage>
     </directivesynopsis>
+
+    <directivesynopsis>
+        <name>H2Push</name>
+        <description>H2 Server Push Switch</description>
+        <syntax>H2Push on|off</syntax>
+        <default>H2Push on</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive toggles the usage of the HTTP/2 server push 
+                protocol feature. This should be used inside a 
+                <directive module="core" type="section">VirtualHost</directive> 
+                section to enable direct HTTP/2 communication for that virtual host. 
+            </p>
+            <p>
+                The HTTP/2 protocol allows the server to push other resources to
+                a client when it asked for a particular one. This is helpful
+                if those resources are connected in some way and the client can
+                be expected to ask for it anyway. The pushing then saves the
+                time it takes the client to ask for the resources itself. On the
+                other hand, pushing resources the client never needs or already
+                has is a waste of bandwidth.
+            </p>
+            <p>
+                Server pushes are detected by inspecting the <code>Link</code> headers of
+                responses (see https://tools.ietf.org/html/rfc5988 for the 
+                specification). When a link thus specified has the <code>rel=preload</code>
+                attribute, it is treated as a resource to be pushed.
+            </p>
+            <p> 
+                Link headers in responses are either set by the application or
+                can be configured via <module>mod_headers</module> as:
+            </p>
+            <example><title>mod_headers example</title>
+                <highlight language="config">
+&lt;Location /index.html&gt;
+    Header add Link "&lt;/css/site.css&gt;;rel=preload"
+    Header add Link "&lt;/images/logo.jpg&gt;;rel=preload"
+&lt;/Location&gt;
+                </highlight>
+            </example>
+            <p>
+                As the example shows, there can be several link headers added
+                to a response, resulting in several pushes being triggered. There
+                are no checks in the module to avoid pushing the same resource
+                twice or more to one client. Use with care.
+            </p>
+            <p> 
+                HTTP/2 server pushes are enabled by default. This directive 
+                allows it to be switch off on all resources of this server/virtual
+                host.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2Push off
+                </highlight>
+            </example>
+            <p>
+                Last but not least, pushes happen only when the client signals
+                its willingness to accept those. Most browsers do, some, like Safari 9,
+                do not.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
+        <name>H2Upgrade</name>
+        <description>H2 Upgrade Protocol Switch</description>
+        <syntax>H2Upgrade on|off</syntax>
+        <default>H2Upgrade on for h2c, off for h2 protocol</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive toggles the usage of the HTTP/1.1 Upgrade method 
+                for switching to HTTP/2. This
+                should be used inside a 
+                <directive module="core" type="section">VirtualHost</directive> 
+                section to enable Upgrades to HTTP/2 for that virtual host. 
+            </p>
+            <p>
+                This method of switching protocols is defined in HTTP/1.1 and
+                uses the "Upgrade" header (thus the name) to announce willingness
+                to use another protocol. This may happen on any request of a
+                HTTP/1.1 connection.
+            </p>
+            <p>
+                This method of protocol switching is enabled by default on cleartext
+                (potential h2c) connections and disabled on TLS (potential h2), 
+                as mandated by RFC 7540. 
+            </p>
+            <p>
+                Please be aware that Upgrades are only accepted for requests
+                that carry no body. POSTs and PUTs with content will never
+                trigger an upgrade to HTTP/2. 
+                See <directive type="section">H2Direct</directive> for an 
+                alternative to Upgrade.
+            </p>
+            <p>
+                This mode only has an effect when h2 or h2c is enabled via
+                the <directive module="core" type="section">Protocols</directive>.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2Upgrade on
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
     
     <directivesynopsis>
         <name>H2MaxSessionStreams</name>
@@ -230,7 +374,7 @@
             <p>
                 This directive sets maximum number of <em>extra</em> file handles
                 a HTTP/2 session is allowed to use. A file handle is counted as
-                <em>extra</em> when it is transfered from a h2 worker thread to
+                <em>extra</em> when it is transferred from a h2 worker thread to
                 the main HTTP/2 connection handling. This commonly happens when
                 serving static files.
             </p><p>
@@ -282,4 +426,147 @@
         </usage>
     </directivesynopsis>
 
+    <directivesynopsis>
+        <name>H2ModernTLSOnly</name>
+        <description>Require HTTP/2 connections to be "modern TLS" only</description>
+        <syntax>H2ModernTLSOnly on|off</syntax>
+        <default>H2ModernTLSOnly on</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive toggles the security checks on HTTP/2 connections
+                in TLS mode (https:). This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                The security checks require that the TSL protocol is at least
+                TLSv1.2 and that none of the ciphers listed in RFC 7540, Appendix A
+                is used. These checks will be extended once new security requirements
+                come into place.
+            </p>
+            <p>
+                The name stems from the 
+                <a href="https://wiki.mozilla.org/Security/Server_Side_TLS">Security/Server Side TLS</a>
+                definitions at mozilla where "modern compatibility" is defined. Mozilla Firefox and
+                other browsers require modern compatibility for HTTP/2 connections. As everything
+                in OpSec, this is a moving target and can be expected to evolve in the future.
+            </p>
+            <p>
+                One purpose of having these checks in mod_http2 is to enforce this
+                security level for all connections, not only those from browsers. The other
+                purpose is to prevent the negotiation of HTTP/2 as a protocol should
+                the requirements not be met.
+            </p>
+            <p>
+                Ultimately, the security of the TLS connection is determined by the
+                server configuration directives for mod_ssl.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2ModernTLSOnly off
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
+        <name>H2TLSWarmUpSize</name>
+        <description></description>
+        <syntax>H2TLSWarmUpSize amount</syntax>
+        <default>H2TLSWarmUpSize 1048576</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive sets the number of bytes to be sent in small
+                TLS records (~1300 bytes) until doing maximum sized writes (16k)
+                on https: HTTP/2 connections.
+                This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                Measurements by <a href="https://www.igvita.com">google performance
+                labs</a> show that best performance on TLS connections is reached,
+                if initial record sizes stay below the MTU level, to allow a
+                complete record to fit into an IP packet.
+            </p>
+            <p>
+                While TCP adjust its flow-control and window sizes, longer TLS
+                records can get stuck in queues or get lost and need retransmission.
+                This is of course true for all packets. TLS however needs the 
+                whole record in order to decrypt it. Any missing bytes at the end
+                will stall usage of the received ones.
+            </p>
+            <p>
+                After a sufficient number of bytes have been send successfully,
+                the TCP state of the connection is stable and maximum TLS record
+                sizes (16 KB) can be used for optimal performance.
+            </p>
+            <p>
+                In deployments where servers are reached locally or over reliable
+                connections only, the value might be decreased with 0 disabling
+                any warmup phase altogether.
+            </p>
+            <p>
+                The following example sets the size to zero, effectively disabling
+                any warmup phase.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2TLSWarmUpSize 0
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+    
+    <directivesynopsis>
+        <name>H2TLSCoolDownSecs</name>
+        <description></description>
+        <syntax>H2TLSCoolDownSecs seconds</syntax>
+        <default>H2TLSCoolDownSecs 1</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive sets the number of seconds of idle time on a TLS
+                connection before the TLS write size falls back to small (~1300 bytes)
+                length.
+                This can be used server wide or for specific
+                <directive module="core" type="section">VirtualHost</directive>s. 
+            </p>
+            <p>
+                See <directive type="section">H2TLSWarmUpSize</directive> for a
+                description of TLS warmup. H2TLSCoolDownSecs reflects the fact
+                that connections may deteriorate over time (and TCP flow adjusts)
+                for idle connections as well. It is beneficial to overall performance
+                to fall back to the pre-warmup phase after a number of seconds that
+                no data has been sent. 
+            </p>
+            <p>
+                In deployments where connections can be considered reliable, this
+                timer can be disabled by setting it to 0. 
+            </p>
+            <p>
+                The following example sets the seconds to zero, effectively disabling
+                any cool down. Warmed up TLS connections stay on maximum record
+                size.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2TLSCoolDownSecs 0
+                </highlight>
+            </example>
+        </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=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/config.m4 (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/config.m4 Fri Nov 20 15:13:11 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
@@ -29,6 +31,7 @@ h2_h2.lo dnl
 h2_io.lo dnl
 h2_io_set.lo dnl
 h2_mplx.lo dnl
+h2_push.lo dnl
 h2_request.lo dnl
 h2_response.lo dnl
 h2_session.lo dnl
@@ -39,7 +42,6 @@ h2_task.lo dnl
 h2_task_input.lo dnl
 h2_task_output.lo dnl
 h2_task_queue.lo dnl
-h2_to_h1.lo dnl
 h2_util.lo dnl
 h2_worker.lo dnl
 h2_workers.lo dnl

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.c?rev=1715371&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.c (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.c Fri Nov 20 15:13:11 2015
@@ -0,0 +1,108 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 <stddef.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_connection.h>
+#include <http_log.h>
+
+#include "h2_private.h"
+#include "h2_mplx.h"
+#include "h2_session.h"
+#include "h2_bucket_eoc.h"
+
+typedef struct {
+    apr_bucket_refcount refcount;
+    h2_session *session;
+} h2_bucket_eoc;
+
+static apr_status_t bucket_cleanup(void *data)
+{
+    h2_session **psession = data;
+
+    if (*psession) {
+        /*
+         * If bucket_destroy is called after us, this prevents
+         * bucket_destroy from trying to destroy the pool again.
+         */
+        *psession = NULL;
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t bucket_read(apr_bucket *b, const char **str,
+                                apr_size_t *len, apr_read_type_e block)
+{
+    (void)b;
+    (void)block;
+    *str = NULL;
+    *len = 0;
+    return APR_SUCCESS;
+}
+
+apr_bucket * h2_bucket_eoc_make(apr_bucket *b, h2_session *session)
+{
+    h2_bucket_eoc *h;
+
+    h = apr_bucket_alloc(sizeof(*h), b->list);
+    h->session = session;
+
+    b = apr_bucket_shared_make(b, h, 0, 0);
+    b->type = &h2_bucket_type_eoc;
+    
+    return b;
+}
+
+apr_bucket * h2_bucket_eoc_create(apr_bucket_alloc_t *list, h2_session *session)
+{
+    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+    APR_BUCKET_INIT(b);
+    b->free = apr_bucket_free;
+    b->list = list;
+    b = h2_bucket_eoc_make(b, session);
+    if (session) {
+        h2_bucket_eoc *h = b->data;
+        apr_pool_pre_cleanup_register(session->pool, &h->session, bucket_cleanup);
+    }
+    return b;
+}
+
+static void bucket_destroy(void *data)
+{
+    h2_bucket_eoc *h = data;
+
+    if (apr_bucket_shared_destroy(h)) {
+        h2_session *session = h->session;
+        if (session) {
+            h2_session_eoc_callback(session);
+        }
+        apr_bucket_free(h);
+    }
+}
+
+const apr_bucket_type_t h2_bucket_type_eoc = {
+    "H2EOC", 5, APR_BUCKET_METADATA,
+    bucket_destroy,
+    bucket_read,
+    apr_bucket_setaside_noop,
+    apr_bucket_split_notimpl,
+    apr_bucket_shared_copy
+};
+

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.h?rev=1715371&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.h (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eoc.h Fri Nov 20 15:13:11 2015
@@ -0,0 +1,31 @@
+/* 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_http2_h2_bucket_eoc_h
+#define mod_http2_h2_bucket_eoc_h
+
+struct h2_session;
+
+/** End Of HTTP/2 SESSION (H2EOC) bucket */
+extern const apr_bucket_type_t h2_bucket_type_eoc;
+
+
+apr_bucket * h2_bucket_eoc_make(apr_bucket *b, 
+                                struct h2_session *session);
+
+apr_bucket * h2_bucket_eoc_create(apr_bucket_alloc_t *list,
+                                  struct h2_session *session);
+
+#endif /* mod_http2_h2_bucket_eoc_h */

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.c?rev=1715371&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.c (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.c Fri Nov 20 15:13:11 2015
@@ -0,0 +1,109 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 <stddef.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_connection.h>
+#include <http_log.h>
+
+#include "h2_private.h"
+#include "h2_mplx.h"
+#include "h2_stream.h"
+#include "h2_bucket_eos.h"
+
+typedef struct {
+    apr_bucket_refcount refcount;
+    h2_stream *stream;
+} h2_bucket_eos;
+
+static apr_status_t bucket_cleanup(void *data)
+{
+    h2_stream **pstream = data;
+
+    if (*pstream) {
+        /*
+         * If bucket_destroy is called after us, this prevents
+         * bucket_destroy from trying to destroy the pool again.
+         */
+        *pstream = NULL;
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t bucket_read(apr_bucket *b, const char **str,
+                                apr_size_t *len, apr_read_type_e block)
+{
+    (void)b;
+    (void)block;
+    *str = NULL;
+    *len = 0;
+    return APR_SUCCESS;
+}
+
+apr_bucket *h2_bucket_eos_make(apr_bucket *b, h2_stream *stream)
+{
+    h2_bucket_eos *h;
+
+    h = apr_bucket_alloc(sizeof(*h), b->list);
+    h->stream = stream;
+
+    b = apr_bucket_shared_make(b, h, 0, 0);
+    b->type = &h2_bucket_type_eos;
+    
+    return b;
+}
+
+apr_bucket *h2_bucket_eos_create(apr_bucket_alloc_t *list,
+                                 h2_stream *stream)
+{
+    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+    APR_BUCKET_INIT(b);
+    b->free = apr_bucket_free;
+    b->list = list;
+    b = h2_bucket_eos_make(b, stream);
+    if (stream) {
+        h2_bucket_eos *h = b->data;
+        apr_pool_pre_cleanup_register(stream->pool, &h->stream, bucket_cleanup);
+    }
+    return b;
+}
+
+static void bucket_destroy(void *data)
+{
+    h2_bucket_eos *h = data;
+
+    if (apr_bucket_shared_destroy(h)) {
+        h2_stream *stream = h->stream;
+        if (stream) {
+            h2_stream_cleanup(stream);
+        }
+        apr_bucket_free(h);
+    }
+}
+
+const apr_bucket_type_t h2_bucket_type_eos = {
+    "H2EOS", 5, APR_BUCKET_METADATA,
+    bucket_destroy,
+    bucket_read,
+    apr_bucket_setaside_noop,
+    apr_bucket_split_notimpl,
+    apr_bucket_shared_copy
+};
+

Added: httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.h?rev=1715371&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.h (added)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_bucket_eos.h Fri Nov 20 15:13:11 2015
@@ -0,0 +1,30 @@
+/* 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_http2_h2_bucket_stream_eos_h
+#define mod_http2_h2_bucket_stream_eos_h
+
+struct h2_stream;
+
+/** End Of HTTP/2 STREAM (H2EOS) bucket */
+extern const apr_bucket_type_t h2_bucket_type_eos;
+
+
+apr_bucket *h2_bucket_eos_make(apr_bucket *b, struct h2_stream *stream);
+
+apr_bucket *h2_bucket_eos_create(apr_bucket_alloc_t *list, 
+                                 struct h2_stream *stream);
+
+#endif /* mod_http2_h2_bucket_stream_eos_h */

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -29,6 +29,7 @@
 #include "h2_ctx.h"
 #include "h2_conn.h"
 #include "h2_config.h"
+#include "h2_h2.h"
 #include "h2_private.h"
 
 #define DEF_VAL     (-1)
@@ -38,17 +39,22 @@
 
 static h2_config defconf = {
     "default",
-    100,              /* max_streams */
-    64 * 1024,        /* window_size */
-    -1,               /* min workers */
-    -1,               /* max workers */
-    10 * 60,          /* max workers idle secs */
-    64 * 1024,        /* stream max mem size */
-    NULL,             /* no alt-svcs */
-    -1,               /* alt-svc max age */
-    0,                /* serialize headers */
-    -1,               /* h2 direct mode */
-    -1,               /* # session extra files */
+    100,                    /* max_streams */
+    H2_INITIAL_WINDOW_SIZE, /* window_size */
+    -1,                     /* min workers */
+    -1,                     /* max workers */
+    10 * 60,                /* max workers idle secs */
+    64 * 1024,              /* stream max mem size */
+    NULL,                   /* no alt-svcs */
+    -1,                     /* alt-svc max age */
+    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 */
+    1,                      /* HTTP/2 server push enabled */
 };
 
 static int files_per_session = 0;
@@ -100,6 +106,12 @@ 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;
+    conf->h2_push              = DEF_VAL;
+    
     return conf;
 }
 
@@ -127,23 +139,33 @@ 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);
+    n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
     
     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 +184,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 +196,12 @@ 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);
+        case H2_CONF_PUSH:
+            return H2_CONFIG_GET(conf, &defconf, h2_push);
         default:
             return DEF_VAL;
     }
@@ -290,8 +322,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 +364,77 @@ 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_push(cmd_parms *parms,
+                                    void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    if (!strcasecmp(value, "On")) {
+        cfg->h2_push = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->h2_push = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
+
+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 +455,20 @@ 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_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
+                  RSRC_CONF, "off to disable HTTP/2 server push"),
     AP_END_CMD
 };
 

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -34,6 +34,11 @@ 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_CONF_PUSH,
 } h2_config_var_t;
 
 /* Apache httpd module configuration for h2. */
@@ -51,6 +56,11 @@ 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 */
+    int h2_push;                  /* if HTTP/2 server push is enabled */
 } h2_config;
 
 
@@ -67,6 +77,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.x/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c?rev=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 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"
@@ -39,11 +40,8 @@
 
 static struct h2_workers *workers;
 
-static apr_status_t h2_session_process(h2_session *session);
-
 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 +62,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 +98,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) {
@@ -139,228 +131,70 @@ static module *h2_conn_mpm_module(void)
     return mpm_module;
 }
 
-apr_status_t h2_conn_rprocess(request_rec *r)
+apr_status_t h2_conn_process(conn_rec *c, request_rec *r)
 {
-    h2_config *config = h2_config_rget(r);
+    apr_status_t status;
     h2_session *session;
+    h2_config *config;
+    int rv;
     
-    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "h2_conn_process start");
     if (!workers) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02911) 
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911) 
                       "workers not initialized");
         return APR_EGENERAL;
     }
     
-    session = h2_session_rcreate(r, config, workers);
-    if (!session) {
-        return APR_EGENERAL;
-    }
-    
-    return h2_session_process(session);
-}
-
-apr_status_t h2_conn_main(conn_rec *c)
-{
-    h2_config *config = h2_config_get(c);
-    h2_session *session;
-    apr_status_t status;
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_process start");
     
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_main start");
-    if (!workers) {
-        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02912) 
-                      "workers not initialized");
-        return APR_EGENERAL;
-    }
-    
-    session = h2_session_create(c, config, workers);
-    if (!session) {
-        return APR_EGENERAL;
+    if (r) {
+        config = h2_config_rget(r);
+        session = h2_session_rcreate(r, config, workers);
     }
-    
-    status = h2_session_process(session);
-
-    /* Make sure this connection gets closed properly. */
-    c->keepalive = AP_CONN_CLOSE;
-    if (c->cs) {
-        c->cs->state = CONN_STATE_WRITE_COMPLETION;
+    else {
+        config = h2_config_get(c);
+        session = h2_session_create(c, config, workers);
     }
-
-    return status;
-}
-
-apr_status_t h2_session_process(h2_session *session)
-{
-    apr_status_t status = APR_SUCCESS;
-    int rv = 0;
-    apr_interval_time_t wait_micros = 0;
-    static const int MAX_WAIT_MICROS = 200 * 1000;
-    
-    /* Start talking to the client. Apart from protocol meta data,
-     * we mainly will see new http/2 streams opened by the client, which
-     * basically are http requests we need to dispatch.
-     *
-     * There will be bursts of new streams, to be served concurrently,
-     * followed by long pauses of no activity.
-     *
-     * Since the purpose of http/2 is to allow siumultaneous streams, we
-     * need to dispatch the handling of each stream into a separate worker
-     * thread, keeping this thread open for sending responses back as
-     * soon as they arrive.
-     * At the same time, we need to continue reading new frames from
-     * our client, which may be meta (WINDOWS_UPDATEs, PING, SETTINGS) or
-     * new streams.
-     *
-     * As long as we have streams open in this session, we cannot really rest
-     * since there are two conditions to wait on: 1. new data from the client,
-     * 2. new data from the open streams to send back.
-     *
-     * Only when we have no more streams open, can we do a blocking read
-     * on our connection.
-     *
-     * TODO: implement graceful GO_AWAY after configurable idle time
-     */
     
-    ap_update_child_status_from_conn(session->c->sbh, SERVER_BUSY_READ, 
-                                     session->c);
+    if (!h2_is_acceptable_connection(c, 1)) {
+        nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE, 0,
+                              NGHTTP2_INADEQUATE_SECURITY, NULL, 0);
+    } 
 
-    if (APLOGctrace2(session->c)) {
-        ap_filter_t *filter = session->c->input_filters;
-        while (filter) {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
-                          "h2_conn(%ld), has connection filter %s",
-                          session->id, filter->frec->name);
-            filter = filter->next;
-        }
-    }
-    
+    ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
     status = h2_session_start(session, &rv);
     
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
                   "h2_session(%ld): starting on %s:%d", session->id,
-                  session->c->base_server->defn_name,
+                  session->c->base_server->server_hostname,
                   session->c->local_addr->port);
     if (status != APR_SUCCESS) {
         h2_session_abort(session, status, rv);
-        h2_session_destroy(session);
+        h2_session_eoc_callback(session);
         return status;
     }
     
-    while (!h2_session_is_done(session)) {
-        int have_written = 0;
-        int have_read = 0;
-        int got_streams;
-        
-        status = h2_session_write(session, wait_micros);
-        if (status == APR_SUCCESS) {
-            have_written = 1;
-            wait_micros = 0;
-        }
-        else if (status == APR_EAGAIN) {
-            /* nop */
-        }
-        else if (status == APR_TIMEUP) {
-            wait_micros *= 2;
-            if (wait_micros > MAX_WAIT_MICROS) {
-                wait_micros = MAX_WAIT_MICROS;
-            }
-        }
-        else {
-            ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
-                          "h2_session(%ld): writing, terminating",
-                          session->id);
-            h2_session_abort(session, status, 0);
-            break;
-        }
-        
-        /* We would like to do blocking reads as often as possible as they
-         * are more efficient in regard to server resources.
-         * We can do them under the following circumstances:
-         * - we have no open streams and therefore have nothing to write
-         * - we have just started the session and are waiting for the first
-         *   two frames to come in. There will always be at least 2 frames as
-         *   * h2 will send SETTINGS and SETTINGS-ACK
-         *   * h2c will count the header settings as one frame and we
-         *     submit our settings and need the ACK.
-         */
-        got_streams = !h2_stream_set_is_empty(session->streams);
-        status = h2_session_read(session, 
-                                 (!got_streams 
-                                  || session->frames_received <= 1)?
-                                 APR_BLOCK_READ : APR_NONBLOCK_READ);
-        switch (status) {
-            case APR_SUCCESS:       /* successful read, reset our idle timers */
-                have_read = 1;
-                wait_micros = 0;
-                break;
-            case APR_EAGAIN:              /* non-blocking read, nothing there */
-                break;
-            case APR_EBADF:               /* connection is not there any more */
-            case APR_EOF:
-            case APR_ECONNABORTED:
-            case APR_ECONNRESET:
-            case APR_TIMEUP:                       /* blocked read, timed out */
-                ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
-                              "h2_session(%ld): reading",
-                              session->id);
-                h2_session_abort(session, status, 0);
-                break;
-            default:
-                ap_log_cerror( APLOG_MARK, APLOG_INFO, status, session->c,
-                              APLOGNO(02950) 
-                              "h2_session(%ld): error reading, terminating",
-                              session->id);
-                h2_session_abort(session, status, 0);
-                break;
-        }
-        
-        if (!have_read && !have_written
-            && !h2_stream_set_is_empty(session->streams)) {
-            /* Nothing to read or write, we have streams, but
-             * the have no data yet ready to be delivered. Slowly
-             * back off to give others a chance to do their work.
-             */
-            if (wait_micros == 0) {
-                wait_micros = 10;
-            }
-        }
-    }
-    
+    status = h2_session_process(session);
+
     ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
                   "h2_session(%ld): done", session->id);
-    
-    ap_update_child_status_from_conn(session->c->sbh, SERVER_CLOSING, 
-                                     session->c);
-
     h2_session_close(session);
-    h2_session_destroy(session);
+    h2_session_flush(session);
+    /* hereafter session might be gone */
     
-    return DONE;
+    /* 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;
+    }
+
+    return status;
 }
 
 
 static void fix_event_conn(conn_rec *c, conn_rec *master);
 
-/*
- * We would like to create the connection more lightweight like
- * slave connections in 2.5-DEV. But we get 500 responses on long
- * cgi tests in modules/h2.t as the script parsing seems to see an
- * EOF from the cgi before anything is sent. 
- *
-conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
-{
-    conn_rec *c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
-    
-    memcpy(c, master, sizeof(conn_rec));
-    c->id = (master->id & (long)pool);
-    c->slaves = NULL;
-    c->master = master;
-    c->input_filters = NULL;
-    c->output_filters = NULL;
-    c->pool = pool;
-    
-    return c;
-}
-*/
+static int SLAVE_CONN_25DEV_STYLE = 1;
 
 conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
 {
@@ -368,39 +202,56 @@ conn_rec *h2_conn_create(conn_rec *maste
     conn_rec *c;
     
     AP_DEBUG_ASSERT(master);
-    
-    /* CAVEAT: it seems necessary to setup the conn_rec in the master
-     * connection thread. Other attempts crashed. 
-     * HOWEVER: we setup the connection using the pools and other items
-     * from the master connection, since we do not want to allocate 
-     * lots of resources here. 
-     * Lets allocated pools and everything else when we actually start
-     * working on this new connection.
-     */
-    /* Not sure about the scoreboard handle. Reusing the one from the main
-     * connection could make sense, is not really correct, but we cannot
-     * easily create new handles for our worker threads either.
-     * TODO
-     */
-    socket = ap_get_module_config(master->conn_config, &core_module);
-    c = ap_run_create_connection(pool, master->base_server,
-                                 socket,
-                                 master->id^((long)pool), 
-                                 master->sbh,
-                                 master->bucket_alloc);
+
+    if (SLAVE_CONN_25DEV_STYLE) {
+        /* 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));
+        
+        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;        
+    }
+    else {
+        /* CAVEAT: it seems necessary to setup the conn_rec in the master
+         * connection thread. Other attempts crashed. 
+         * HOWEVER: we setup the connection using the pools and other items
+         * from the master connection, since we do not want to allocate 
+         * lots of resources here. 
+         * Lets allocated pools and everything else when we actually start
+         * working on this new connection.
+         */
+        /* Not sure about the scoreboard handle. Reusing the one from the main
+         * connection could make sense, is not really correct, but we cannot
+         * easily create new handles for our worker threads either.
+         * TODO
+         */
+        socket = ap_get_module_config(master->conn_config, &core_module);
+        c = ap_run_create_connection(pool, master->base_server,
+                                     socket,
+                                     master->id^((long)pool), 
+                                     master->sbh,
+                                     master->bucket_alloc);
+    }
     if (c == NULL) {
         ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool, 
                       APLOGNO(02913) "h2_task: creating conn");
-        return NULL;
     }
     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, apr_bucket_alloc_t *bucket_alloc,
+                           apr_thread_t *thread, apr_socket_t *socket)
 {
-    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
@@ -409,28 +260,17 @@ 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->current_thread = thread;
+    task->c->bucket_alloc = bucket_alloc;
     
-    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, socket);
     
     /* This works for mpm_worker so far. Other mpm modules have 
      * different needs, unfortunately. The most interesting one 
@@ -441,7 +281,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 */
@@ -453,26 +293,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;
-    
-    return APR_SUCCESS;
-}
-
-apr_status_t h2_conn_post(conn_rec *c, h2_worker *worker)
-{
-    (void)worker;
-    
-    /* be sure no one messes with this any more */
-    memset(c, 0, sizeof(*c)); 
-    return APR_SUCCESS;
-}
-
-apr_status_t h2_conn_process(conn_rec *c, apr_socket_t *socket)
-{
-    AP_DEBUG_ASSERT(c);
-    
-    c->clogging_input_filters = 1;
-    ap_process_connection(c, socket);
+    task->c->keepalives = 1;
     
     return APR_SUCCESS;
 }

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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -17,20 +17,16 @@
 #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
+/**
+ * Process the connection that is now starting the HTTP/2
  * conversation. Return when the HTTP/2 session is done
  * and the connection will close.
+ *
+ * @param c the connection HTTP/2 is starting on
+ * @param r the upgrad requestion that still awaits an answer, optional
  */
-apr_status_t h2_conn_main(conn_rec *c);
-
-/* Process the request that has been upgraded to a HTTP/2
- * conversation. Return when the HTTP/2 session is done
- * and the connection will close.
- */
-apr_status_t h2_conn_rprocess(request_rec *r);
+apr_status_t h2_conn_process(conn_rec *c, request_rec *r);
 
 /* Initialize this child process for h2 connection work,
  * to be called once during child init before multi processing
@@ -52,9 +48,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_post(conn_rec *c, struct h2_worker *worker);
-
-apr_status_t h2_conn_process(conn_rec *c, apr_socket_t *socket);
+apr_status_t h2_conn_setup(struct h2_task *task, apr_bucket_alloc_t *bucket_alloc,
+                           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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 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_pass(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,47 +305,78 @@ 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_flush(h2_conn_io *io)
+apr_status_t h2_conn_io_consider_flush(h2_conn_io *io)
 {
+    apr_status_t status = APR_SUCCESS;
+    
+    /* 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 have not found out the "best" way to deal with
+     * this, force a flush at least every WRITE_BUFFER_SIZE amount
+     * of data.
+     */
     if (io->unflushed) {
-        apr_status_t status; 
+        apr_off_t len = 0;
+        if (!APR_BRIGADE_EMPTY(io->output)) {
+            apr_brigade_length(io->output, 0, &len);
+        }
+        len += io->buflen;
+        if (len >= WRITE_BUFFER_SIZE) {
+            return h2_conn_io_pass(io);
+        }
+    }
+    return status;
+}
+
+static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force)
+{
+    if (io->unflushed || force) {
         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 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 {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
-                          "h2_conn_io: flush error");
+        if (force) {
+            APR_BRIGADE_INSERT_TAIL(io->output,
+                                    apr_bucket_flush_create(io->output->bucket_alloc));
         }
         
-        return status;
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, io->connection,
+                      "h2_conn_io: flush");
+        /* Send it out */
+        io->unflushed = 0;
+        return pass_out(io->output, io);
+        /* 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)
+{
+    return h2_conn_io_flush_int(io, 1);
+}
+
+apr_status_t h2_conn_io_pass(h2_conn_io *io)
+{
+    return h2_conn_io_flush_int(io, 0);
+}
\ 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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -26,11 +26,16 @@ typedef struct {
     conn_rec *connection;
     apr_bucket_brigade *input;
     apr_bucket_brigade *output;
-    int buffer_output;
-    int write_size;
+
+    int is_tls;
+    apr_time_t cooldown_usecs;
+    apr_int64_t warmup_size;
+    
+    apr_size_t 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,7 +58,12 @@ 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_pass(h2_conn_io *io);
 apr_status_t h2_conn_io_flush(h2_conn_io *io);
 
 #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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 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.x/modules/http2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h?rev=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 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.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=1715371&r1=1715370&r2=1715371&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 Fri Nov 20 15:13:11 2015
@@ -59,11 +59,6 @@ apr_status_t h2_from_h1_destroy(h2_from_
     return APR_SUCCESS;
 }
 
-h2_from_h1_state_t h2_from_h1_get_state(h2_from_h1 *from_h1)
-{
-    return from_h1->state;
-}
-
 static void set_state(h2_from_h1 *from_h1, h2_from_h1_state_t state)
 {
     if (from_h1->state != state) {
@@ -78,16 +73,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);
-    if (from_h1->response == NULL) {
-        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, r->connection,
-                      APLOGNO(02915) 
-                      "h2_from_h1(%d): unable to create resp_head",
-                      from_h1->stream_id);
-        return APR_EINVAL;
-    }
+    from_h1->response = h2_response_create(from_h1->stream_id, 0,
+                                           from_h1->http_status, from_h1->hlines,
+                                           from_h1->pool);
     from_h1->content_length = from_h1->response->content_length;
     from_h1->chunked = r->chunked;
     
@@ -202,8 +190,7 @@ apr_status_t h2_from_h1_read_response(h2
                 }
                 if (from_h1->state == H2_RESP_ST_STATUS_LINE) {
                     /* instead of parsing, just take it directly */
-                    from_h1->status = apr_psprintf(from_h1->pool, 
-                                                   "%d", f->r->status);
+                    from_h1->http_status = f->r->status;
                     from_h1->state = H2_RESP_ST_HEADERS;
                 }
                 else if (line[0] == '\0') {
@@ -417,7 +404,7 @@ static h2_response *create_response(h2_f
     }
     
     if (!apr_is_empty_array(r->content_languages)) {
-        int i;
+        unsigned int i;
         char *token;
         char **languages = (char **)(r->content_languages->elts);
         const char *field = apr_table_get(r->headers_out, "Content-Language");
@@ -492,8 +479,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 +490,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.x/modules/http2/h2_from_h1.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h Fri Nov 20 15:13:11 2015
@@ -48,35 +48,25 @@ struct h2_from_h1 {
     apr_pool_t *pool;
     apr_bucket_brigade *bb;
     
-    apr_size_t content_length;
+    apr_off_t content_length;
     int chunked;
     
-    const char *status;
+    int http_status;
     apr_array_header_t *hlines;
     
     struct h2_response *response;
 };
 
 
-typedef void h2_from_h1_state_change_cb(struct h2_from_h1 *resp,
-                                         h2_from_h1_state_t prevstate,
-                                         void *cb_ctx);
-
 h2_from_h1 *h2_from_h1_create(int stream_id, apr_pool_t *pool);
 
 apr_status_t h2_from_h1_destroy(h2_from_h1 *response);
 
-void h2_from_h1_set_state_change_cb(h2_from_h1 *from_h1,
-                                     h2_from_h1_state_change_cb *callback,
-                                     void *cb_ctx);
-
 apr_status_t h2_from_h1_read_response(h2_from_h1 *from_h1,
                                       ap_filter_t* f, apr_bucket_brigade* bb);
 
 struct h2_response *h2_from_h1_get_response(h2_from_h1 *from_h1);
 
-h2_from_h1_state_t h2_from_h1_get_state(h2_from_h1 *from_h1);
-
 apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb);
 
 #endif /* defined(__mod_h2__h2_from_h1__) */