]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
http: allow folding in check_headers(), still compliant with RFC 7230 (3.2.4).
authorWilliam A. Rowe Jr <wrowe@apache.org>
Mon, 9 Jan 2017 15:58:24 +0000 (15:58 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Mon, 9 Jan 2017 15:58:24 +0000 (15:58 +0000)
Backports: r1777460, r1777672
Submitted by: ylavic
Reviewed by: ylavic, covener, wrowe

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1777999 13f79535-47bb-0310-9956-ffa450edef68

STATUS
modules/http/http_filters.c

diff --git a/STATUS b/STATUS
index 4bd0f787413c4d5a2fe847797f153477b6182381..d8df5eacd74b160973b5af2f3b5ff5907b691cf8 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -99,16 +99,10 @@ CURRENT RELEASE NOTES:
 
 RELEASE SHOWSTOPPERS:
 
+
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  *) http: allow folding in check_headers(), still compliant with RFC 7230 (3.2.4).
-     trunk patch: http://svn.apache.org/r1777460
-                  http://svn.apache.org/r1777672
-     2.4.x patch: N/A
-     2.2.x patch: http://home.apache.org/~ylavic/patches/httpd-2.2.x-r1777460-v3.patch
-                  (needed because of s/APLOGNO//)
-     +1: ylavic, covener, wrowe
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]
index 8e95494f1fc9ab6702d7ad262264044234047e0a..f537c65556dcbf6931d2e9298c2eb3ce394a9ebd 100644 (file)
@@ -689,10 +689,11 @@ struct check_header_ctx {
 };
 
 /* check a single header, to be used with apr_table_do() */
-static int check_header(void *arg, const char *name, const char *val)
+static int check_header(struct check_header_ctx *ctx,
+                        const char *name, const char **val)
 {
-    struct check_header_ctx *ctx = arg;
-    const char *test;
+    const char *pos, *end;
+    char *dst = NULL;
 
     if (name[0] == '\0') {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
@@ -701,12 +702,12 @@ static int check_header(void *arg, const char *name, const char *val)
     }
 
     if (ctx->strict) { 
-        test = ap_scan_http_token(name);
+        end = ap_scan_http_token(name);
     }
     else {
-        test = ap_scan_vchar_obstext(name);
+        end = ap_scan_vchar_obstext(name);
     }
-    if (*test) {
+    if (*end) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
                       "Response header name '%s' contains invalid "
                       "characters, aborting request",
@@ -714,13 +715,51 @@ static int check_header(void *arg, const char *name, const char *val)
         return 0;
     }
 
-    test = ap_scan_http_field_content(val);
-    if (*test) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
-                      "Response header '%s' value of '%s' contains invalid "
-                      "characters, aborting request",
-                      name, val);
-        return 0;
+    for (pos = *val; *pos; pos = end) {
+        end = ap_scan_http_field_content(pos);
+        if (*end) {
+            if (end[0] != CR || end[1] != LF || (end[2] != ' ' &&
+                                                 end[2] != '\t')) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
+                              "Response header '%s' value of '%s' contains "
+                              "invalid characters, aborting request",
+                              name, pos);
+                return 0;
+            }
+            if (!dst) {
+                *val = dst = apr_palloc(ctx->r->pool, strlen(*val) + 1);
+            }
+        }
+        if (dst) {
+            memcpy(dst, pos, end - pos);
+            dst += end - pos;
+            if (*end) {
+                /* skip folding and replace with a single space */
+                end += 3 + strspn(end + 3, "\t ");
+                *dst++ = ' ';
+            }
+        }
+    }
+    if (dst) {
+        *dst = '\0';
+    }
+    return 1;
+}
+
+static int check_headers_table(apr_table_t *t, struct check_header_ctx *ctx)
+{
+    const apr_array_header_t *headers = apr_table_elts(t);
+    apr_table_entry_t *header;
+    int i;
+
+    for (i = 0; i < headers->nelts; ++i) {
+        header = &((apr_table_entry_t *)headers->elts)[i];
+        if (!header->key) {
+            continue;
+        }
+        if (!check_header(ctx, header->key, (const char **)&header->val)) {
+            return 0;
+        }
     }
     return 1;
 }
@@ -738,8 +777,8 @@ static APR_INLINE int check_headers(request_rec *r)
 
     ctx.r = r;
     ctx.strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
-    return apr_table_do(check_header, &ctx, r->headers_out, NULL) &&
-           apr_table_do(check_header, &ctx, r->err_headers_out, NULL);
+    return check_headers_table(r->headers_out, &ctx) &&
+           check_headers_table(r->err_headers_out, &ctx);
 }
 
 static int check_headers_recursion(request_rec *r)