]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
announce protocol choices on first request
authorStefan Eissing <icing@apache.org>
Fri, 23 Oct 2015 15:14:50 +0000 (15:14 +0000)
committerStefan Eissing <icing@apache.org>
Fri, 23 Oct 2015 15:14:50 +0000 (15:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1710231 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/http_protocol.h
server/core.c
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 37050ca6aea7d787adff7b7e22e2d60ce7c729bf..028249ea5934896b74def9a8dc67d9e1d86a5b1e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) core: add ap_get_protocol_upgrades() to retrieve the list of protocols
+     that a client could possibly upgrade to. Use in first request on a 
+     connection to announce protocol choices.
+     [Stefan Eissing]
+
   *) mod_http2: reworked deallocation on connection shutdown and worker
      abort. Separate parent pool for all workers. worker threads are joined
      on planned worker shutdown.
index f9110385cd5ffd6682013d3bade78ad18a574f7a..20e1b782e74ea71cb4847f256a2d88e4016ebc00 100644 (file)
@@ -782,7 +782,22 @@ AP_DECLARE_HOOK(int,protocol_switch,(conn_rec *c, request_rec *r,
  * @return The identifier of the protocol in place or NULL
  */
 AP_DECLARE_HOOK(const char *,protocol_get,(const conn_rec *c))
-    
+
+/**
+ * Get the protocols that the connection and optional request may
+ * upgrade to - besides the protocol currently active on the connection. These
+ * values may be used to announce to a client what choices it has.
+ *
+ * @param c The current connection
+ * @param r The current request or NULL
+ * @param s The server/virtual host selected or NULL
+ * @param pupgrades on return, possible protocols to upgrade to in descending order 
+ *                 of preference. Maybe NULL if none are available.    
+ */
+AP_DECLARE(apr_status_t) ap_get_protocol_upgrades(conn_rec *c, request_rec *r, 
+                                                  server_rec *s, 
+                                                  const apr_array_header_t **pupgrades);
+                                                  
 /**
  * Select a protocol for the given connection and optional request. Will return
  * the protocol identifier selected which may be the protocol already in place
index 6ffeb19240c774e23d0eaae4b095c13a6a3fb75e..5b8f230a99c0d8c54c5807cafc1ed18b0f7f8a09 100644 (file)
@@ -5363,6 +5363,18 @@ static int core_upgrade_handler(request_rec *r)
             }
         }
     }
+    else if (!r->connection->keepalives) {
+        /* first request on connection, if we have protocols other
+         * than the current one enabled here, announce them to the
+         * client */
+        const apr_array_header_t *upgrades;
+        ap_get_protocol_upgrades(r->connection, r, NULL, &upgrades);
+        if (upgrades && upgrades->nelts > 0) {
+            char *protocols = apr_array_pstrcat(r->pool, upgrades, ',');
+            apr_table_setn(r->headers_out, "Upgrade", protocols);
+            apr_table_setn(r->headers_out, "Connection", "Upgrade");
+        }
+    }
     
     return DECLINED;
 }
index 33bf14884770e39005698708a603e65d716eefee..fc2a20f6023a854477a74f878bf9757724872300 100644 (file)
@@ -1982,6 +1982,42 @@ AP_DECLARE(const char *) ap_get_protocol(conn_rec *c)
     return protocol? protocol : AP_PROTOCOL_HTTP1;
 }
 
+AP_DECLARE(apr_status_t) ap_get_protocol_upgrades(conn_rec *c, request_rec *r, 
+                                                  server_rec *s, 
+                                                  const apr_array_header_t **pupgrades)
+{
+    apr_pool_t *pool = r? r->pool : c->pool;
+    core_server_config *conf;
+    const char *existing;
+    apr_array_header_t *upgrades = NULL;
+
+    if (!s) {
+        s = (r? r->server : c->base_server);
+    }
+    conf = ap_get_core_module_config(s->module_config);
+    
+    if (conf->protocols->nelts > 0) {
+        existing = ap_get_protocol(c);
+        if (conf->protocols->nelts > 1 
+            || !ap_array_str_contains(conf->protocols, existing)) {
+            /* possibly more than one choice or one, but not the
+             * existing. (TODO: maybe 426 and Upgrade then?) */
+            upgrades = apr_array_make(pool, conf->protocols->nelts + 1, 
+                                      sizeof(char *));
+            for (int i = 0; i < conf->protocols->nelts; ++i) {
+                const char *p = APR_ARRAY_IDX(conf->protocols, i, char *);
+                if (strcmp(existing, p)) {
+                    /* not the one we have and possible, add in this order */
+                    APR_ARRAY_PUSH(upgrades, const char*) = p;
+                }
+            }
+        }
+    }
+    
+    *pupgrades = upgrades;
+    return APR_SUCCESS;
+}
+
 AP_DECLARE(const char *) ap_select_protocol(conn_rec *c, request_rec *r, 
                                             server_rec *s,
                                             const apr_array_header_t *choices)