[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apache-cvs
Subject:    svn commit: r1688474 [4/21] - in /httpd/httpd/trunk/modules/http2: ./ m4/ mod-h2.xcodeproj/ mod-h2.x
From:       jim () apache ! org
Date:       2015-06-30 15:26:19
Message-ID: 20150630152622.2A09CAC08DF () hades ! apache ! org
[Download RAW message or body]

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,295 @@
+/* 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 <apr_strings.h>
+#include <apr_optional.h>
+#include <apr_optional_hooks.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_connection.h>
+#include <http_protocol.h>
+#include <http_log.h>
+
+#include "h2_private.h"
+
+#include "h2_config.h"
+#include "h2_ctx.h"
+#include "h2_conn.h"
+#include "h2_h2.h"
+#include "h2_alpn.h"
+
+/*******************************************************************************
+ * SSL var lookup
+ */
+APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
+                        (apr_pool_t *, server_rec *,
+                         conn_rec *, request_rec *,
+                         char *));
+static char *(*opt_ssl_var_lookup)(apr_pool_t *, server_rec *,
+                                   conn_rec *, request_rec *,
+                                   char *);
+
+/*******************************************************************************
+ * NPN callbacks and registry, deprecated
+ */
+typedef int (*ssl_npn_advertise_protos)(conn_rec *connection, 
+    apr_array_header_t *protos);
+
+typedef int (*ssl_npn_proto_negotiated)(conn_rec *connection, 
+    const char *proto_name, apr_size_t proto_name_len);
+
+APR_DECLARE_OPTIONAL_FN(int, modssl_register_npn, 
+                        (conn_rec *conn,
+                         ssl_npn_advertise_protos advertisefn,
+                         ssl_npn_proto_negotiated negotiatedfn));
+
+static int (*opt_ssl_register_npn)(conn_rec*,
+                                   ssl_npn_advertise_protos,
+                                   ssl_npn_proto_negotiated);
+
+/*******************************************************************************
+ * ALPN callbacks and registry
+ */
+typedef int (*ssl_alpn_propose_protos)(conn_rec *connection,
+    apr_array_header_t *client_protos, apr_array_header_t *protos);
+
+typedef int (*ssl_alpn_proto_negotiated)(conn_rec *connection,
+    const char *proto_name, apr_size_t proto_name_len);
+
+APR_DECLARE_OPTIONAL_FN(int, modssl_register_alpn,
+                        (conn_rec *conn,
+                         ssl_alpn_propose_protos proposefn,
+                         ssl_alpn_proto_negotiated negotiatedfn));
+
+static int (*opt_ssl_register_alpn)(conn_rec*,
+                                    ssl_alpn_propose_protos,
+                                    ssl_alpn_proto_negotiated);
+
+/*******************************************************************************
+ * Hooks for processing incoming connections:
+ * - pre_conn_after_tls registers for ALPN handling
+ */
+static int h2_alpn_pre_conn(conn_rec* c, void *arg);
+
+/*******************************************************************************
+ * Once per lifetime init, retrieve optional functions
+ */
+apr_status_t h2_alpn_init(apr_pool_t *pool, server_rec *s)
+{
+    (void)pool;
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "h2_alpn init");
+    opt_ssl_register_npn = APR_RETRIEVE_OPTIONAL_FN(modssl_register_npn);
+    opt_ssl_register_alpn = APR_RETRIEVE_OPTIONAL_FN(modssl_register_alpn);
+    opt_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
+
+    if (!opt_ssl_register_alpn && !opt_ssl_register_npn) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                     "mod_ssl does not offer ALPN or NPN registration");
+    }
+    return APR_SUCCESS;
+}
+
+/*******************************************************************************
+ * Register various hooks
+ */
+static const char *const mod_ssl[]        = { "mod_ssl.c", NULL};
+static const char *const mod_core[]       = { "core.c", NULL};
+
+static void check_sni_host(conn_rec *c) 
+{
+    /* If we have not done so already, ask the connection for the
+     * hostname send to us via SNI. This information is later used
+     * to retrieve the correct server settings for this connection.
+     */
+    h2_ctx *ctx = h2_ctx_get(c);
+    if (opt_ssl_var_lookup && !ctx->hostname) {
+        const char *p = opt_ssl_var_lookup(c->pool, c->base_server, c, 
+                                           NULL, (char*)"SSL_TLS_SNI");
+        if (p && *p) {
+            ctx->hostname = apr_pstrdup(c->pool, p);
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+                          "h2_h2, connection, SNI %s",
+                          ctx->hostname? ctx->hostname : "NULL");
+        }
+    }
+}
+
+void h2_alpn_register_hooks(void)
+{
+    /* This hook runs on new connection after mod_ssl, but before the core
+     * httpd. Its purpose is to register, if TLS is used, the ALPN callbacks
+     * that enable us to chose "h2" as next procotol if the client supports it.
+     */
+    ap_hook_pre_connection(h2_alpn_pre_conn, 
+                           mod_ssl, mod_core, APR_HOOK_LAST);
+    
+}
+
+static int h2_util_array_index(apr_array_header_t *array, const char *s)
+{
+    for (int i = 0; i < array->nelts; i++) {
+        const char *p = APR_ARRAY_IDX(array, i, const char*);
+        if (!strcmp(p, s)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static int h2_npn_advertise(conn_rec *c, apr_array_header_t *protos)
+{
+    h2_config *cfg;
+    
+    check_sni_host(c);
+    cfg = h2_config_get(c);
+    if (!h2_config_geti(cfg, H2_CONF_ENABLED)) {
+        return DECLINED;
+    }
+    
+    for (apr_size_t i = 0; i < h2_alpn_protos_len; ++i) {
+        const char *proto = h2_alpn_protos[i];
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                      "NPN proposing %s from client selection", proto);
+        APR_ARRAY_PUSH(protos, const char*) = proto;
+    }
+    return OK;
+}
+
+static int h2_negotiated(conn_rec *c, const char *via, 
+                         const char *proto_name,
+                         apr_size_t proto_name_len)
+{
+    h2_ctx *ctx = h2_ctx_get(c);
+
+    if (h2_ctx_is_task(ctx) ) {
+        return DECLINED;
+    }
+    
+    if (h2_ctx_pnego_is_done(ctx)) {
+        /* called twice? refraing from overriding existing selection.
+         * NPN is fading...
+         */
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                      "protocol negotiated via %s called, but already set", 
+                      via); 
+        return DECLINED;
+    }
+    
+    if (APLOGctrace1(c)) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                      "protocol negotiated via %s is %s", via, 
+                      apr_pstrndup(c->pool, proto_name, proto_name_len));
+    }
+    
+    for (apr_size_t i = 0; i < h2_alpn_protos_len; ++i) {
+        const char *proto = h2_alpn_protos[i];
+        if (proto_name_len == strlen(proto)
+            && strncmp(proto, proto_name, proto_name_len) == 0) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 
+                          "protocol set via %s to %s", via, proto);
+            h2_ctx_pnego_set_done(ctx, proto);
+            break;
+        }
+    }    
+    return OK;
+}
+
+static int h2_npn_negotiated(conn_rec *c,
+                             const char *proto_name,
+                             apr_size_t proto_name_len)
+{
+    return h2_negotiated(c, "NPN", proto_name, proto_name_len);
+}
+
+static int h2_alpn_propose(conn_rec *c,
+                           apr_array_header_t *client_protos,
+                           apr_array_header_t *protos)
+{
+    h2_config *cfg;
+    
+    check_sni_host(c);
+    cfg = h2_config_get(c);
+    if (!h2_config_geti(cfg, H2_CONF_ENABLED)) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                      "ALPN propose, h2 disabled for config %s", cfg->name);
+        return DECLINED;
+    }
+    
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                  "ALPN propose for config %s", cfg->name);
+    /* */
+    for (apr_size_t i = 0; i < h2_alpn_protos_len; ++i) {
+        const char *proto = h2_alpn_protos[i];
+        if (h2_util_array_index(client_protos, proto) >= 0) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                          "ALPN proposing %s", proto);
+            APR_ARRAY_PUSH(protos, const char*) = proto;
+            return OK; /* propose only one, the first match from our list */
+        }
+    }
+    return OK;
+}
+
+static int h2_alpn_negotiated(conn_rec *c,
+                              const char *proto_name,
+                              apr_size_t proto_name_len)
+{
+    return h2_negotiated(c, "ALPN", proto_name, proto_name_len);
+}
+
+
+
+int h2_alpn_pre_conn(conn_rec* c, void *arg)
+{
+    (void)arg;
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+                  "h2_h2, pre_connection, start");
+    
+    h2_ctx *ctx = h2_ctx_get(c);
+    if (h2_ctx_is_task(ctx)) {
+        /* our stream pseudo connection */
+        return DECLINED;
+    }
+    
+    if (h2_h2_is_tls(c)) {
+        /* Brand new TLS connection: Does mod_ssl offer ALPN/NPN support? 
+         * If so, register at all present, clients may use either/or.
+         */
+        if (opt_ssl_register_alpn == NULL && opt_ssl_register_npn == NULL) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                          "h2_h2, pre_connection, no ALPN/NPN "
+                          "support in mod_ssl");
+            return DECLINED;
+        }
+        
+        if (opt_ssl_register_alpn) {
+            opt_ssl_register_alpn(c, h2_alpn_propose, h2_alpn_negotiated);
+        }
+        if (opt_ssl_register_npn) {
+            opt_ssl_register_npn(c, h2_npn_advertise, h2_npn_negotiated);
+        }
+        
+        h2_ctx_pnego_set_started(ctx);
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+                      "h2_alpn, pre_connection, ALPN callback registered");
+    }
+    
+    return DECLINED;
+}
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_alpn.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,29 @@
+/* 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_alpn__
+#define __mod_h2__h2_alpn__
+
+/*
+ * One time, post config intialization.
+ */
+apr_status_t h2_alpn_init(apr_pool_t *pool, server_rec *s);
+
+/* Register apache hooks for ALPN protocol
+ */
+void h2_alpn_register_hooks(void);
+
+
+#endif /* defined(__mod_h2__h2_h2__) */

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,122 @@
+/* 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 <apr_strings.h>
+#include <httpd.h>
+#include <http_core.h>
+#include <http_log.h>
+
+#include "h2_private.h"
+#include "h2_alt_svc.h"
+#include "h2_ctx.h"
+#include "h2_config.h"
+#include "h2_h2.h"
+#include "h2_util.h"
+
+static int h2_alt_svc_request_handler(request_rec *r);
+
+void h2_alt_svc_register_hooks(void)
+{
+    ap_hook_handler(h2_alt_svc_request_handler, NULL, NULL, APR_HOOK_LAST);
+}
+
+/**
+ * Parse an Alt-Svc specifier as described in "HTTP Alternative Services"
+ * (https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04)
+ * with the following changes:
+ * - 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) {
+    const char *sep = strchr(s, '=');
+    if (sep) {
+        const char *alpn = apr_pstrndup(pool, s, sep - s);
+        const char *host = NULL;
+        int port = 0;
+        s = sep + 1;
+        sep = strchr(s, ':');  /* mandatory : */
+        if (sep) {
+            if (sep != s) {    /* optional host */
+                host = apr_pstrndup(pool, s, sep - s);
+            }
+            s = sep + 1;
+            if (*s) {          /* must be a port number */
+                port = (int)apr_atoi64(s);
+                if (port > 0 && port < (0x1 << 16)) {
+                    h2_alt_svc *as = apr_pcalloc(pool, sizeof(*as));
+                    as->alpn = alpn;
+                    as->host = host;
+                    as->port = port;
+                    return as;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+#define h2_alt_svc_IDX(list, i) ((h2_alt_svc**)(list)->elts)[i]
+
+static int h2_alt_svc_request_handler(request_rec *r)
+{
+    h2_ctx *ctx = h2_ctx_rget(r);
+    
+    if (h2_ctx_is_active(ctx) || h2_ctx_is_task(ctx)) {
+        return DECLINED;
+    }
+    
+    h2_config *cfg = h2_config_rget(r);
+    if (r->hostname && cfg && cfg->alt_svcs && cfg->alt_svcs->nelts > 0) {
+        const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used");
+        if (!alt_svc_used /*|| (alt_svc_used[0] == '0')*/) {
+            /* We have alt-svcs defined and client is not already using
+             * one, announce the services that were configured and match. 
+             * The security of this connection determines if we allow
+             * other host names or ports only.
+             */
+            const char *alt_svc = "";
+            const char *svc_ma = "";
+            int secure = h2_h2_is_tls(r->connection);
+            int ma = h2_config_geti(cfg, H2_CONF_ALT_SVC_MAX_AGE);
+            if (ma >= 0) {
+                svc_ma = apr_psprintf(r->pool, "; ma=%d", ma);
+            }
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "h2_alt_svc: announce %s for %s:%d", 
+                          (secure? "secure" : "insecure"), 
+                          r->hostname, (int)r->server->port);
+            for (int i = 0; i < cfg->alt_svcs->nelts; ++i) {
+                h2_alt_svc *as = h2_alt_svc_IDX(cfg->alt_svcs, i);
+                const char *ahost = as->host;
+                if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) {
+                    ahost = NULL;
+                }
+                if (secure || !ahost) {
+                    alt_svc = apr_psprintf(r->pool, "%s%s%s=\"%s:%d\"%s", 
+                                           alt_svc,
+                                           (*alt_svc? ", " : ""), as->alpn,
+                                           ahost? ahost : "", as->port,
+                                           svc_ma);
+                }
+            }
+            if (*alt_svc) {
+                apr_table_set(r->headers_out, "Alt-Svc", alt_svc);
+            }
+        }
+    }
+    
+    return DECLINED;
+}
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_alt_svc.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,39 @@
+/* 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_alt_svc__
+#define __mod_h2__h2_alt_svc__
+
+typedef struct h2_alt_svc h2_alt_svc;
+
+struct h2_alt_svc {
+    const char *alpn;
+    const char *host;
+    int port;
+};
+
+void h2_alt_svc_register_hooks(void);
+
+/**
+ * Parse an Alt-Svc specifier as described in "HTTP Alternative Services"
+ * (https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04)
+ * with the following changes:
+ * - 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);
+
+
+#endif /* defined(__mod_h2__h2_alt_svc__) */

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_config.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_config.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_config.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,384 @@
+/* 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_config.h>
+#include <http_log.h>
+#include <http_vhost.h>
+
+#include <apr_strings.h>
+
+#include "h2_alt_svc.h"
+#include "h2_ctx.h"
+#include "h2_conn.h"
+#include "h2_config.h"
+#include "h2_private.h"
+
+#define DEF_VAL     (-1)
+
+#define H2_CONFIG_GET(a, b, n) \
+    (((a)->n == DEF_VAL)? (b) : (a))->n
+
+static h2_config defconf = {
+    "default",
+    0,                /* enabled */
+    100,              /* max_streams */
+    16 * 1024,        /* max_hl_size */
+    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,                /* hack mpm event */
+    1,                /* h2 direct mode */
+};
+
+static void *h2_config_create(apr_pool_t *pool,
+                              const char *prefix, const char *x)
+{
+    h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
+    
+    const char *s = x? x : "unknown";
+    char *name = (char *)apr_pcalloc(pool, strlen(prefix) + strlen(s) + 20);
+    strcpy(name, prefix);
+    strcat(name, "[");
+    strcat(name, s);
+    strcat(name, "]");
+    
+    conf->name           = name;
+    conf->h2_enabled     = DEF_VAL;
+    conf->h2_max_streams = DEF_VAL;
+    conf->h2_max_hl_size = DEF_VAL;
+    conf->h2_window_size = DEF_VAL;
+    conf->min_workers    = DEF_VAL;
+    conf->max_workers    = DEF_VAL;
+    conf->max_worker_idle_secs = DEF_VAL;
+    conf->stream_max_mem_size = DEF_VAL;
+    conf->alt_svc_max_age = DEF_VAL;
+    conf->serialize_headers = DEF_VAL;
+    conf->hack_mpm_event = DEF_VAL;
+    conf->h2_direct      = DEF_VAL;
+    return conf;
+}
+
+void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
+{
+    return h2_config_create(pool, "srv", s->defn_name);
+}
+
+void *h2_config_create_dir(apr_pool_t *pool, char *x)
+{
+    return h2_config_create(pool, "dir", x);
+}
+
+void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
+{
+    h2_config *base = (h2_config *)basev;
+    h2_config *add = (h2_config *)addv;
+    h2_config *n = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
+
+    char *name = (char *)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, "]");
+    n->name = name;
+
+    n->h2_enabled     = H2_CONFIG_GET(add, base, h2_enabled);
+    n->h2_max_streams = H2_CONFIG_GET(add, base, h2_max_streams);
+    n->h2_max_hl_size = H2_CONFIG_GET(add, base, h2_max_hl_size);
+    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->hack_mpm_event = H2_CONFIG_GET(add, base, hack_mpm_event);
+    n->h2_direct      = H2_CONFIG_GET(add, base, h2_direct);
+    
+    return n;
+}
+
+int h2_config_geti(h2_config *conf, h2_config_var_t var)
+{
+    switch(var) {
+        case H2_CONF_ENABLED:
+            return H2_CONFIG_GET(conf, &defconf, h2_enabled);
+        case H2_CONF_MAX_STREAMS:
+            return H2_CONFIG_GET(conf, &defconf, h2_max_streams);
+        case H2_CONF_MAX_HL_SIZE:
+            return H2_CONFIG_GET(conf, &defconf, h2_max_hl_size);
+        case H2_CONF_WIN_SIZE:
+            return H2_CONFIG_GET(conf, &defconf, h2_window_size);
+        case H2_CONF_MIN_WORKERS:
+            return H2_CONFIG_GET(conf, &defconf, min_workers);
+        case H2_CONF_MAX_WORKERS:
+            return H2_CONFIG_GET(conf, &defconf, max_workers);
+        case H2_CONF_MAX_WORKER_IDLE_SECS:
+            return H2_CONFIG_GET(conf, &defconf, max_worker_idle_secs);
+        case H2_CONF_STREAM_MAX_MEM:
+            return H2_CONFIG_GET(conf, &defconf, stream_max_mem_size);
+        case H2_CONF_ALT_SVC_MAX_AGE:
+            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_HACK_MPM_EVENT:
+            return H2_CONFIG_GET(conf, &defconf, hack_mpm_event);
+        case H2_CONF_DIRECT:
+            return H2_CONFIG_GET(conf, &defconf, h2_direct);
+        default:
+            return DEF_VAL;
+    }
+}
+
+h2_config *h2_config_sget(server_rec *s)
+{
+    h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, 
+                                                       &h2_module);
+    AP_DEBUG_ASSERT(cfg);
+    return cfg;
+}
+
+
+static const char *h2_conf_set_engine(cmd_parms *parms,
+                                      void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    if (!strcasecmp(value, "On")) {
+        cfg->h2_enabled = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->h2_enabled = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
+
+static const char *h2_conf_set_max_streams(cmd_parms *parms,
+                                           void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->h2_max_streams = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_window_size(cmd_parms *parms,
+                                           void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->h2_window_size = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_max_hl_size(cmd_parms *parms,
+                                           void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->h2_max_hl_size = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_min_workers(cmd_parms *parms,
+                                           void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->min_workers = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_max_workers(cmd_parms *parms,
+                                           void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->max_workers = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms,
+                                                    void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->max_worker_idle_secs = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms,
+                                                   void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    
+    
+    cfg->stream_max_mem_size = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_add_alt_svc(cmd_parms *parms,
+                                  void *arg, const char *value)
+{
+    if (value && strlen(value)) {
+        h2_config *cfg = h2_config_sget(parms->server);
+        h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool);
+        if (!as) {
+            return "unable to parse alt-svc specifier";
+        }
+        if (!cfg->alt_svcs) {
+            cfg->alt_svcs = apr_array_make(parms->pool, 5, sizeof(h2_alt_svc*));
+        }
+        APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
+    }
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms,
+                                               void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->alt_svc_max_age = (int)apr_atoi64(value);
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_serialize_headers(cmd_parms *parms,
+                                                 void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->serialize_headers = !apr_strnatcasecmp(value, "On");
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_hack_mpm_event(cmd_parms *parms,
+                                              void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->hack_mpm_event = !apr_strnatcasecmp(value, "On");
+    (void)arg;
+    return NULL;
+}
+
+static const char *h2_conf_set_direct(cmd_parms *parms,
+                                      void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    cfg->h2_direct = !apr_strnatcasecmp(value, "On");
+    (void)arg;
+    return NULL;
+}
+
+#pragma GCC diagnostic ignored "-Wmissing-braces"
+const command_rec h2_cmds[] = {
+    AP_INIT_TAKE1("H2Engine", h2_conf_set_engine, NULL,
+                  RSRC_CONF, "on to enable HTTP/2 protocol handling"),
+    AP_INIT_TAKE1("H2MaxSessionStreams", h2_conf_set_max_streams, NULL,
+                  RSRC_CONF, "maximum number of open streams per session"),
+    AP_INIT_TAKE1("H2InitialWindowSize", h2_conf_set_window_size, NULL,
+                  RSRC_CONF, "initial window size on client DATA"),
+    AP_INIT_TAKE1("H2MaxHeaderListSize", h2_conf_set_max_hl_size, NULL, 
+                  RSRC_CONF, "maximum acceptable size of request headers"),
+    AP_INIT_TAKE1("H2MinWorkers", h2_conf_set_min_workers, NULL,
+                  RSRC_CONF, "minimum number of worker threads per child"),
+    AP_INIT_TAKE1("H2MaxWorkers", h2_conf_set_max_workers, NULL,
+                  RSRC_CONF, "maximum number of worker threads per child"),
+    AP_INIT_TAKE1("H2MaxWorkerIdleSeconds", h2_conf_set_max_worker_idle_secs, NULL,
+                  RSRC_CONF, "maximum number of idle seconds before a worker shuts \
down"), +    AP_INIT_TAKE1("H2StreamMaxMemSize", h2_conf_set_stream_max_mem_size, \
NULL, +                  RSRC_CONF, "maximum number of bytes buffered in memory for a \
stream"), +    AP_INIT_TAKE1("H2AltSvc", h2_add_alt_svc, NULL,
+                  RSRC_CONF, "adds an Alt-Svc for this server"),
+    AP_INIT_TAKE1("H2AltSvcMaxAge", h2_conf_set_alt_svc_max_age, NULL,
+                  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("H2HackMpmEvent", \
h2_conf_set_hack_mpm_event, NULL, +                  RSRC_CONF, "on to enable a hack \
that makes mpm_event working with mod_h2"), +    AP_INIT_TAKE1("H2Direct", \
h2_conf_set_direct, NULL, +                  RSRC_CONF, "on to enable direct HTTP/2 \
mode on non-TLS"), +    { NULL, NULL, NULL, 0, 0, NULL }
+};
+
+
+h2_config *h2_config_rget(request_rec *r)
+{
+    h2_config *cfg = (h2_config *)ap_get_module_config(r->per_dir_config, 
+                                                       &h2_module);
+    return cfg? cfg : h2_config_sget(r->server); 
+}
+
+h2_config *h2_config_get(conn_rec *c)
+{
+    h2_ctx *ctx = h2_ctx_get(c);
+    if (ctx->config) {
+        return ctx->config;
+    }
+    if (!ctx->server && ctx->hostname) {
+        /* We have a host agreed upon via TLS SNI, but no request yet.
+         * The sni host was accepted and therefore does match a server record
+         * (vhost) for it. But we need to know which one.
+         * Normally, it is enough to be set on the initial request on a
+         * connection, but we need it earlier. Simulate a request and call
+         * the vhost matching stuff.
+         */
+        apr_uri_t uri;
+        memset(&uri, 0, sizeof(uri));
+        uri.scheme = (char*)"https";
+        uri.hostinfo = (char*)ctx->hostname;
+        uri.hostname = (char*)ctx->hostname;
+        uri.port_str = (char*)"";
+        uri.port = c->local_addr->port;
+        uri.path = (char*)"/";
+        
+        request_rec r;
+        memset(&r, 0, sizeof(r));
+        r.uri = (char*)"/";
+        r.connection = c;
+        r.pool = c->pool;
+        r.hostname = ctx->hostname;
+        r.headers_in = apr_table_make(c->pool, 1);
+        r.parsed_uri = uri;
+        r.status = HTTP_OK;
+        r.server = r.connection->base_server;
+        ap_update_vhost_from_headers(&r);
+        ctx->server = r.server;
+    }
+    
+    if (ctx->server) {
+        ctx->config = h2_config_sget(ctx->server);
+        return ctx->config;
+    }
+    
+    return h2_config_sget(c->base_server);
+}
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_config.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_config.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_config.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,78 @@
+/* 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_config_h__
+#define __mod_h2__h2_config_h__
+
+#undef PACKAGE_VERSION
+#undef PACKAGE_TARNAME
+#undef PACKAGE_STRING
+#undef PACKAGE_NAME
+#undef PACKAGE_BUGREPORT
+#include "config.h"
+
+typedef enum {
+    H2_CONF_ENABLED,
+    H2_CONF_MAX_STREAMS,
+    H2_CONF_MAX_HL_SIZE,
+    H2_CONF_WIN_SIZE,
+    H2_CONF_MIN_WORKERS,
+    H2_CONF_MAX_WORKERS,
+    H2_CONF_MAX_WORKER_IDLE_SECS,
+    H2_CONF_STREAM_MAX_MEM,
+    H2_CONF_ALT_SVCS,
+    H2_CONF_ALT_SVC_MAX_AGE,
+    H2_CONF_SER_HEADERS,
+    H2_CONF_HACK_MPM_EVENT,
+    H2_CONF_DIRECT,
+} h2_config_var_t;
+
+/* Apache httpd module configuration for h2. */
+typedef struct h2_config {
+    const char *name;
+    int h2_enabled;               /* if mod_h2 is active at all here */
+    int h2_max_streams;           /* max concurrent # streams (http2) */
+    int h2_max_hl_size;           /* max header list size (http2) */
+    int h2_window_size;           /* stream window size (http2) */
+    int min_workers;              /* min # of worker threads/child */
+    int max_workers;              /* max # of worker threads/child */
+    int max_worker_idle_secs;     /* max # of idle seconds for worker */
+    int stream_max_mem_size;      /* max # bytes held in memory/stream */
+    apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
+    int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
+    int serialize_headers;        /* Use serialized HTTP/1.1 headers for 
+                                     processing, better compatibility */
+    int hack_mpm_event;           /* If mpm_event is detected, perform a hack
+                                     on stream connections to make it work */
+    int h2_direct;                /* if mod_h2 is active on non-TLS directly */
+} h2_config;
+
+
+void *h2_config_create_dir(apr_pool_t *pool, char *x);
+void *h2_config_create_svr(apr_pool_t *pool, server_rec *s);
+void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv);
+
+apr_status_t h2_config_apply_header(h2_config *config, request_rec *r);
+
+extern const command_rec h2_cmds[];
+
+h2_config *h2_config_get(conn_rec *c);
+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);
+
+#endif /* __mod_h2__h2_config_h__ */
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,543 @@
+/* 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 <ap_mpm.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_log.h>
+#include <http_connection.h>
+#include <http_protocol.h>
+#include <http_request.h>
+
+#include "h2_private.h"
+#include "h2_config.h"
+#include "h2_ctx.h"
+#include "h2_mplx.h"
+#include "h2_session.h"
+#include "h2_stream.h"
+#include "h2_stream_set.h"
+#include "h2_task.h"
+#include "h2_worker.h"
+#include "h2_workers.h"
+#include "h2_conn.h"
+
+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() 
+{
+    if (!checked) {
+        for (int 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;
+            }
+            else if (!strcmp("mod_ssl.c", m->name)) {
+                ssl_module = m;
+            }
+        }
+        checked = 1;
+    }
+}
+
+apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
+{
+    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 max_threads_per_child = 0;
+    ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads_per_child);
+    int threads_limit = 0;
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &threads_limit);
+    
+    if (minw <= 0) {
+        minw = max_threads_per_child;
+    }
+    if (maxw <= 0) {
+        maxw = threads_limit;
+        if (maxw < minw) {
+            maxw = minw;
+        }
+    }
+    
+    for (int 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;
+            /* prefork reports 1 thread per child, also as max */
+            if (maxw == 1) {
+                maxw = 8; /* number of cores maybe? */
+            }
+        }
+        else if (!strcmp("mod_ssl.c", m->name)) {
+            ssl_module = m;
+        }
+    }
+    
+    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);
+    
+    workers = h2_workers_create(s, pool, minw, maxw);
+    int idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
+    h2_workers_set_max_idle_secs(workers, idle_secs);
+    
+    return status;
+}
+
+h2_mpm_type_t h2_conn_mpm_type(void) {
+    check_modules();
+    return mpm_type;
+}
+
+module *h2_conn_mpm_module(void) {
+    check_modules();
+    return mpm_module;
+}
+
+apr_status_t h2_conn_rprocess(request_rec *r)
+{
+    h2_config *config = h2_config_rget(r);
+    
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "h2_conn_process start");
+    if (!workers) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "workers not initialized");
+        return APR_EGENERAL;
+    }
+    
+    h2_session *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);
+    
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_main start");
+    if (!workers) {
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, "workers not initialized");
+        return APR_EGENERAL;
+    }
+    
+    h2_session *session = h2_session_create(c, config, workers);
+    if (!session) {
+        return APR_EGENERAL;
+    }
+    
+    return h2_session_process(session);
+}
+
+apr_status_t h2_session_process(h2_session *session)
+{
+    apr_status_t status = APR_SUCCESS;
+    int rv = 0;
+    
+    /* 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 (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;
+        }
+    }
+    
+    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->local_addr->port);
+    if (status != APR_SUCCESS) {
+        h2_session_abort(session, status, rv);
+        h2_session_destroy(session);
+        return status;
+    }
+    
+    apr_interval_time_t wait_micros = 0;
+    static const int MAX_WAIT_MICROS = 200 * 1000;
+    
+    while (!h2_session_is_done(session)) {
+        int have_written = 0;
+        int have_read = 0;
+        
+        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.
+         */
+        int 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:
+                break;
+            case APR_EBADF:
+            case APR_EOF:
+            case APR_ECONNABORTED:
+            case ECONNRESET:
+                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_WARNING, status, session->c,
+                              "h2_session(%ld): error reading, terminating",
+                              session->id);
+                h2_session_abort(session, status, 0);
+                break;
+        }
+        
+        if (!have_read && !have_written) {
+            /* Nothing to read or write, we may have sessions, 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;
+            }
+        }
+    }
+    
+    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);
+    
+    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)
+{
+    apr_socket_t *socket;
+    
+    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);
+    conn_rec *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,
+                      "h2_task: creating conn");
+        return NULL;
+    }
+    return c;
+}
+
+apr_status_t h2_conn_prep(h2_task_env *env, conn_rec *master, h2_worker *worker)
+{
+    h2_config *cfg = h2_config_get(master);
+    
+    ap_log_perror(APLOG_MARK, APLOG_TRACE3, 0, env->pool,
+                  "h2_conn(%ld): created from master", master->id);
+    
+    /* 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.
+     */
+    env->c.pool = env->pool;
+    env->c.bucket_alloc = h2_worker_get_bucket_alloc(worker);
+    env->c.current_thread = h2_worker_get_thread(worker);
+    
+    env->c.conn_config = ap_create_conn_config(env->pool);
+    env->c.notes = apr_table_make(env->pool, 5);
+
+    ap_set_module_config(env->c.conn_config, &core_module, 
+                         h2_worker_get_socket(worker));
+    
+    if (ssl_module) {
+        /* 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);
+        }
+    }
+    
+    /* This works for mpm_worker so far. Other mpm modules have 
+     * different needs, unfortunately. The most interesting one 
+     * being mpm_event...
+     */
+    switch (h2_conn_mpm_type()) {
+        case H2_MPM_WORKER:
+            /* all fine */
+            break;
+        case H2_MPM_EVENT: 
+            if (h2_config_geti(cfg, H2_CONF_HACK_MPM_EVENT)) {
+                fix_event_conn(&env->c, master);
+            }
+            break;
+        default:
+            /* fingers crossed */
+            break;
+    }
+    
+    return APR_SUCCESS;
+}
+
+apr_status_t h2_conn_setup(struct h2_task_env *env, struct h2_worker *worker)
+{
+    return h2_conn_prep(env, env->mplx->c, worker);
+}
+
+apr_status_t h2_conn_init(struct h2_task_env *env, struct h2_worker *worker)
+{
+    conn_rec *master = env->mplx->c;
+    h2_config *cfg = h2_config_get(master);
+    
+    apr_socket_t *socket = ap_get_module_config(master->conn_config, 
+                                                &core_module);
+    conn_rec *c = ap_run_create_connection(env->pool, master->base_server,
+                                           socket,
+                                           master->id^((long)env->pool), 
+                                           master->sbh,
+                                           master->bucket_alloc);
+    if (c == NULL) {
+        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, env->pool,
+                      "h2_task: creating conn");
+        return APR_ENOMEM;
+    }
+    
+    env->c = *c;
+    env->c.bucket_alloc = h2_worker_get_bucket_alloc(worker);
+    env->c.current_thread = h2_worker_get_thread(worker);
+    
+    ap_set_module_config(env->c.conn_config, &core_module, socket);
+    if (ssl_module) {
+        /* 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);
+        }
+    }
+    
+    /* This works for mpm_worker so far. Other mpm modules have 
+     * different needs, unfortunately. The most interesting one 
+     * being mpm_event...
+     */
+    switch (h2_conn_mpm_type()) {
+        case H2_MPM_WORKER:
+            /* all fine */
+            break;
+        case H2_MPM_EVENT: 
+            if (h2_config_geti(cfg, H2_CONF_HACK_MPM_EVENT)) {
+                fix_event_conn(&env->c, master);
+            }
+            break;
+        default:
+            /* fingers crossed */
+            break;
+    }
+    
+    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);
+    
+    return APR_SUCCESS;
+}
+
+/* This is an internal mpm event.c struct which is disguised
+ * as a conn_state_t so that mpm_event can have special connection
+ * state information without changing the struct seen on the outside.
+ *
+ * For our task connections we need to create a new beast of this type
+ * and fill it with enough meaningful things that mpm_event reads and
+ * starts processing out task request.
+ */
+typedef struct event_conn_state_t event_conn_state_t;
+struct event_conn_state_t {
+    /** APR_RING of expiration timeouts */
+    APR_RING_ENTRY(event_conn_state_t) timeout_list;
+    /** the expiration time of the next keepalive timeout */
+    apr_time_t expiration_time;
+    /** connection record this struct refers to */
+    conn_rec *c;
+    /** request record (if any) this struct refers to */
+    request_rec *r;
+    /** is the current conn_rec suspended?  (disassociated with
+     * a particular MPM thread; for suspend_/resume_connection
+     * hooks)
+     */
+    int suspended;
+    /** memory pool to allocate from */
+    apr_pool_t *p;
+    /** bucket allocator */
+    apr_bucket_alloc_t *bucket_alloc;
+    /** poll file descriptor information */
+    apr_pollfd_t pfd;
+    /** public parts of the connection state */
+    conn_state_t pub;
+};
+APR_RING_HEAD(timeout_head_t, event_conn_state_t);
+
+static void fix_event_conn(conn_rec *c, conn_rec *master) 
+{
+    event_conn_state_t *master_cs = ap_get_module_config(master->conn_config, 
+                                                         h2_conn_mpm_module());
+    event_conn_state_t *cs = apr_pcalloc(c->pool, sizeof(event_conn_state_t));
+    cs->bucket_alloc = apr_bucket_alloc_create(c->pool);
+    
+    ap_set_module_config(c->conn_config, h2_conn_mpm_module(), cs);
+    
+    cs->c = c;
+    cs->r = NULL;
+    cs->p = master_cs->p;
+    cs->pfd = master_cs->pfd;
+    cs->pub = master_cs->pub;
+    cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
+    
+    c->cs = &(cs->pub);
+}
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_conn.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,70 @@
+/* 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_conn__
+#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
+ * conversation. Return when the HTTP/2 session is done
+ * and the connection will close.
+ */
+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);
+
+/* Initialize this child process for h2 connection work,
+ * to be called once during child init before multi processing
+ * starts.
+ */
+apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s);
+
+
+typedef enum {
+    H2_MPM_UNKNOWN,
+    H2_MPM_WORKER,
+    H2_MPM_EVENT,
+    H2_MPM_PREFORK,
+} h2_mpm_type_t;
+
+h2_mpm_type_t h2_conn_mpm_type();
+module *h2_conn_mpm_module();
+
+/* Returns the type of MPM module detected */
+h2_mpm_type_t h2_conn_mpm_type(void);
+
+/* Gives the detected module itself or NULL if unknown */
+module *h2_conn_mpm_module(void);
+
+
+conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *stream_pool);
+
+apr_status_t h2_conn_init(struct h2_task_env *env, struct h2_worker *worker);
+
+apr_status_t h2_conn_setup(struct h2_task_env *env, struct h2_worker *worker);
+apr_status_t h2_conn_prep(struct h2_task_env *env, conn_rec *master, 
+                          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);
+
+#endif /* defined(__mod_h2__h2_conn__) */

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,285 @@
+/* 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 <ap_mpm.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_log.h>
+#include <http_connection.h>
+
+#include "h2_private.h"
+#include "h2_conn_io.h"
+#include "h2_h2.h"
+#include "h2_util.h"
+
+/* If we write directly to our brigade or use a char buffer to collect
+ * out data.
+ */
+
+#define H2_CONN_IO_BUF_SIZE        (64 * 1024)
+#define H2_CONN_IO_SSL_WRITE_SIZE  (16 * 1024)
+
+
+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->buffer_output = h2_h2_is_tls(c);
+    io->buflen = 0;
+    
+    if (io->buffer_output) {
+        io->bufsize = H2_CONN_IO_BUF_SIZE;
+        io->buffer = apr_pcalloc(c->pool, io->bufsize);
+    }
+    else {
+        io->bufsize = 0;
+    }
+    
+    return APR_SUCCESS;
+}
+
+void h2_conn_io_destroy(h2_conn_io *io)
+{
+    io->input = NULL;
+    io->output = NULL;
+}
+
+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) {
+                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);
+                }
+                
+                if (bucket_length > 0) {
+                    apr_size_t consumed = 0;
+                    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);
+        if (status != APR_SUCCESS || done) {
+            return status;
+        }
+        apr_brigade_cleanup(io->input);
+    }
+
+    /* 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);
+    }
+
+    status = ap_get_brigade(io->connection->input_filters,
+                            io->input, AP_MODE_READBYTES,
+                            block, 16 * 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;
+}
+
+static apr_status_t flush_out(apr_bucket_brigade *bb, void *ctx) 
+{
+    h2_conn_io *io = (h2_conn_io*)ctx;
+    
+    ap_update_child_status(io->connection->sbh, SERVER_BUSY_WRITE, NULL);
+    
+    apr_status_t status = ap_pass_brigade(io->connection->output_filters, bb);
+    apr_brigade_cleanup(bb);
+    return status;
+}
+
+static apr_status_t bucketeer_buffer(h2_conn_io *io) {
+    const char *data = io->buffer;
+    apr_size_t remaining = io->buflen;
+    int bcount = (int)(remaining / H2_CONN_IO_SSL_WRITE_SIZE);
+    apr_bucket *b;
+    
+    for (int i = 0; i < bcount; ++i) {
+        b = apr_bucket_transient_create(data, H2_CONN_IO_SSL_WRITE_SIZE, 
+                                        io->output->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(io->output, b);
+        data += H2_CONN_IO_SSL_WRITE_SIZE;
+        remaining -= H2_CONN_IO_SSL_WRITE_SIZE;
+    }
+    
+    if (remaining > 0) {
+        b = apr_bucket_transient_create(data, remaining, 
+                                        io->output->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(io->output, b);
+    }
+    return APR_SUCCESS;
+}
+
+apr_status_t h2_conn_io_write(h2_conn_io *io, 
+                              const char *buf, size_t length)
+{
+    apr_status_t status = APR_SUCCESS;
+    io->unflushed = 1;
+    
+    if (io->buffer_output) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+                      "h2_conn_io: buffering %ld bytes", (long)length);
+        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);
+                io->buflen = 0;
+            }
+            else if (length > avail) {
+                memcpy(io->buffer + io->buflen, buf, avail);
+                io->buflen += avail;
+                length -= avail;
+                buf += avail;
+            }
+            else {
+                memcpy(io->buffer + io->buflen, buf, length);
+                io->buflen += length;
+                length = 0;
+                break;
+            }
+        }
+        
+    }
+    else {
+        status = apr_brigade_write(io->output, flush_out, io, buf, length);
+        if (status == APR_SUCCESS
+            || APR_STATUS_IS_ECONNABORTED(status)
+            || APR_STATUS_IS_EPIPE(status)) {
+            /* These are all fine and no reason for concern. Everything else
+             * is interesting. */
+            status = APR_SUCCESS;
+        }
+        else {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
+                          "h2_conn_io: write error");
+        }
+    }
+    
+    return status;
+}
+
+
+apr_status_t h2_conn_io_flush(h2_conn_io *io)
+{
+    if (io->unflushed) {
+        if (io->buflen > 0) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection,
+                          "h2_conn_io: flush, flushing %ld bytes", \
(long)io->buflen); +            apr_bucket *b = \
apr_bucket_transient_create(io->buffer, io->buflen,  +                                \
io->output->bucket_alloc); +            APR_BRIGADE_INSERT_TAIL(io->output, b);
+            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 */
+        apr_status_t status = flush_out(io->output, io);
+        
+        if (status == APR_SUCCESS
+            || APR_STATUS_IS_ECONNABORTED(status)
+            || APR_STATUS_IS_EPIPE(status)) {
+            /* 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");
+        }
+        
+        return status;
+    }
+    return APR_SUCCESS;
+}
+

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_conn_io.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,55 @@
+/* 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_conn_io__
+#define __mod_h2__h2_conn_io__
+
+/* 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
+ * filters.
+ * The read is done via a callback function, so that input can be processed
+ * directly without copying.
+ */
+typedef struct {
+    conn_rec *connection;
+    apr_bucket_brigade *input;
+    apr_bucket_brigade *output;
+    int buffer_output;
+    
+    char *buffer;
+    apr_size_t buflen;
+    apr_size_t bufsize;
+    int unflushed;
+} 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);
+
+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);
+
+apr_status_t h2_conn_io_flush(h2_conn_io *io);
+
+#endif /* defined(__mod_h2__h2_conn_io__) */

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.c?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.c (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,100 @@
+/* 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_config.h>
+
+#include "h2_private.h"
+#include "h2_task.h"
+#include "h2_ctx.h"
+#include "h2_private.h"
+
+static h2_ctx *h2_ctx_create(conn_rec *c)
+{
+    h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
+    AP_DEBUG_ASSERT(ctx);
+    ctx->pnego_state = H2_PNEGO_NONE;
+    ap_set_module_config(c->conn_config, &h2_module, ctx);
+    return ctx;
+}
+
+h2_ctx *h2_ctx_create_for(conn_rec *c, h2_task_env *env)
+{
+    h2_ctx *ctx = h2_ctx_create(c);
+    if (ctx) {
+        ctx->task_env = env;
+    }
+    return ctx;
+}
+
+h2_ctx *h2_ctx_get(conn_rec *c)
+{
+    h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &h2_module);
+    if (ctx == NULL) {
+        ctx = h2_ctx_create(c);
+    }
+    return ctx;
+}
+
+h2_ctx *h2_ctx_rget(request_rec *r)
+{
+    return h2_ctx_get(r->connection);
+}
+
+const char *h2_ctx_pnego_get(h2_ctx *ctx)
+{
+    return ctx? ctx->protocol : NULL;
+}
+
+void h2_ctx_pnego_set_started(h2_ctx *ctx)
+{
+    ctx->pnego_state = H2_PNEGO_STARTED;
+}
+
+h2_ctx *h2_ctx_pnego_set_done(h2_ctx *ctx, const char *proto)
+{
+    ctx->protocol = proto;
+    ctx->pnego_state = H2_PNEGO_DONE;
+    ctx->is_h2 = (proto != NULL);
+    return ctx;
+}
+
+int h2_ctx_is_task(h2_ctx *ctx)
+{
+    return ctx && !!ctx->task_env;
+}
+
+int h2_ctx_pnego_is_ongoing(h2_ctx *ctx)
+{
+    return ctx && (ctx->pnego_state == H2_PNEGO_STARTED);
+}
+
+int h2_ctx_pnego_is_done(h2_ctx *ctx)
+{
+    return ctx && (ctx->pnego_state == H2_PNEGO_DONE);
+}
+
+int h2_ctx_is_active(h2_ctx *ctx)
+{
+    return ctx && ctx->is_h2;
+}
+
+struct h2_task_env *h2_ctx_get_task(h2_ctx *ctx)
+{
+    return ctx->task_env;
+}

Added: httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.h?rev=1688474&view=auto
 ==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.h (added)
+++ httpd/httpd/trunk/modules/http2/mod_h2/h2_ctx.h Tue Jun 30 15:26:16 2015
@@ -0,0 +1,74 @@
+/* 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_ctx__
+#define __mod_h2__h2_ctx__
+
+struct h2_task_env;
+struct h2_config;
+
+typedef enum {
+    H2_PNEGO_NONE,
+    H2_PNEGO_STARTED,
+    H2_PNEGO_DONE,    
+} h2_pnego_state_t;
+
+/**
+ * The h2 module context associated with a connection. 
+ *
+ * It keeps track of the different types of connections:
+ * - those from clients that use HTTP/2 protocol
+ * - those from clients that do not use HTTP/2
+ * - those created by ourself to perform work on HTTP/2 streams
+ */
+typedef struct h2_ctx {
+    int is_h2;                    /* h2 engine is used */
+    h2_pnego_state_t pnego_state; /* protocol negotiation state */
+    const char *protocol;         /* the protocol negotiated */
+    struct h2_task_env *task_env; /* the h2_task environment 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 */
+} h2_ctx;
+
+h2_ctx *h2_ctx_get(conn_rec *c);
+h2_ctx *h2_ctx_rget(request_rec *r);
+h2_ctx *h2_ctx_create_for(conn_rec *c, struct h2_task_env *env);
+
+
+void h2_ctx_pnego_set_started(h2_ctx *ctx);
+h2_ctx *h2_ctx_pnego_set_done(h2_ctx *ctx, const char *proto);
+/**
+ * Returns != 0 iff protocol negitiation did happen, not matter
+ * what the outcome was.
+ */
+int h2_ctx_pnego_is_done(h2_ctx *ctx);
+/**
+ * Returns != 0 iff protocol negotiation has started but is not
+ * done yet.
+ */
+int h2_ctx_pnego_is_ongoing(h2_ctx *ctx);
+
+/**
+ * Get the h2 protocol negotiated for this connection, or NULL.
+ */
+const char *h2_ctx_pnego_get(h2_ctx *ctx);
+
+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);
+
+#endif /* defined(__mod_h2__h2_ctx__) */


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic