httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ic...@apache.org
Subject svn commit: r1692486 [1/2] - in /httpd/httpd/trunk: docs/log-message-tags/ include/ modules/http2/ modules/ssl/ server/
Date Fri, 24 Jul 2015 12:09:45 GMT
Author: icing
Date: Fri Jul 24 12:09:44 2015
New Revision: 1692486

URL: http://svn.apache.org/r1692486
Log:
new Protocols directive and core API changes to enable protocol switching on HTTP Upgrade or ALPN, implemented in mod_ssl and mod_h2

Added:
    httpd/httpd/trunk/modules/http2/h2_switch.c
      - copied, changed from r1692482, httpd/httpd/trunk/modules/http2/h2_alpn.c
    httpd/httpd/trunk/modules/http2/h2_switch.h
      - copied, changed from r1692482, httpd/httpd/trunk/modules/http2/h2_alpn.h
Removed:
    httpd/httpd/trunk/modules/http2/h2_alpn.c
    httpd/httpd/trunk/modules/http2/h2_alpn.h
    httpd/httpd/trunk/modules/http2/h2_upgrade.c
    httpd/httpd/trunk/modules/http2/h2_upgrade.h
Modified:
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/include/http_core.h
    httpd/httpd/trunk/include/http_protocol.h
    httpd/httpd/trunk/modules/http2/config.m4
    httpd/httpd/trunk/modules/http2/h2_conn.c
    httpd/httpd/trunk/modules/http2/h2_ctx.c
    httpd/httpd/trunk/modules/http2/h2_ctx.h
    httpd/httpd/trunk/modules/http2/h2_from_h1.c
    httpd/httpd/trunk/modules/http2/h2_h2.c
    httpd/httpd/trunk/modules/http2/h2_h2.h
    httpd/httpd/trunk/modules/http2/h2_mplx.c
    httpd/httpd/trunk/modules/http2/h2_request.c
    httpd/httpd/trunk/modules/http2/h2_response.c
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_task.c
    httpd/httpd/trunk/modules/http2/h2_task_input.c
    httpd/httpd/trunk/modules/http2/h2_to_h1.c
    httpd/httpd/trunk/modules/http2/h2_util.c
    httpd/httpd/trunk/modules/http2/h2_util.h
    httpd/httpd/trunk/modules/http2/h2_version.h
    httpd/httpd/trunk/modules/http2/h2_worker.c
    httpd/httpd/trunk/modules/http2/h2_workers.c
    httpd/httpd/trunk/modules/http2/mod_h2.c
    httpd/httpd/trunk/modules/http2/mod_h2.h
    httpd/httpd/trunk/modules/ssl/mod_ssl.c
    httpd/httpd/trunk/modules/ssl/mod_ssl.h
    httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_io.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c
    httpd/httpd/trunk/modules/ssl/ssl_private.h
    httpd/httpd/trunk/server/core.c
    httpd/httpd/trunk/server/protocol.c

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Fri Jul 24 12:09:44 2015
@@ -1 +1 @@
-2905
+2963

Modified: httpd/httpd/trunk/include/http_core.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/http_core.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/include/http_core.h (original)
+++ httpd/httpd/trunk/include/http_core.h Fri Jul 24 12:09:44 2015
@@ -707,6 +707,9 @@ typedef struct {
 #define AP_HTTP_EXPECT_STRICT_ENABLE   1
 #define AP_HTTP_EXPECT_STRICT_DISABLE  2
     int http_expect_strict;
+
+
+    apr_array_header_t *protocols;
 } core_server_config;
 
 /* for AddOutputFiltersByType in core.c */

Modified: httpd/httpd/trunk/include/http_protocol.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/http_protocol.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/include/http_protocol.h (original)
+++ httpd/httpd/trunk/include/http_protocol.h Fri Jul 24 12:09:44 2015
@@ -700,6 +700,109 @@ AP_DECLARE_HOOK(const char *,http_scheme
  */
 AP_DECLARE_HOOK(apr_port_t,default_port,(const request_rec *r))
 
+
+#define AP_PROTOCOL_HTTP1		"http/1.1"
+
+/**
+ * Negotiate a possible protocol switch on the connection. The negotiation
+ * may start without any request sent, in which case the request is NULL. Or
+ * it may be triggered by the request received, e.g. through the "Upgrade"
+ * header.
+ * 
+ * The identifiers for protocols are taken from the TLS extension type ALPN:
+ * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
+ *
+ * If no protocols are added to the proposals, the server will always fallback
+ * to "http/1.1" which is the default protocol for connections that Apache
+ * handles. If the protocol selected from the proposals is the protocol
+ * already in place, no "protocol_switch" will be invoked.
+ *
+ * All hooks are run, unless one returns an error. Proposals may contain
+ * duplicates. The order in which proposals are added is usually ignored.
+ * 
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected
+ * @param offers a list of protocol identifiers offered by the client
+ * @param proposals the list of protocol identifiers proposed by the hooks
+ * @return OK or DECLINED
+ */
+AP_DECLARE_HOOK(int,protocol_propose,(conn_rec *c, request_rec *r,
+                                      server_rec *s,
+                                      const apr_array_header_t *offers,
+                                      apr_array_header_t *proposals))
+
+/**
+ * Perform a protocol switch on the connection. The exact requirements for
+ * that depend on the protocol in place and the one switched to. The first 
+ * protocol module to handle the switch is the last module run.
+ * 
+ * For a connection level switch (r == NULL), the handler must on return
+ * leave the conn_rec in a state suitable for processing the switched
+ * protocol, e.g. correct filters in place.
+ *
+ * For a request triggered switch (r != NULL), the protocol switch is done
+ * before the response is sent out. When switching from "http/1.1" via Upgrade
+ * header, the 101 intermediate response will have been sent. The
+ * hook needs then to process the connection until it can be closed. Which
+ * the server will enforce on hook return.
+ * Any error the hook might encounter must already be sent by the hook itself
+ * to the client in whatever form the new protocol requires.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected
+ * @param choices a list of protocol identifiers, normally the clients whishes
+ * @param proposals the list of protocol identifiers proposed by the hooks
+ * @return OK or DECLINED
+ */
+AP_DECLARE_HOOK(int,protocol_switch,(conn_rec *c, request_rec *r,
+                                     server_rec *s,
+                                     const char *protocol))
+
+/**
+ * Return the protocol used on the connection. Modules implementing
+ * protocol switching must register here and return the correct protocol
+ * identifier for connections they switched.
+ *
+ * @param c The current connection
+ * @return The identifier of the protocol in place
+ */
+AP_DECLARE_HOOK(const char *,protocol_get,(const conn_rec *c))
+    
+/**
+ * Select a protocol for the given connection and optional request. Will return
+ * the protocol identifier selected which may be the protocol already in place
+ * on the connection. The server may ignore the choices given.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected
+ * @param choices a list of protocol identifiers, normally the clients whishes
+ * @return the selected protocol
+ */
+AP_DECLARE(const char *) ap_select_protocol(conn_rec *c, request_rec *r, 
+                                            server_rec *s,
+                                            apr_array_header_t *choices);
+
+/**
+ * Perform the actual protocol switch. The protocol given must have been
+ * selected before on the very same connection and request pair.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected
+ * @param protocol the protocol to switch to
+ * @return APR_SUCCESS, if caller may continue processing as usual
+ *         APR_EOF,     if caller needs to stop processing the connection
+ *         APR_EINVAL,  if the protocol is already in place
+ *         APR_NOTIMPL, if no module performed the switch
+ *         Other errors where appropriate
+ */
+AP_DECLARE(apr_status_t) ap_switch_protocol(conn_rec *c, request_rec *r, 
+                                            server_rec *s,
+                                            const char *protocol);
+
 /** @see ap_bucket_type_error */
 typedef struct ap_bucket_error ap_bucket_error;
 

Modified: httpd/httpd/trunk/modules/http2/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/config.m4?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/config.m4 (original)
+++ httpd/httpd/trunk/modules/http2/config.m4 Fri Jul 24 12:09:44 2015
@@ -19,7 +19,6 @@ APACHE_MODPATH_INIT(http2)
 dnl #  list of module object files
 h2_objs="dnl
 mod_h2.lo dnl
-h2_alpn.lo dnl
 h2_alt_svc.lo dnl
 h2_config.lo dnl
 h2_conn.lo dnl
@@ -35,12 +34,12 @@ h2_response.lo dnl
 h2_session.lo dnl
 h2_stream.lo dnl
 h2_stream_set.lo dnl
+h2_switch.lo dnl
 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_upgrade.lo dnl
 h2_util.lo dnl
 h2_worker.lo dnl
 h2_workers.lo dnl

Modified: httpd/httpd/trunk/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_conn.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_conn.c Fri Jul 24 12:09:44 2015
@@ -144,7 +144,8 @@ apr_status_t h2_conn_rprocess(request_re
     
     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");
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02911) 
+                      "workers not initialized");
         return APR_EGENERAL;
     }
     
@@ -163,7 +164,8 @@ apr_status_t h2_conn_main(conn_rec *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");
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02912) 
+                      "workers not initialized");
         return APR_EGENERAL;
     }
     
@@ -293,6 +295,7 @@ apr_status_t h2_session_process(h2_sessi
                 break;
             default:
                 ap_log_cerror( APLOG_MARK, APLOG_WARNING, status, session->c,
+                              APLOGNO(02950) 
                               "h2_session(%ld): error reading, terminating",
                               session->id);
                 h2_session_abort(session, status, 0);
@@ -353,8 +356,8 @@ conn_rec *h2_conn_create(conn_rec *maste
                                            master->sbh,
                                            master->bucket_alloc);
     if (c == NULL) {
-        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool,
-                      "h2_task: creating conn");
+        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool, 
+                      APLOGNO(02913) "h2_task: creating conn");
         return NULL;
     }
     /* TODO: we simulate that we had already a request on this connection.
@@ -440,7 +443,7 @@ apr_status_t h2_conn_init(struct h2_task
                                            master->bucket_alloc);
     if (c == NULL) {
         ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, env->pool,
-                      "h2_task: creating conn");
+                      APLOGNO(02914) "h2_task: creating conn");
         return APR_ENOMEM;
     }
     

Modified: httpd/httpd/trunk/modules/http2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_ctx.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_ctx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_ctx.c Fri Jul 24 12:09:44 2015
@@ -24,7 +24,7 @@
 #include "h2_ctx.h"
 #include "h2_private.h"
 
-static h2_ctx *h2_ctx_create(conn_rec *c)
+static h2_ctx *h2_ctx_create(const conn_rec *c)
 {
     h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
     AP_DEBUG_ASSERT(ctx);
@@ -33,7 +33,7 @@ static h2_ctx *h2_ctx_create(conn_rec *c
     return ctx;
 }
 
-h2_ctx *h2_ctx_create_for(conn_rec *c, h2_task_env *env)
+h2_ctx *h2_ctx_create_for(const conn_rec *c, h2_task_env *env)
 {
     h2_ctx *ctx = h2_ctx_create(c);
     if (ctx) {
@@ -42,7 +42,7 @@ h2_ctx *h2_ctx_create_for(conn_rec *c, h
     return ctx;
 }
 
-h2_ctx *h2_ctx_get(conn_rec *c)
+h2_ctx *h2_ctx_get(const conn_rec *c)
 {
     h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &h2_module);
     if (ctx == NULL) {
@@ -51,22 +51,18 @@ h2_ctx *h2_ctx_get(conn_rec *c)
     return ctx;
 }
 
-h2_ctx *h2_ctx_rget(request_rec *r)
+h2_ctx *h2_ctx_rget(const request_rec *r)
 {
     return h2_ctx_get(r->connection);
 }
 
-const char *h2_ctx_pnego_get(h2_ctx *ctx)
+const char *h2_ctx_protocol_get(const conn_rec *c)
 {
+    h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &h2_module);
     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)
+h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto)
 {
     ctx->protocol = proto;
     ctx->pnego_state = H2_PNEGO_DONE;
@@ -84,11 +80,6 @@ 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;

Modified: httpd/httpd/trunk/modules/http2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_ctx.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_ctx.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_ctx.h Fri Jul 24 12:09:44 2015
@@ -43,18 +43,16 @@ typedef struct h2_ctx {
     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);
+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);
 
 
-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.
+/* Set the h2 protocol established on this connection context or
+ * NULL when other protocols are in place.
  */
-int h2_ctx_pnego_is_done(h2_ctx *ctx);
+h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto);
+
 /**
  * Returns != 0 iff protocol negotiation has started but is not
  * done yet.
@@ -64,7 +62,7 @@ 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);
+const char *h2_ctx_protocol_get(const conn_rec *c);
 
 int h2_ctx_is_task(h2_ctx *ctx);
 int h2_ctx_is_active(h2_ctx *ctx);

Modified: httpd/httpd/trunk/modules/http2/h2_from_h1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_from_h1.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_from_h1.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_from_h1.c Fri Jul 24 12:09:44 2015
@@ -83,6 +83,7 @@ static apr_status_t make_h2_headers(h2_f
                                        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;

Modified: httpd/httpd/trunk/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.c Fri Jul 24 12:09:44 2015
@@ -33,20 +33,15 @@
 #include "h2_config.h"
 #include "h2_ctx.h"
 #include "h2_conn.h"
-#include "h2_alpn.h"
 #include "h2_h2.h"
 
-const char *h2_alpn_protos[] = {
-    "h2",
+const char *h2_tls_protos[] = {
+    "h2", NULL
 };
-apr_size_t h2_alpn_protos_len = (sizeof(h2_alpn_protos)
-                                 / sizeof(h2_alpn_protos[0]));
 
-const char *h2_upgrade_protos[] = {
-    "h2c",
+const char *h2_clear_protos[] = {
+    "h2c", NULL
 };
-apr_size_t h2_upgrade_protos_len = (sizeof(h2_upgrade_protos)
-                                    / sizeof(h2_upgrade_protos[0]));
 
 const char *H2_MAGIC_TOKEN = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
 
@@ -80,7 +75,7 @@ apr_status_t h2_h2_init(apr_pool_t *pool
     
     if (!opt_ssl_is_https) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
-                     "mod_ssl does not seem to be enabled");
+                     APLOGNO(02951) "mod_ssl does not seem to be enabled");
     }
     
     return APR_SUCCESS;
@@ -107,7 +102,7 @@ static const char *const mod_reqtimeout[
 void h2_h2_register_hooks(void)
 {
     /* When the connection processing actually starts, we might to
-     * take over, if h2* was selected by ALPN on a TLS connection.
+     * take over, if h2* was selected as protocol.
      */
     ap_hook_process_connection(h2_h2_process_conn, 
                                NULL, NULL, APR_HOOK_FIRST);
@@ -156,7 +151,7 @@ int h2_h2_process_conn(conn_rec* c)
     apr_bucket_brigade* temp;
 
     if (h2_ctx_is_task(ctx)) {
-        /* out stream pseudo connection */
+        /* our stream pseudo connection */
         return DECLINED;
     }
 
@@ -170,15 +165,19 @@ int h2_h2_process_conn(conn_rec* c)
         apr_brigade_destroy(temp);
     }
 
-    /* If we still do not know the protocol and H2Direct is enabled, check
-     * if we receive the magic PRIamble. A client sending this on connection
-     * start should know what it is doing.
+    /* If we have not already switched to a h2* protocol 
+     * and the connection is on "http/1.1"
+     * and H2Direct is enabled, 
+     * -> sniff for the magic PRIamble. A client sending this on connection
+     *    start should know what it is doing.
      */
-    if (!h2_ctx_pnego_is_done(ctx) && h2_config_geti(cfg, H2_CONF_DIRECT)) {
+    if (!h2_ctx_protocol_get(c) 
+        && !strcmp(AP_PROTOCOL_HTTP1, ap_run_protocol_get(c))
+        && h2_config_geti(cfg, H2_CONF_DIRECT)) {
         apr_status_t status;
         temp = apr_brigade_create(c->pool, c->bucket_alloc);
         status = ap_get_brigade(c->input_filters, temp,
-                                /*h2_h2_is_tls(c)? AP_MODE_READBYTES :*/ AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24);
+                                AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24);
         if (status == APR_SUCCESS) {
             char *s = NULL;
             apr_size_t slen;
@@ -187,7 +186,7 @@ int h2_h2_process_conn(conn_rec* c)
             if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                               "h2_h2, direct mode detected");
-                h2_ctx_pnego_set_done(ctx, "h2");
+                h2_ctx_protocol_set(ctx, "h2");
             }
             else {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,

Modified: httpd/httpd/trunk/modules/http2/h2_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.h Fri Jul 24 12:09:44 2015
@@ -17,18 +17,16 @@
 #define __mod_h2__h2_h2__
 
 /**
- * List of ALPN protocol identifiers that we support in ALPN/NPN 
- * negotiations.
+ * List of ALPN protocol identifiers that we suport in cleartext
+ * negotiations. NULL terminated.
  */
-extern const char *h2_alpn_protos[];
-extern apr_size_t h2_alpn_protos_len;
+extern const char *h2_clear_protos[];
 
 /**
- * List of ALPN protocol identifiers that we suport in HTTP/1 Upgrade:
- * negotiations.
+ * List of ALPN protocol identifiers that we support in TLS encrypted 
+ * negotiations. NULL terminated.
  */
-extern const char *h2_upgrade_protos[];
-extern apr_size_t h2_upgrade_protos_len;
+extern const char *h2_tls_protos[];
 
 /**
  * The magic PRIamble of RFC 7540 that is always sent when starting

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Fri Jul 24 12:09:44 2015
@@ -199,6 +199,7 @@ apr_status_t h2_mplx_release_and_join(h2
             apr_thread_cond_timedwait(wait, m->lock, apr_time_from_sec(10));
             if (++attempts >= 6) {
                 ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c,
+                              APLOGNO(02952) 
                               "h2_mplx(%ld): join attempts exhausted, refs=%d", 
                               m->id, m->refs);
                 break;
@@ -497,7 +498,7 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
             }
             else {
                 ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_NOTFOUND, m->c,
-                              "h2_mplx(%ld): stream for response %d",
+                              APLOGNO(02953) "h2_mplx(%ld): stream for response %d",
                               m->id, response->stream_id);
             }
         }
@@ -785,7 +786,7 @@ apr_status_t h2_mplx_create_task(h2_mplx
         conn_rec *c = h2_conn_create(m->c, stream->pool);
         if (c == NULL) {
             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, m->c,
-                          "h2_mplx(%ld-%d): start stream",
+                          APLOGNO(02916) "h2_mplx(%ld-%d): start stream",
                           m->id, stream->id);
             return APR_ENOMEM;
         }

Modified: httpd/httpd/trunk/modules/http2/h2_request.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_request.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_request.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_request.c Fri Jul 24 12:09:44 2015
@@ -92,6 +92,7 @@ apr_status_t h2_request_write_header(h2_
         /* pseudo header, see ch. 8.1.2.3, always should come first */
         if (req->to_h1) {
             ap_log_perror(APLOG_MARK, APLOG_ERR, 0, req->pool,
+                          APLOGNO(02917) 
                           "h2_request(%d): pseudo header after request start",
                           req->id);
             return APR_EGENERAL;
@@ -118,6 +119,7 @@ apr_status_t h2_request_write_header(h2_
             memset(buffer, 0, 32);
             strncpy(buffer, name, (nlen > 31)? 31 : nlen);
             ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, req->pool,
+                          APLOGNO(02954) 
                           "h2_request(%d): ignoring unknown pseudo header %s",
                           req->id, buffer);
         }

Modified: httpd/httpd/trunk/modules/http2/h2_response.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_response.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_response.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_response.c Fri Jul 24 12:09:44 2015
@@ -61,7 +61,7 @@ h2_response *h2_response_create(int stre
             char *sep = strchr(hline, ':');
             if (!sep) {
                 ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
-                              "h2_response(%d): invalid header[%d] '%s'",
+                              APLOGNO(02955) "h2_response(%d): invalid header[%d] '%s'",
                               response->stream_id, i, (char*)hline);
                 /* not valid format, abort */
                 return NULL;
@@ -80,7 +80,8 @@ h2_response *h2_response_create(int stre
                     response->content_length = apr_strtoi64(sep, &end, 10);
                     if (sep == end) {
                         ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, 
-                                      pool, "h2_response(%d): content-length"
+                                      pool, APLOGNO(02956) 
+                                      "h2_response(%d): content-length"
                                       " value not parsed: %s", 
                                       response->stream_id, sep);
                         response->content_length = -1;
@@ -199,7 +200,7 @@ static int add_header(void *ctx, const c
     if (!ignore_header(key)) {
         nvctx_t *nvctx = (nvctx_t*)ctx;
         if (nvctx->debug) {
-            ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, 
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, 
                           nvctx->r, "h2_response(%d) header -> %s: %s",
                           nvctx->response->stream_id, key, value);
         }

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Fri Jul 24 12:09:44 2015
@@ -73,6 +73,7 @@ static int stream_open(h2_session *sessi
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, session->c,
+                  APLOGNO(02918) 
                   "h2_session: stream(%ld-%d): unable to create",
                   session->id, stream_id);
     return NGHTTP2_ERR_INVALID_STREAM_ID;
@@ -145,6 +146,7 @@ static int on_data_chunk_recv_cb(nghttp2
     stream = h2_stream_set_get(session->streams, stream_id);
     if (!stream) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
+                      APLOGNO(02919) 
                       "h2_session:  stream(%ld-%d): on_data_chunk for unknown stream",
                       session->id, (int)stream_id);
         rv = nghttp2_submit_rst_stream(ngh2, NGHTTP2_FLAG_NONE, stream_id,
@@ -279,6 +281,7 @@ static int on_header_cb(nghttp2_session
                                            frame->hd.stream_id);
     if (!stream) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
+                      APLOGNO(02920) 
                       "h2_session:  stream(%ld-%d): on_header for unknown stream",
                       session->id, (int)frame->hd.stream_id);
         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
@@ -320,6 +323,7 @@ static int on_frame_recv_cb(nghttp2_sess
                                                    frame->hd.stream_id);
             if (stream == NULL) {
                 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
+                              APLOGNO(02921) 
                               "h2_session:  stream(%ld-%d): HEADERS frame "
                               "for unknown stream", session->id,
                               (int)frame->hd.stream_id);
@@ -342,6 +346,7 @@ static int on_frame_recv_cb(nghttp2_sess
                                                    frame->hd.stream_id);
             if (stream == NULL) {
                 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
+                              APLOGNO(02922) 
                               "h2_session:  stream(%ld-%d): DATA frame "
                               "for unknown stream", session->id,
                               (int)frame->hd.stream_id);
@@ -394,6 +399,7 @@ static int on_frame_recv_cb(nghttp2_sess
     
     if (status != APR_SUCCESS) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
+                      APLOGNO(02923) 
                       "h2_session: stream(%ld-%d): error handling frame",
                       session->id, (int)frame->hd.stream_id);
         rv = nghttp2_submit_rst_stream(ng2s, NGHTTP2_FLAG_NONE,
@@ -443,6 +449,7 @@ static int on_send_data_cb(nghttp2_sessi
     stream = h2_stream_set_get(session->streams, stream_id);
     if (!stream) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_NOTFOUND, session->c,
+                      APLOGNO(02924) 
                       "h2_stream(%ld-%d): send_data",
                       session->id, (int)stream_id);
         return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -477,6 +484,7 @@ static int on_send_data_cb(nghttp2_sessi
     }
     else if (status != APR_EOF) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
+                      APLOGNO(02925) 
                       "h2_stream(%ld-%d): failed send_data_cb",
                       session->id, (int)stream_id);
         return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -494,7 +502,7 @@ static apr_status_t init_callbacks(conn_
     int rv = nghttp2_session_callbacks_new(pcb);
     if (rv != 0) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
-                      "nghttp2_session_callbacks_new: %s",
+                      APLOGNO(02926) "nghttp2_session_callbacks_new: %s",
                       nghttp2_strerror(rv));
         return APR_EGENERAL;
     }
@@ -556,7 +564,7 @@ static h2_session *h2_session_create_int
         
         status = init_callbacks(c, &callbacks);
         if (status != APR_SUCCESS) {
-            ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c,
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, APLOGNO(02927) 
                           "nghttp2: error in init_callbacks");
             h2_session_destroy(session);
             return NULL;
@@ -565,7 +573,8 @@ static h2_session *h2_session_create_int
         rv = nghttp2_option_new(&options);
         if (rv != 0) {
             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
-                          "nghttp2_option_new: %s", nghttp2_strerror(rv));
+                          APLOGNO(02928) "nghttp2_option_new: %s", 
+                          nghttp2_strerror(rv));
             h2_session_destroy(session);
             return NULL;
         }
@@ -584,7 +593,7 @@ static h2_session *h2_session_create_int
         
         if (rv != 0) {
             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
-                          "nghttp2_session_server_new: %s",
+                          APLOGNO(02929) "nghttp2_session_server_new: %s",
                           nghttp2_strerror(rv));
             h2_session_destroy(session);
             return NULL;
@@ -660,7 +669,7 @@ apr_status_t h2_session_goaway(h2_sessio
     if (rv != 0) {
         status = APR_EGENERAL;
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
-                      "session(%ld): submit goaway: %s",
+                    APLOGNO(02930) "session(%ld): submit goaway: %s",
                       session->id, nghttp2_strerror(rv));
     }
     return status;
@@ -733,6 +742,7 @@ apr_status_t h2_session_start(h2_session
         s = apr_table_get(session->r->headers_in, "HTTP2-Settings");
         if (!s) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r,
+                          APLOGNO(02931) 
                           "HTTP2-Settings header missing in request");
             return APR_EINVAL;
         }
@@ -751,7 +761,8 @@ apr_status_t h2_session_start(h2_session
         if (*rv != 0) {
             status = APR_EINVAL;
             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
-                          "nghttp2_session_upgrade: %s", nghttp2_strerror(*rv));
+                          APLOGNO(02932) "nghttp2_session_upgrade: %s", 
+                          nghttp2_strerror(*rv));
             return status;
         }
         
@@ -760,7 +771,8 @@ apr_status_t h2_session_start(h2_session
         if (*rv != 0) {
             status = APR_EGENERAL;
             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
-                          "open stream 1: %s", nghttp2_strerror(*rv));
+                          APLOGNO(02933) "open stream 1: %s", 
+                          nghttp2_strerror(*rv));
             return status;
         }
         
@@ -768,7 +780,7 @@ apr_status_t h2_session_start(h2_session
         if (stream == NULL) {
             status = APR_EGENERAL;
             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
-                          "lookup of stream 1");
+                          APLOGNO(02934) "lookup of stream 1");
             return status;
         }
         
@@ -795,7 +807,8 @@ apr_status_t h2_session_start(h2_session
     if (*rv != 0) {
         status = APR_EGENERAL;
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
-                      "nghttp2_submit_settings: %s", nghttp2_strerror(*rv));
+                      APLOGNO(02935) "nghttp2_submit_settings: %s", 
+                      nghttp2_strerror(*rv));
     }
     
     return status;
@@ -826,6 +839,7 @@ static int resume_on_data(void *ctx, h2_
             rv = nghttp2_session_resume_data(session->ngh2, stream->id);
             ap_log_cerror(APLOG_MARK, nghttp2_is_fatal(rv)?
                           APLOG_ERR : APLOG_DEBUG, 0, session->c,
+                          APLOGNO(02936) 
                           "h2_stream(%ld-%d): resuming stream %s",
                           session->id, stream->id, nghttp2_strerror(rv));
         }
@@ -1002,6 +1016,7 @@ static ssize_t stream_data_cb(nghttp2_se
     stream = h2_stream_set_get(session->streams, stream_id);
     if (!stream) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_NOTFOUND, session->c,
+                      APLOGNO(02937) 
                       "h2_stream(%ld-%d): data requested but stream not found",
                       session->id, (int)stream_id);
         return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1038,7 +1053,7 @@ static ssize_t stream_data_cb(nghttp2_se
         default:
             nread = 0;
             ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
-                          "h2_stream(%ld-%d): reading data",
+                          APLOGNO(02938) "h2_stream(%ld-%d): reading data",
                           session->id, (int)stream_id);
             return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
@@ -1074,7 +1089,7 @@ static int submit_response(h2_session *s
     
     if (rv != 0) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
-                      "h2_stream(%ld-%d): submit_response: %s",
+                      APLOGNO(02939) "h2_stream(%ld-%d): submit_response: %s",
                       session->id, response->stream_id, nghttp2_strerror(rv));
     }
     else {
@@ -1110,7 +1125,8 @@ apr_status_t h2_session_handle_response(
         status = APR_EGENERAL;
         h2_session_abort_int(session, rv);
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
-                      "submit_response: %s", nghttp2_strerror(rv));
+                      APLOGNO(02940) "submit_response: %s", 
+                      nghttp2_strerror(rv));
     }
     return status;
 }

Copied: httpd/httpd/trunk/modules/http2/h2_switch.c (from r1692482, httpd/httpd/trunk/modules/http2/h2_alpn.c)
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_switch.c?p2=httpd/httpd/trunk/modules/http2/h2_switch.c&p1=httpd/httpd/trunk/modules/http2/h2_alpn.c&r1=1692482&r2=1692486&rev=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_alpn.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_switch.c Fri Jul 24 12:09:44 2015
@@ -32,7 +32,7 @@
 #include "h2_ctx.h"
 #include "h2_conn.h"
 #include "h2_h2.h"
-#include "h2_alpn.h"
+#include "h2_switch.h"
 
 /*******************************************************************************
  * SSL var lookup
@@ -46,102 +46,21 @@ static char *(*opt_ssl_var_lookup)(apr_p
                                    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)
+apr_status_t h2_switch_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);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "h2_switch init");
     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)
+static int h2_util_array_index(const apr_array_header_t *array, const char *s)
 {
     int i;
     for (i = 0; i < array->nelts; i++) {
@@ -153,147 +72,130 @@ static int h2_util_array_index(apr_array
     return -1;
 }
 
-static int h2_npn_advertise(conn_rec *c, apr_array_header_t *protos)
+static int h2_protocol_propose(conn_rec *c, request_rec *r,
+                               server_rec *s,
+                               const apr_array_header_t *offers,
+                               apr_array_header_t *proposals)
 {
     h2_config *cfg;
-    apr_size_t i;
+    int proposed = 0;
+    const char **protos = h2_h2_is_tls(c)? h2_tls_protos : h2_clear_protos;
     
-    check_sni_host(c);
-    cfg = h2_config_get(c);
-    if (!h2_config_geti(cfg, H2_CONF_ENABLED)) {
-        return DECLINED;
-    }
-    
-    for (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);
-    apr_size_t i;
-
-    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...
+    if (strcmp(AP_PROTOCOL_HTTP1, ap_run_protocol_get(c))) {
+        /* We do not know how to switch from anything else but http/1.1.
          */
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                      "protocol negotiated via %s called, but already set", 
-                      via); 
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                      "protocol switch: current proto != http/1.1, declined");
         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));
-    }
+    cfg = h2_config_sget(s);
     
-    for (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;
-    apr_size_t i;
-    
-    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);
+                      "protocol 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 (i = 0; i < h2_alpn_protos_len; ++i) {
-        const char *proto = h2_alpn_protos[i];
-        if (h2_util_array_index(client_protos, proto) >= 0) {
+    if (r) {
+        const char *p;
+        /* So far, this indicates an HTTP/1 Upgrade header initiated
+         * protocol switch. For that, the HTTP2-Settings header needs
+         * to be present and valid for the connection.
+         */
+        p = apr_table_get(r->headers_in, "HTTP2-Settings");
+        if (!p) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "upgrade without HTTP2-Settings declined");
+            return DECLINED;
+        }
+        
+        p = apr_table_get(r->headers_in, "Connection");
+        if (!ap_find_token(r->pool, p, "http2-settings")) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "upgrade without HTTP2-Settings declined");
+            return DECLINED;
+        }
+        
+        /* We also allow switching only for requests that have no body.
+         */
+        p = apr_table_get(r->headers_in, "Content-Length");
+        if (p && strcmp(p, "0")) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "upgrade with content-length: %s, declined", p);
+            return DECLINED;
+        }
+    }
+    
+    while (*protos) {
+        /* Add all protocols we know (tls or clear) and that
+         * were offered as options for the switch. 
+         */
+        if (h2_util_array_index(offers, *protos) >= 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 */
+                          "proposing protocol '%s'", *protos);
+            APR_ARRAY_PUSH(proposals, const char*) = *protos;
+            proposed = 1;
         }
+        ++protos;
     }
-    return OK;
+    return proposed? DECLINED : 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)
+static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
+                              const char *protocol)
 {
-    h2_ctx *ctx = h2_ctx_get(c);
-
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                  "h2_h2, pre_connection, start");
+    int found = 0;
+    const char **protos = h2_h2_is_tls(c)? h2_tls_protos : h2_clear_protos;
+    const char **p = protos;
     
-    if (h2_ctx_is_task(ctx)) {
-        /* our stream pseudo connection */
-        return DECLINED;
+    while (*p) {
+        if (!strcmp(*p, protocol)) {
+            found = 1;
+            break;
+        }
+        p++;
     }
     
-    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 (found) {
+        h2_ctx *ctx = h2_ctx_get(c);
+        h2_ctx_protocol_set(ctx, protocol);
         
-        if (opt_ssl_register_alpn) {
-            opt_ssl_register_alpn(c, h2_alpn_propose, h2_alpn_negotiated);
+        if (r != NULL) {
+            /* Switching in the middle of a request means that
+             * we have to send out the response to this one in h2
+             * format. So we need to take over the connection
+             * right away.
+             */
+            ap_remove_input_filter_byhandle(r->input_filters, "http_in");
+            ap_remove_input_filter_byhandle(r->input_filters, "reqtimeout");
+            
+            /* Ok, start an h2_conn on this one. */
+            apr_status_t status = h2_conn_rprocess(r);
+            if (status != DONE) {
+                /* Nothing really to do about this. */
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
+                              "session proessed, unexpected status");
+            }
         }
-        if (opt_ssl_register_npn) {
-            opt_ssl_register_npn(c, h2_npn_advertise, h2_npn_negotiated);
+        else {
+            
         }
-        
-        h2_ctx_pnego_set_started(ctx);
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                      "h2_alpn, pre_connection, ALPN callback registered");
+        return DONE;
     }
     
     return DECLINED;
 }
 
+static const char *h2_protocol_get(const conn_rec *c)
+{
+    return h2_ctx_protocol_get(c);
+}
+
+void h2_switch_register_hooks(void)
+{
+    ap_hook_protocol_propose(h2_protocol_propose, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_protocol_switch(h2_protocol_switch, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_protocol_get(h2_protocol_get, NULL, NULL, APR_HOOK_MIDDLE);
+}
+

Copied: httpd/httpd/trunk/modules/http2/h2_switch.h (from r1692482, httpd/httpd/trunk/modules/http2/h2_alpn.h)
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_switch.h?p2=httpd/httpd/trunk/modules/http2/h2_switch.h&p1=httpd/httpd/trunk/modules/http2/h2_alpn.h&r1=1692482&r2=1692486&rev=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_alpn.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_switch.h Fri Jul 24 12:09:44 2015
@@ -13,17 +13,17 @@
  * limitations under the License.
  */
 
-#ifndef __mod_h2__h2_alpn__
-#define __mod_h2__h2_alpn__
+#ifndef __mod_h2__h2_switch__
+#define __mod_h2__h2_switch__
 
 /*
  * One time, post config intialization.
  */
-apr_status_t h2_alpn_init(apr_pool_t *pool, server_rec *s);
+apr_status_t h2_switch_init(apr_pool_t *pool, server_rec *s);
 
-/* Register apache hooks for ALPN protocol
+/* Register apache hooks for protocol switching
  */
-void h2_alpn_register_hooks(void);
+void h2_switch_register_hooks(void);
 
 
-#endif /* defined(__mod_h2__h2_h2__) */
+#endif /* defined(__mod_h2__h2_switch__) */

Modified: httpd/httpd/trunk/modules/http2/h2_task.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_task.c Fri Jul 24 12:09:44 2015
@@ -162,7 +162,7 @@ h2_task *h2_task_create(long session_id,
     h2_task *task = apr_pcalloc(stream_pool, sizeof(h2_task));
     if (task == NULL) {
         ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, stream_pool,
-                      "h2_task(%ld-%d): create stream task", 
+                      APLOGNO(02941) "h2_task(%ld-%d): create stream task", 
                       session_id, stream_id);
         h2_mplx_out_close(mplx, stream_id);
         return NULL;
@@ -256,7 +256,8 @@ apr_status_t h2_task_do(h2_task *task, h
     }
     else {
         ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, &env.c,
-                      "h2_task(%s): error setting up h2_task_env", env.id);
+                      APLOGNO(02957) "h2_task(%s): error setting up h2_task_env", 
+                      env.id);
     }
     
     if (env.input) {

Modified: httpd/httpd/trunk/modules/http2/h2_task_input.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task_input.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task_input.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_task_input.c Fri Jul 24 12:09:44 2015
@@ -117,7 +117,7 @@ apr_status_t h2_task_input_read(h2_task_
         status = apr_brigade_length(input->bb, 1, &bblen);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, f->c,
-                          "h2_task_input(%s): brigade length fail", 
+                          APLOGNO(02958) "h2_task_input(%s): brigade length fail", 
                           input->env->id);
             return status;
         }
@@ -201,8 +201,8 @@ apr_status_t h2_task_input_read(h2_task_
             /* Hmm, well. There is mode AP_MODE_EATCRLF, but we chose not
              * to support it. Seems to work. */
             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOTIMPL, f->c,
-                          "h2_task_input, unsupported READ mode %d",
-                          mode);
+                          APLOGNO(02942) 
+                          "h2_task_input, unsupported READ mode %d", mode);
             return APR_ENOTIMPL;
         }
     }

Modified: httpd/httpd/trunk/modules/http2/h2_to_h1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_to_h1.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_to_h1.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_to_h1.c Fri Jul 24 12:09:44 2015
@@ -39,11 +39,13 @@ h2_to_h1 *h2_to_h1_create(int stream_id,
     h2_to_h1 *to_h1;
     if (!method) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, m->c,
+                      APLOGNO(02943) 
                       "h2_to_h1: header start but :method missing");
         return NULL;
     }
     if (!path) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, m->c,
+                      APLOGNO(02944) 
                       "h2_to_h1: header start but :path missing");
         return NULL;
     }
@@ -78,6 +80,7 @@ apr_status_t h2_to_h1_add_header(h2_to_h
         if (!apr_strnatcasecmp("chunked", value)) {
             /* This should never arrive here in a HTTP/2 request */
             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_BADARG, to_h1->m->c,
+                          APLOGNO(02945) 
                           "h2_to_h1: 'transfer-encoding: chunked' received");
             return APR_BADARG;
         }
@@ -87,6 +90,7 @@ apr_status_t h2_to_h1_add_header(h2_to_h
         to_h1->content_len = apr_strtoi64(value, &end, 10);
         if (value == end) {
             ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, to_h1->m->c,
+                          APLOGNO(02959) 
                           "h2_request(%d): content-length value not parsed: %s",
                           to_h1->stream_id, value);
             return APR_EINVAL;
@@ -187,6 +191,7 @@ apr_status_t h2_to_h1_end_headers(h2_to_
         apr_status_t status = h2_to_h1_close(to_h1);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, to_h1->m->c,
+                          APLOGNO(02960) 
                           "h2_to_h1(%ld-%d): end headers, eos=%d", 
                           to_h1->m->id, to_h1->stream_id, eos);
         }
@@ -243,6 +248,7 @@ apr_status_t h2_to_h1_add_data(h2_to_h1
         to_h1->remain_len -= len;
         if (to_h1->remain_len < 0) {
             ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, to_h1->m->c,
+                          APLOGNO(02961) 
                           "h2_to_h1(%ld-%d): got %ld more content bytes than announced "
                           "in content-length header: %ld", 
                           to_h1->m->id, to_h1->stream_id, 
@@ -263,7 +269,7 @@ apr_status_t h2_to_h1_flush(h2_to_h1 *to
         status = h2_mplx_in_write(to_h1->m, to_h1->stream_id, to_h1->bb);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_ERR, status, to_h1->m->c,
-                          "h2_request(%d): pushing request data",
+                          APLOGNO(02946) "h2_request(%d): pushing request data",
                           to_h1->stream_id);
         }
     }

Modified: httpd/httpd/trunk/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.c Fri Jul 24 12:09:44 2015
@@ -109,7 +109,7 @@ static const int BASE64URL_TABLE[] = {
     -1, -1, -1, -1
 };
 
-apr_size_t h2_util_base64url_decode(unsigned char **decoded, const char *encoded, 
+apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded, 
                                     apr_pool_t *pool)
 {
     const unsigned char *e = (const unsigned char *)encoded;
@@ -126,7 +126,7 @@ apr_size_t h2_util_base64url_decode(unsi
     *decoded = apr_pcalloc(pool, len+1);
     
     i = 0;
-    d = *decoded;
+    d = (unsigned char*)*decoded;
     for (; i < mlen; i += 4) {
         n = ((BASE64URL_TABLE[ e[i+0] ] << 18) +
              (BASE64URL_TABLE[ e[i+1] ] << 12) +
@@ -359,7 +359,8 @@ apr_status_t h2_util_move(apr_bucket_bri
                         status = apr_file_setaside(&fd, fd, to->p);
                         if (status != APR_SUCCESS) {
                             ap_log_perror(APLOG_MARK, APLOG_ERR, status, to->p,
-                                          "h2_util: %s, setaside FILE", msg);
+                                          APLOGNO(02947) "h2_util: %s, setaside FILE", 
+                                          msg);
                             return status;
                         }
                     }

Modified: httpd/httpd/trunk/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.h Fri Jul 24 12:09:44 2015
@@ -42,7 +42,7 @@ const char *h2_util_first_token_match(ap
  * I always wanted to write my own base64url decoder...not. See 
  * https://tools.ietf.org/html/rfc4648#section-5 for description.
  */
-apr_size_t h2_util_base64url_decode(unsigned char **decoded, 
+apr_size_t h2_util_base64url_decode(const char **decoded, 
                                     const char *encoded, 
                                     apr_pool_t *pool);
 

Modified: httpd/httpd/trunk/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_version.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_version.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_version.h Fri Jul 24 12:09:44 2015
@@ -20,7 +20,7 @@
  * @macro
  * Version number of the h2 module as c string
  */
-#define MOD_H2_VERSION "0.8.1"
+#define MOD_H2_VERSION "1.0.0"
 
 /**
  * @macro
@@ -28,7 +28,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_H2_VERSION_NUM 0x000801
+#define MOD_H2_VERSION_NUM 0x010000
 
 
 #endif /* mod_h2_h2_version_h */

Modified: httpd/httpd/trunk/modules/http2/h2_worker.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_worker.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_worker.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_worker.c Fri Jul 24 12:09:44 2015
@@ -41,7 +41,8 @@ static void *execute(apr_thread_t *threa
                                APR_PROTO_TCP, worker->pool);
     if (status != APR_SUCCESS) {
         ap_log_perror(APLOG_MARK, APLOG_ERR, status, worker->pool,
-                      "h2_worker(%d): alloc socket", worker->id);
+                      APLOGNO(02948) "h2_worker(%d): alloc socket", 
+                      worker->id);
         worker->worker_done(worker, worker->ctx);
         return NULL;
     }

Modified: httpd/httpd/trunk/modules/http2/h2_workers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_workers.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_workers.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_workers.c Fri Jul 24 12:09:44 2015
@@ -343,7 +343,7 @@ void h2_workers_set_max_idle_secs(h2_wor
 {
     if (idle_secs <= 0) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, workers->s,
-                     "h2_workers: max_worker_idle_sec value of %d"
+                     APLOGNO(02962) "h2_workers: max_worker_idle_sec value of %d"
                      " is not valid, ignored.", idle_secs);
         return;
     }

Modified: httpd/httpd/trunk/modules/http2/mod_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2.c (original)
+++ httpd/httpd/trunk/modules/http2/mod_h2.c Fri Jul 24 12:09:44 2015
@@ -31,8 +31,7 @@
 #include "h2_config.h"
 #include "h2_ctx.h"
 #include "h2_h2.h"
-#include "h2_alpn.h"
-#include "h2_upgrade.h"
+#include "h2_switch.h"
 #include "h2_version.h"
 
 
@@ -94,14 +93,14 @@ static int h2_post_config(apr_pool_t *p,
             break;
         case H2_MPM_UNKNOWN:
             /* ??? */
-            ap_log_error( APLOG_MARK, APLOG_ERR, 0, s,
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                          "post_config: mpm type unknown");
             break;
     }
     
     status = h2_h2_init(p, s);
     if (status == APR_SUCCESS) {
-        status = h2_alpn_init(p, s);
+        status = h2_switch_init(p, s);
     }
     
     return status;
@@ -116,15 +115,10 @@ static void h2_child_init(apr_pool_t *po
     apr_status_t status = h2_conn_child_init(pool, s);
     if (status != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
-                      "initializing connection handling");
+                     APLOGNO(02949) "initializing connection handling");
     }
 }
 
-const char *h2_get_protocol(conn_rec *c)
-{
-    return h2_ctx_pnego_get(h2_ctx_get(c));
-}
-
 /* Install this module into the apache2 infrastructure.
  */
 static void h2_hooks(apr_pool_t *pool)
@@ -142,16 +136,11 @@ static void h2_hooks(apr_pool_t *pool)
     ap_hook_child_init(h2_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 
     h2_h2_register_hooks();
-    h2_alpn_register_hooks();
-    h2_upgrade_register_hooks();
+    h2_switch_register_hooks();
     h2_task_register_hooks();
 
     h2_alt_svc_register_hooks();
     
-    /* We offer a function to other modules that lets them retrieve
-     * the h2 protocol used on a connection (if any).
-     */
-    APR_REGISTER_OPTIONAL_FN(h2_get_protocol);
 }
 
 

Modified: httpd/httpd/trunk/modules/http2/mod_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_h2.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_h2.h (original)
+++ httpd/httpd/trunk/modules/http2/mod_h2.h Fri Jul 24 12:09:44 2015
@@ -16,13 +16,4 @@
 #ifndef mod_h2_mod_h2_h
 #define mod_h2_mod_h2_h
 
-const char *h2_get_protocol(conn_rec *c);
-
-
-/** 
- * An optional function which returns the h2 protocol used on the given
- * connection and NULL if no h2* protocol is active on it.
- */
-APR_DECLARE_OPTIONAL_FN(const char *, h2_get_protocol, (conn_rec*));
-
 #endif

Modified: httpd/httpd/trunk/modules/ssl/mod_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/mod_ssl.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/mod_ssl.c (original)
+++ httpd/httpd/trunk/modules/ssl/mod_ssl.c Fri Jul 24 12:09:44 2015
@@ -283,12 +283,6 @@ static const command_rec ssl_config_cmds
                 "OpenSSL configuration command")
 #endif
 
-#ifdef HAVE_TLS_ALPN
-    SSL_CMD_SRV(ALPNPreference, ITERATE,
-                "Preference in Application-Layer Protocol Negotiation (ALPN), "
-                "protocols are chosen in the specified order")
-#endif
-
     /* Deprecated directives. */
     AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL,
       "SSLLog directive is no longer supported - use ErrorLog."),
@@ -451,37 +445,6 @@ static int ssl_engine_disable(conn_rec *
     return 1;
 }
 
-static int modssl_register_alpn(conn_rec *c,
-                               ssl_alpn_propose_protos advertisefn,
-                               ssl_alpn_proto_negotiated negotiatedfn)
-{
-#ifdef HAVE_TLS_ALPN
-    SSLConnRec *sslconn = myConnConfig(c);
-
-    if (!sslconn) {
-        return DECLINED;
-    }
-
-    if (!sslconn->alpn_proposefns) {
-        sslconn->alpn_proposefns =
-            apr_array_make(c->pool, 5, sizeof(ssl_alpn_propose_protos));
-        sslconn->alpn_negofns =
-            apr_array_make(c->pool, 5, sizeof(ssl_alpn_proto_negotiated));
-    }
-
-    if (advertisefn)
-        APR_ARRAY_PUSH(sslconn->alpn_proposefns, ssl_alpn_propose_protos) =
-            advertisefn;
-    if (negotiatedfn)
-        APR_ARRAY_PUSH(sslconn->alpn_negofns, ssl_alpn_proto_negotiated) =
-            negotiatedfn;
-
-    return OK;
-#else
-    return DECLINED;
-#endif
-}
-
 int ssl_init_ssl_connection(conn_rec *c, request_rec *r)
 {
     SSLSrvConfigRec *sc;
@@ -650,7 +613,6 @@ static void ssl_register_hooks(apr_pool_
 
     APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
     APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
-    APR_REGISTER_OPTIONAL_FN(modssl_register_alpn);
 
     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl",
                               AUTHZ_PROVIDER_VERSION,

Modified: httpd/httpd/trunk/modules/ssl/mod_ssl.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/mod_ssl.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/mod_ssl.h (original)
+++ httpd/httpd/trunk/modules/ssl/mod_ssl.h Fri Jul 24 12:09:44 2015
@@ -93,46 +93,5 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_e
 
 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
 
-/** The alpn_propose_proto callback allows other modules to propose
- * the name of the protocol that will be chosen during the
- * Application-Layer Protocol Negotiation (ALPN) portion of the SSL handshake.
- * The callback is given the connection and a list of NULL-terminated
- * protocol strings as supported by the client.  If this client_protos is 
- * non-empty, it must pick its preferred protocol from that list. Otherwise
- * it should add its supported protocols in order of precedence.
- * The callback should not yet modify the connection or install any filters
- * as its proposal(s) may be overridden by another callback or server 
- * configuration. 
- * It should return OK or, to prevent further processing of (other modules') 
- * callbacks, return DONE.
- */
-typedef int (*ssl_alpn_propose_protos)(conn_rec *connection,
-                                       apr_array_header_t *client_protos,
-                                       apr_array_header_t *proposed_protos);
-
-/** The alpn_proto_negotiated callback allows other modules to discover
- * the name of the protocol that was chosen during the Application-Layer
- * Protocol Negotiation (ALPN) portion of the SSL handshake.  
- * The callback is given the connection, a
- * non-NUL-terminated string containing the protocol name, and the
- * length of the string; it should do something appropriate
- * (i.e. insert or remove filters) and return OK. To prevent further
- * processing of (other modules') callbacks, return DONE. */
-typedef int (*ssl_alpn_proto_negotiated)(conn_rec *connection,
-                                         const char *proto_name,
-                                         apr_size_t proto_name_len);
-
-/* An optional function which can be used to register a pair of callbacks 
- * for ALPN handling.
- * This optional function should be invoked from a pre_connection hook 
- * which runs *after* mod_ssl.c's pre_connection hook.  The function returns 
- * OK if the callbacks are registered, or DECLINED otherwise (for example if 
- * mod_ssl does not support ALPN).
- */
-APR_DECLARE_OPTIONAL_FN(int, modssl_register_alpn,
-                        (conn_rec *conn,
-                         ssl_alpn_propose_protos proposefn,
-                         ssl_alpn_proto_negotiated negotiatedfn));
-
 #endif /* __MOD_SSL_H__ */
 /** @} */

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_config.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_config.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_config.c Fri Jul 24 12:09:44 2015
@@ -161,9 +161,6 @@ static void modssl_ctx_init(modssl_ctx_t
     SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE);
     mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t));
 #endif
-#ifdef HAVE_TLS_ALPN
-    mctx->ssl_alpn_pref = apr_array_make(p, 5, sizeof(const char *));
-#endif
 }
 
 static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
@@ -308,9 +305,6 @@ static void modssl_ctx_cfg_merge(apr_poo
 #ifdef HAVE_SSL_CONF_CMD
     cfgMergeArray(ssl_ctx_param);
 #endif
-#ifdef HAVE_TLS_ALPN
-    cfgMergeArray(ssl_alpn_pref);
-#endif
 }
 
 static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p,
@@ -1862,16 +1856,6 @@ const char *ssl_cmd_SSLOpenSSLConfCmd(cm
     return NULL;
 }
 #endif
-
-#ifdef HAVE_TLS_ALPN
-const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg,
-                                      const char *protocol)
-{
-    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
-    APR_ARRAY_PUSH(sc->server->ssl_alpn_pref, const char *) = protocol;
-    return NULL;
-}
-#endif
 
 #ifdef HAVE_SRP
 

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_io.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_io.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_io.c Fri Jul 24 12:09:44 2015
@@ -1495,24 +1495,26 @@ static apr_status_t ssl_io_filter_input(
         SSLConnRec *sslconn = myConnConfig(f->c);
         const unsigned char *next_proto = NULL;
         unsigned next_proto_len = 0;
+        const char *protocol;
         int n;
 
-        if (sslconn->alpn_negofns) {
-            SSL_get0_alpn_selected(inctx->ssl, &next_proto, &next_proto_len);
+        SSL_get0_alpn_selected(inctx->ssl, &next_proto, &next_proto_len);
+        if (next_proto && next_proto_len) {
+            protocol = apr_pstrmemdup(f->c->pool, (const char *)next_proto,
+                                       next_proto_len);
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c,
                           APLOGNO(02836) "ALPN selected protocol: '%s'",
-                          (next_proto && next_proto_len) ?
-                              apr_pstrmemdup(f->c->pool,
-                                             (const char *)next_proto,
-                                             next_proto_len) :
-                              "(null)");
-            for (n = 0; n < sslconn->alpn_negofns->nelts; n++) {
-                ssl_alpn_proto_negotiated fn =
-                    APR_ARRAY_IDX(sslconn->alpn_negofns, n,
-                                  ssl_alpn_proto_negotiated);
-
-                if (fn(f->c, (const char *)next_proto, next_proto_len) == DONE)
-                    break;
+                          protocol);
+            
+            if (strcmp(protocol, ap_run_protocol_get(f->c))) {
+                status = ap_switch_protocol(f->c, NULL, sslconn->server,
+                                            protocol);
+                if (status != APR_SUCCESS) {
+                    ap_log_cerror(APLOG_MARK, APLOG_ERR, status, f->c,
+                                  APLOGNO(02908) "protocol switch to '%s' failed",
+                                  protocol);
+                    return status;
+                }
             }
         }
         inctx->alpn_finished = 1;

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c Fri Jul 24 12:09:44 2015
@@ -1923,23 +1923,29 @@ void ssl_callback_Info(const SSL *ssl, i
 
 #ifdef HAVE_TLSEXT
 /*
- * This callback function is executed when OpenSSL encounters an extended
+ * This function sets the virtual host from an extended
  * client hello with a server name indication extension ("SNI", cf. RFC 6066).
  */
-int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
+static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
 {
-    const char *servername =
-                SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-    conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-
+    const char *servername;
+    
     if (c) {
+        SSLConnRec *sslcon = myConnConfig(c);
+        
+        if (sslcon->server != c->base_server) {
+            /* already found the vhost */
+            return APR_SUCCESS;
+        }
+        
+        servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
         if (servername) {
             if (ap_vhost_iterate_given_conn(c, ssl_find_vhost,
                                             (void *)servername)) {
                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02043)
                               "SSL virtual host for servername %s found",
                               servername);
-                return SSL_TLSEXT_ERR_OK;
+                return APR_SUCCESS;
             }
             else {
                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044)
@@ -1969,8 +1975,20 @@ int ssl_callback_ServerNameIndication(SS
                           "(using default/first virtual host)");
         }
     }
+    
+    return APR_NOTFOUND;
+}
 
-    return SSL_TLSEXT_ERR_NOACK;
+/*
+ * This callback function is executed when OpenSSL encounters an extended
+ * client hello with a server name indication extension ("SNI", cf. RFC 6066).
+ */
+int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
+{
+    conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+    apr_status_t status = init_vhost(c, ssl);
+    
+    return (status == APR_SUCCESS)? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;
 }
 
 /*
@@ -2170,41 +2188,6 @@ int ssl_callback_SessionTicket(SSL *ssl,
 #endif /* HAVE_TLS_SESSION_TICKETS */
 
 #ifdef HAVE_TLS_ALPN
-static int ssl_array_index(apr_array_header_t *array, const char *s)
-{
-    int i;
-    for (i = 0; i < array->nelts; i++) {
-        const char *p = APR_ARRAY_IDX(array, i, const char *);
-        if (!strcmp(p, s)) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-/*
- * Compare two ALPN protocol proposal. Result is similar to strcmp():
- * 0 gives same precedence, >0 means proto1 is preferred.
- */
-static int ssl_cmp_alpn_protos(modssl_ctx_t *ctx,
-                               const char *proto1,
-                               const char *proto2)
-{
-    if (ctx && ctx->ssl_alpn_pref) {
-        int index1 = ssl_array_index(ctx->ssl_alpn_pref, proto1);
-        int index2 = ssl_array_index(ctx->ssl_alpn_pref, proto2);
-        if (index2 > index1) {
-            return (index1 >= 0) ? 1 : -1;
-        }
-        else if (index1 > index2) {
-            return (index2 >= 0) ? -1 : 1;
-        }
-    }
-    /* both have the same index (mabye -1 or no pref configured) and we compare
-     * the names so that spdy3 gets precedence over spdy2. That makes
-     * the outcome at least deterministic. */
-    return strcmp((const char *)proto1, (const char *)proto2);
-}
 
 /*
  * This callback function is executed when the TLS Application-Layer
@@ -2225,14 +2208,9 @@ int ssl_callback_alpn_select(SSL *ssl,
 {
     conn_rec *c = (conn_rec*)SSL_get_app_data(ssl);
     SSLConnRec *sslconn = myConnConfig(c);
-    server_rec *s = mySrvFromConn(c);
-    SSLSrvConfigRec *sc = mySrvConfig(s);
-    modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
-    const char *alpn_http1 = "http/1.1";
     apr_array_header_t *client_protos;
-    apr_array_header_t *proposed_protos;
-    int i;
     size_t len;
+    int i;
 
     /* If the connection object is not available,
      * then there's nothing for us to do. */
@@ -2261,48 +2239,15 @@ int ssl_callback_alpn_select(SSL *ssl,
         i += plen;
     }
 
-    proposed_protos = apr_array_make(c->pool, client_protos->nelts+1,
-                                     sizeof(char *));
-
-    if (sslconn->alpn_proposefns != NULL) {
-        /* Invoke our alpn_propose functions, giving other modules a chance to
-         * propose protocol names for selection. We might have several such
-         * functions installed and if two make a proposal, we need to give
-         * preference to one.
-         */
-        for (i = 0; i < sslconn->alpn_proposefns->nelts; i++) {
-            ssl_alpn_propose_protos fn =
-                APR_ARRAY_IDX(sslconn->alpn_proposefns, i,
-                              ssl_alpn_propose_protos);
-
-            if (fn(c, client_protos, proposed_protos) == DONE)
-                break;
-        }
-    }
-
-    if (proposed_protos->nelts <= 0) {
-        /* Regardless of installed hooks, the http/1.1 protocol is always
-         * supported by us. Choose it if none other matches. */
-        if (ssl_array_index(client_protos, alpn_http1) < 0) {
-            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02839)
-                          "none of the client ALPN protocols are supported");
-            return SSL_TLSEXT_ERR_ALERT_FATAL;
-        }
-        *out = (const unsigned char*)alpn_http1;
-        *outlen = (unsigned char)strlen(alpn_http1);
-        return SSL_TLSEXT_ERR_OK;
-    }
-
-    /* Now select the most preferred protocol from the proposals. */
-    *out = APR_ARRAY_IDX(proposed_protos, 0, const unsigned char *);
-    for (i = 1; i < proposed_protos->nelts; ++i) {
-        const char *proto = APR_ARRAY_IDX(proposed_protos, i, const char *);
-        /* Do we prefer it over existing candidate? */
-        if (ssl_cmp_alpn_protos(mctx, (const char *)*out, proto) < 0) {
-            *out = (const unsigned char *)proto;
-        }
-    }
-
+    /* The order the callbacks are invoked from TLS extensions is, unfortunately
+     * not defined and older openssl versions do call ALPN selection before
+     * they callback the SNI. We need to make sure that we know which vhost
+     * we are dealing with so we respect the correct protocols.
+     */
+    init_vhost(c, ssl);
+    
+    *out = (const unsigned char *)ap_select_protocol(c, NULL, sslconn->server, 
+                                                     client_protos);
     len = strlen((const char*)*out);
     if (len > 255) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840)

Modified: httpd/httpd/trunk/modules/ssl/ssl_private.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_private.h?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_private.h (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_private.h Fri Jul 24 12:09:44 2015
@@ -438,12 +438,6 @@ typedef struct {
                      * connection */
     } reneg_state;
 
-#ifdef HAVE_TLS_ALPN
-    /* Poor man's inter-module optional hooks for ALPN. */
-    apr_array_header_t *alpn_proposefns; /* list of ALPN propose callbacks */
-    apr_array_header_t *alpn_negofns; /* list of ALPN negotiation callbacks. */
-#endif
-
     server_rec *server;
 } SSLConnRec;
 
@@ -625,10 +619,6 @@ typedef struct {
     SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */
     apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */
 #endif
-  
-#ifdef HAVE_TLS_ALPN
-  apr_array_header_t *ssl_alpn_pref; /* list of ALPN protocol IDs */
-#endif
 } modssl_ctx_t;
 
 struct SSLSrvConfigRec {
@@ -755,10 +745,6 @@ const char *ssl_cmd_SSLOCSPEnable(cmd_pa
 const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2);
 #endif
 
-#ifdef HAVE_TLS_ALPN
-const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg, const char *protocol);
-#endif
-
 #ifdef HAVE_SRP
 const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg);
 const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg);

Modified: httpd/httpd/trunk/server/core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/core.c?rev=1692486&r1=1692485&r2=1692486&view=diff
==============================================================================
--- httpd/httpd/trunk/server/core.c (original)
+++ httpd/httpd/trunk/server/core.c Fri Jul 24 12:09:44 2015
@@ -478,6 +478,8 @@ static void *create_core_server_config(a
 
     conf->trace_enable = AP_TRACE_UNSET;
 
+    conf->protocols = apr_array_make(a, 5, sizeof(const char *));
+    
     return (void *)conf;
 }
 
@@ -551,6 +553,8 @@ static void *merge_core_server_configs(a
                            ? virt->merge_trailers
                            : base->merge_trailers;
 
+    conf->protocols = apr_array_append(p, base->protocols, virt->protocols);
+
     return conf;
 }
 
@@ -3799,12 +3803,33 @@ static const char *set_trace_enable(cmd_
     return NULL;
 }
 
+static const char *set_protocols(cmd_parms *cmd, void *dummy,
+                                 const char *arg)
+{
+    core_server_config *conf =
+    ap_get_core_module_config(cmd->server->module_config);
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
+
+    if (err) {
+        return err;
+    }
+    
+    /* Should we check for some ALPN valid char sequence here? */
+    const char **np = (const char **)apr_array_push(conf->protocols);
+    *np = arg;
+
+    return NULL;
+}
+
 static const char *set_http_protocol(cmd_parms *cmd, void *dummy,
                                      const char *arg)
 {
     core_server_config *conf =
         ap_get_core_module_config(cmd->server->module_config);
 
+    if (!conf->protocols) {
+        
+    }
     if (strncmp(arg, "min=", 4) == 0) {
         arg += 4;
         if (strcmp(arg, "0.9") == 0)
@@ -4445,6 +4470,8 @@ AP_INIT_FLAG("HttpContentLengthHeadZero"
   "whether to permit Content-Length of 0 responses to HEAD requests"),
 AP_INIT_FLAG("HttpExpectStrict", set_expect_strict, NULL, OR_OPTIONS,
   "whether to return a 417 if a client doesn't send 100-Continue"),
+AP_INIT_ITERATE("Protocols", set_protocols, NULL, RSRC_CONF,
+                "Controls which protocols are allowed, sorted by preference"),
 { NULL }
 };
 
@@ -5226,6 +5253,73 @@ static void core_dump_config(apr_pool_t
     }
 }
 
+static const char *core_protocol_get(const conn_rec *c) 
+{
+    return AP_PROTOCOL_HTTP1;
+}
+
+static int core_upgrade_handler(request_rec *r)
+{
+    conn_rec *c = r->connection;
+    const char *upgrade = apr_table_get(r->headers_in, "Upgrade");
+
+    if (upgrade && *upgrade) {
+        const char *conn = apr_table_get(r->headers_in, "Connection");
+        if (ap_find_token(r->pool, conn, "upgrade")) {
+            apr_array_header_t *offers = NULL;
+            const char *err;
+            
+            err = ap_parse_token_list_strict(r->pool, upgrade, &offers, 0);
+            if (err) {
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02910)
+                              "parsing Upgrade header: %s", err);
+                return DECLINED;
+            }
+            
+            if (offers && offers->nelts > 0) {
+                const char *protocol = ap_select_protocol(c, r, r->server,
+                                                          offers);
+                if (strcmp(protocol, ap_run_protocol_get(c))) {
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02909)
+                                  "Upgrade selects '%s'", protocol);
+                    /* Let the client know what we are upgrading to. */
+                    apr_table_clear(r->headers_out);
+                    apr_table_setn(r->headers_out, "Upgrade", protocol);
+                    apr_table_setn(r->headers_out, "Connection", "Upgrade");
+                    
+                    r->status = HTTP_SWITCHING_PROTOCOLS;
+                    r->status_line = ap_get_status_line(r->status);
+                    ap_send_interim_response(r, 1);
+
+                    ap_switch_protocol(c, r, r->server, protocol);
+
+                    /* make sure httpd closes the connection after this */
+                    c->keepalive = AP_CONN_CLOSE;
+                    ap_lingering_close(c);
+                    
+                    if (c->sbh) {
+                        ap_update_child_status_from_conn(c->sbh, 
+                                                         SERVER_CLOSING, c);
+                    }
+                    
+                    return DONE;
+                }
+            }
+        }
+    }
+    
+    return DECLINED;
+}
+
+static int core_upgrade_storage(request_rec *r)
+{
+    if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
+        (r->uri[1] == '\0')) {
+        return core_upgrade_handler(r);
+    }
+    return DECLINED;
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     errorlog_hash = apr_hash_make(p);
@@ -5248,10 +5342,12 @@ static void register_hooks(apr_pool_t *p
     ap_hook_check_config(core_check_config,NULL,NULL,APR_HOOK_FIRST);
     ap_hook_test_config(core_dump_config,NULL,NULL,APR_HOOK_FIRST);
     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
+    ap_hook_map_to_storage(core_upgrade_storage,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_child_init(core_child_init,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
+    ap_hook_handler(core_upgrade_handler,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
@@ -5267,6 +5363,7 @@ static void register_hooks(apr_pool_t *p
     ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST);
     ap_hook_optional_fn_retrieve(core_optional_fn_retrieve, NULL, NULL,
                                  APR_HOOK_MIDDLE);
+    ap_hook_protocol_get(core_protocol_get, NULL, NULL, APR_HOOK_REALLY_LAST);
     
     /* register the core's insert_filter hook and register core-provided
      * filters



Mime
View raw message