From: William A. Rowe Jr Date: Mon, 9 Jan 2017 15:58:24 +0000 (+0000) Subject: http: allow folding in check_headers(), still compliant with RFC 7230 (3.2.4). X-Git-Tag: 2.2.32~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a556b36e5eb47ede101a012e82bc66d1a69ecd8;p=thirdparty%2Fapache%2Fhttpd.git http: allow folding in check_headers(), still compliant with RFC 7230 (3.2.4). 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 --- diff --git a/STATUS b/STATUS index 4bd0f787413..d8df5eacd74 100644 --- 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 ] diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 8e95494f1fc..f537c65556d 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -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)