httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject svn commit: r1705672 [2/2] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ docs/manual/rewrite/ include/ modules/http/ modules/ssl/ server/
Date Mon, 28 Sep 2015 12:31:37 GMT
Modified: httpd/httpd/branches/2.4.x/server/protocol.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/server/protocol.c?rev=1705672&r1=1705671&r2=1705672&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/server/protocol.c (original)
+++ httpd/httpd/branches/2.4.x/server/protocol.c Mon Sep 28 12:31:37 2015
@@ -67,6 +67,9 @@ APR_HOOK_STRUCT(
     APR_HOOK_LINK(http_scheme)
     APR_HOOK_LINK(default_port)
     APR_HOOK_LINK(note_auth_failure)
+    APR_HOOK_LINK(protocol_propose)
+    APR_HOOK_LINK(protocol_switch)
+    APR_HOOK_LINK(protocol_get)
 )
 
 AP_DECLARE_DATA ap_filter_rec_t *ap_old_write_func = NULL;
@@ -1790,6 +1793,150 @@ AP_DECLARE(void) ap_send_interim_respons
     apr_brigade_destroy(x.bb);
 }
 
+/*
+ * Compare two protocol identifier. Result is similar to strcmp():
+ * 0 gives same precedence, >0 means proto1 is preferred.
+ */
+static int protocol_cmp(const apr_array_header_t *preferences,
+                        const char *proto1,
+                        const char *proto2)
+{
+    if (preferences && preferences->nelts > 0) {
+        int index1 = ap_array_str_index(preferences, proto1, 0);
+        int index2 = ap_array_str_index(preferences, proto2, 0);
+        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(proto1, proto2);
+}
+
+AP_DECLARE(const char *) ap_get_protocol(conn_rec *c)
+{
+    const char *protocol = ap_run_protocol_get(c);
+    return protocol? protocol : AP_PROTOCOL_HTTP1;
+}
+
+AP_DECLARE(const char *) ap_select_protocol(conn_rec *c, request_rec *r, 
+                                            server_rec *s,
+                                            const apr_array_header_t *choices)
+{
+    apr_pool_t *pool = r? r->pool : c->pool;
+    core_server_config *conf = ap_get_core_module_config(s->module_config);
+    const char *protocol = NULL, *existing;
+    apr_array_header_t *proposals;
+
+    if (APLOGcdebug(c)) {
+        const char *p = apr_array_pstrcat(pool, conf->protocols, ',');
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 
+                      "select protocol from %s, choices=%s for server %s", 
+                      p, apr_array_pstrcat(pool, choices, ','),
+                      s->server_hostname);
+    }
+
+    if (conf->protocols->nelts <= 0) {
+        /* nothing configured, by default, we only allow http/1.1 here.
+         * For now...
+         */
+        if (ap_array_str_contains(choices, AP_PROTOCOL_HTTP1)) {
+            return AP_PROTOCOL_HTTP1;
+        }
+        else {
+            return NULL;
+        }
+    }
+
+    proposals = apr_array_make(pool, choices->nelts + 1, sizeof(char *));
+    ap_run_protocol_propose(c, r, s, choices, proposals);
+
+    /* If the existing protocol has not been proposed, but is a choice,
+     * add it to the proposals implicitly.
+     */
+    existing = ap_get_protocol(c);
+    if (!ap_array_str_contains(proposals, existing)
+        && ap_array_str_contains(choices, existing)) {
+        APR_ARRAY_PUSH(proposals, const char*) = existing;
+    }
+
+    if (proposals->nelts > 0) {
+        int i;
+        const apr_array_header_t *prefs = NULL;
+
+        /* Default for protocols_honor_order is 'on' or != 0 */
+        if (conf->protocols_honor_order == 0 && choices->nelts > 0) {
+            prefs = choices;
+        }
+        else {
+            prefs = conf->protocols;
+        }
+
+        /* Select the most preferred protocol */
+        if (APLOGcdebug(c)) {
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 
+                          "select protocol, proposals=%s preferences=%s configured=%s", 
+                          apr_array_pstrcat(pool, proposals, ','),
+                          apr_array_pstrcat(pool, prefs, ','),
+                          apr_array_pstrcat(pool, conf->protocols, ','));
+        }
+        for (i = 0; i < proposals->nelts; ++i) {
+            const char *p = APR_ARRAY_IDX(proposals, i, const char *);
+            if (!ap_array_str_contains(conf->protocols, p)) {
+                /* not a configured protocol here */
+                continue;
+            }
+            else if (!protocol 
+                     || (protocol_cmp(prefs, protocol, p) < 0)) {
+                /* none selected yet or this one has preference */
+                protocol = p;
+            }
+        }
+    }
+    if (APLOGcdebug(c)) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "selected protocol=%s", 
+                      protocol? protocol : "(none)");
+    }
+
+    return protocol;
+}
+
+AP_DECLARE(apr_status_t) ap_switch_protocol(conn_rec *c, request_rec *r, 
+                                            server_rec *s,
+                                            const char *protocol)
+{
+    const char *current = ap_get_protocol(c);
+    int rc;
+    
+    if (!strcmp(current, protocol)) {
+        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(02906)
+                      "already at it, protocol_switch to %s", 
+                      protocol);
+        return APR_SUCCESS;
+    }
+    
+    rc = ap_run_protocol_switch(c, r, s, protocol);
+    switch (rc) {
+        case DECLINED:
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02907)
+                          "no implementation for protocol_switch to %s", 
+                          protocol);
+            return APR_ENOTIMPL;
+        case OK:
+        case DONE:
+            return APR_SUCCESS;
+        default:
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02905)
+                          "unexpected return code %d from protocol_switch to %s"
+                          , rc, protocol);
+            return APR_EOF;
+    }    
+}
+
 
 AP_IMPLEMENT_HOOK_VOID(pre_read_request,
                        (request_rec *r, conn_rec *c),
@@ -1805,3 +1952,14 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(unsigned sho
 AP_IMPLEMENT_HOOK_RUN_FIRST(int, note_auth_failure,
                             (request_rec *r, const char *auth_type),
                             (r, auth_type), DECLINED)
+AP_IMPLEMENT_HOOK_RUN_ALL(int,protocol_propose,
+                          (conn_rec *c, request_rec *r, server_rec *s,
+                           const apr_array_header_t *offers,
+                           apr_array_header_t *proposals), 
+                          (c, r, s, offers, proposals), OK, DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int,protocol_switch,
+                            (conn_rec *c, request_rec *r, server_rec *s,
+                             const char *protocol), 
+                            (c, r, s, protocol), DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,protocol_get,
+                            (const conn_rec *c), (c), NULL)

Modified: httpd/httpd/branches/2.4.x/server/util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/server/util.c?rev=1705672&r1=1705671&r2=1705672&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/server/util.c (original)
+++ httpd/httpd/branches/2.4.x/server/util.c Mon Sep 28 12:31:37 2015
@@ -1451,6 +1451,95 @@ AP_DECLARE(int) ap_find_etag_weak(apr_po
     return find_list_item(p, line, tok, AP_ETAG_WEAK);
 }
 
+/* Grab a list of tokens of the format 1#token (from RFC7230) */
+AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
+                                                    const char *str_in,
+                                                    apr_array_header_t **tokens,
+                                                    int skip_invalid)
+{
+    int in_leading_space = 1;
+    int in_trailing_space = 0;
+    int string_end = 0;
+    const char *tok_begin;
+    const char *cur;
+    
+    if (!str_in) {
+        return NULL;
+    }
+    
+    tok_begin = cur = str_in;
+    
+    while (!string_end) {
+        const unsigned char c = (unsigned char)*cur;
+        
+        if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP) && c != '\0') {
+            /* Non-separator character; we are finished with leading
+             * whitespace. We must never have encountered any trailing
+             * whitespace before the delimiter (comma) */
+            in_leading_space = 0;
+            if (in_trailing_space) {
+                return "Encountered illegal whitespace in token";
+            }
+        }
+        else if (c == ' ' || c == '\t') {
+            /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
+             * we can't get a CRLF since headers are split on them already,
+             * so only look for a space or a tab */
+            if (in_leading_space) {
+                /* We're still in leading whitespace */
+                ++tok_begin;
+            }
+            else {
+                /* We must be in trailing whitespace */
+                ++in_trailing_space;
+            }
+        }
+        else if (c == ',' || c == '\0') {
+            if (!in_leading_space) {
+                /* If we're out of the leading space, we know we've read some
+                 * characters of a token */
+                if (*tokens == NULL) {
+                    *tokens = apr_array_make(p, 4, sizeof(char *));
+                }
+                APR_ARRAY_PUSH(*tokens, char *) =
+                apr_pstrmemdup((*tokens)->pool, tok_begin,
+                               (cur - tok_begin) - in_trailing_space);
+            }
+            /* We're allowed to have null elements, just don't add them to the
+             * array */
+            
+            tok_begin = cur + 1;
+            in_leading_space = 1;
+            in_trailing_space = 0;
+            string_end = (c == '\0');
+        }
+        else {
+            /* Encountered illegal separator char */
+            if (skip_invalid) {
+                /* Skip to the next separator */
+                const char *temp;
+                temp = ap_strchr_c(cur, ',');
+                if(!temp) {
+                    temp = ap_strchr_c(cur, '\0');
+                }
+                
+                /* Act like we haven't seen a token so we reset */
+                cur = temp - 1;
+                in_leading_space = 1;
+                in_trailing_space = 0;
+            }
+            else {
+                return apr_psprintf(p, "Encountered illegal separator "
+                                    "'\\x%.2x'", (unsigned int)c);
+            }
+        }
+        
+        ++cur;
+    }
+    
+    return NULL;
+}
+    
 /* Retrieve a token, spacing over it and returning a pointer to
  * the first non-white byte afterwards.  Note that these tokens
  * are delimited by semis and commas; and can also be delimited
@@ -3005,3 +3094,28 @@ AP_DECLARE(char *) ap_get_exec_line(apr_
 
     return apr_pstrndup(p, buf, k);
 }
+
+AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
+                                   const char *s,
+                                   int start)
+{
+    if (start >= 0) {
+        int i;
+        
+        for (i = start; i < array->nelts; i++) {
+            const char *p = APR_ARRAY_IDX(array, i, const char *);
+            if (!strcmp(p, s)) {
+                return i;
+            }
+        }
+    }
+    
+    return -1;
+}
+
+AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
+                                      const char *s)
+{
+    return (ap_array_str_index(array, s, 0) >= 0);
+}
+



Mime
View raw message