]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
apreq: Sync r1894982 from libapreq.
authorYann Ylavic <ylavic@apache.org>
Fri, 12 Nov 2021 21:46:11 +0000 (21:46 +0000)
committerYann Ylavic <ylavic@apache.org>
Fri, 12 Nov 2021 21:46:11 +0000 (21:46 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1894985 13f79535-47bb-0310-9956-ffa450edef68

server/apreq_util.c

index 7b0f3b1022d945a9f87cb48cfdcc83c0a43af019..eba8b8b3f6903d816037da5a25cdaf1dee840972 100644 (file)
@@ -839,100 +839,157 @@ APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
 }
 
 
-/*
- * is_2616_token() is the verbatim definition from section 2.2
- * in the rfc itself.  We try to optimize it around the
- * expectation that the argument is not a token, which
- * should be the typical usage.
- */
-
-static APR_INLINE
-unsigned is_2616_token(const char c) {
-    switch (c) {
-    case ' ': case ';': case ',': case '"': case '\t':
-        /* The chars we are expecting are listed above;
-           the chars below are just for completeness. */
-    case '?': case '=': case '@': case ':': case '\\': case '/':
-    case '(': case ')':
-    case '<': case '>':
-    case '{': case '}':
-    case '[': case ']':
-        return 0;
-    default:
-        if (apr_iscntrl(c))
-            return 0;
-    }
-    return 1;
-}
+#define IS_SPACE_CHAR(c) ((c) == '\t' || (c) == ' ')
+#define IS_TOKEN_CHAR(c) (apr_isalnum(c) \
+                          || ((c) && strchr("!#$%&'*+-.^_`|~", (c))))
 
 APREQ_DECLARE(apr_status_t)
     apreq_header_attribute(const char *hdr,
                            const char *name, const apr_size_t nlen,
                            const char **val, apr_size_t *vlen)
 {
-    const char *key, *v;
-
-    /* Must ensure first char isn't '=', so we can safely backstep. */
-    while (*hdr == '=')
-        ++hdr;
+    int done = 0;
 
-    while ((key = strchr(hdr, '=')) != NULL) {
+    if (!nlen)
+        return APREQ_ERROR_NOATTR;
 
-        v = key + 1;
-        --key;
+    do {
+        const char *hde, *v;
+        apr_size_t tail = 0;
 
-        while (apr_isspace(*key) && key > hdr + nlen)
-            --key;
+        /* Parse the name => [hdr:hde[ */
+        hde = hdr;
+    look_for_end_name:
+        switch (*hde) {
+        case 0:
+        case '\r':
+        case '\n':
+            done = 1;
+        case '=':
+        case ';':
+        case ',':
+            v = hde + 1;
+            hde -= tail;
+            break;
+        case ' ':
+        case '\t':
+            if (hde == hdr)
+                ++hdr;
+            else
+                ++tail;
+            ++hde;
+            goto look_for_end_name;
+        default:
+            /* The name is a token */
+            if (!IS_TOKEN_CHAR(*hde))
+                return APREQ_ERROR_BADCHAR;
+            /* Nothing after the tail */
+            if (tail)
+                return APREQ_ERROR_BADATTR;
+            ++hde;
+            goto look_for_end_name;
+        }
 
-        key -= nlen - 1;
+        /* Parse the value => (*val, *vlen) */
+        if (v[-1] == '=') {
+            if (hde == hdr) {
+                /* The name can't be empty */
+                return APREQ_ERROR_BADATTR;
+            }
 
-        while (apr_isspace(*v))
-            ++v;
+            while (IS_SPACE_CHAR(*v))
+                ++v;
 
-        if (*v == '"') {
-            ++v;
-            *val = v;
+            /* Quoted string ? */
+            if (*v == '"') {
+                *val = ++v;
+
+                /* XXX: the interface does not permit unescaping,
+                 *      it should have pool to allocate from.
+                 * The caller can't know whether a returned '\\' is
+                 * a quoted-char or not..
+                 */
+            look_for_end_quote:
+                switch (*v) {
+                case 0:
+                case '\r':
+                case '\n':
+                    return APREQ_ERROR_BADSEQ;
+                case '"':
+                    *vlen = v - *val;
+                    break;
+                case '\\':
+                    if (v[1] != 0)
+                        ++v;
+                    ++v;
+                    goto look_for_end_quote;
+                default:
+                    if (apr_iscntrl(*v))
+                        return APREQ_ERROR_BADCHAR;
+                    ++v;
+                    goto look_for_end_quote;
+                }
 
-        look_for_end_quote:
-            switch (*v) {
-            case '"':
-                break;
-            case 0:
-                return APREQ_ERROR_BADSEQ;
-            case '\\':
-                if (v[1] != 0)
+            look_for_after_quote:
+                switch (*v) {
+                case 0:
+                case '\r':
+                case '\n':
+                    done = 1;
+                case ';':
+                case ',':
+                    break;
+                case ' ':
+                case '\t':
+                    goto look_for_after_quote;
+                default:
+                    if (apr_iscntrl(*v))
+                        return APREQ_ERROR_BADCHAR;
+                    return APREQ_ERROR_BADSEQ;
+                }
+            }
+            else {
+                *val = v;
+                tail = 0;
+
+            look_for_end_value:
+                switch (*v) {
+                case 0:
+                case '\r':
+                case '\n':
+                    done = 1;
+                case ';':
+                case ',':
+                    *vlen = v - *val - tail;
+                    break;
+                case ' ':
+                case '\t':
+                    if (*val == v)
+                        ++*val;
+                    else
+                        ++tail;
                     ++v;
-            default:
-                ++v;
-                goto look_for_end_quote;
+                    goto look_for_end_value;
+                default:
+                    if (apr_iscntrl(*v))
+                        return APREQ_ERROR_BADCHAR;
+                    ++v;
+                    tail = 0;
+                    goto look_for_end_value;
+                }
             }
         }
         else {
-            *val = v;
-
-        look_for_terminator:
-            switch (*v) {
-            case 0:
-            case ' ':
-            case ';':
-            case ',':
-            case '\t':
-            case '\r':
-            case '\n':
-                break;
-            default:
-                ++v;
-                goto look_for_terminator;
-            }
+            *val = NULL;
+            *vlen = 0;
         }
 
-        if (key >= hdr && strncasecmp(key, name, nlen) == 0) {
-            *vlen = v - *val;
-            if (key == hdr || ! is_2616_token(key[-1]))
-                return APR_SUCCESS;
+        if (hdr + nlen == hde && strncasecmp(hdr, name, nlen) == 0) {
+            return APR_SUCCESS;
         }
-        hdr = v;
-    }
+
+        hdr = v + 1;
+    } while (!done);
 
     return APREQ_ERROR_NOATTR;
 }