summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2017-01-10 08:15:38 +0000
committerYann Ylavic <ylavic@apache.org>2017-01-10 08:15:38 +0000
commit727eea070834dfd93d1aeec9d4d8cab0ab9e9d87 (patch)
treeffe24957971529a8e7afbc1e18b06ecbbf073e1b
parent5cd3d6daee9008b8f2cde919d8c9a926956eb6f4 (diff)
downloadhttpd-2.4.x-merge-http-strict.tar.gz
Merge r1777460, r1777672 from trunk:2.4.x-merge-http-strict
http: allow folding in check_headers(), still compliant with RFC 7230 (3.2.4). http: follow up to r1777460. We MUST unfold outgoing HTTP headers in any case, "message/http" is for inner content. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x-merge-http-strict@1778095 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--modules/http/http_filters.c69
1 files changed, 54 insertions, 15 deletions
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 11b02f2f8b..388f899361 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -690,10 +690,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, APLOGNO(02428)
@@ -702,12 +703,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, APLOGNO(02429)
"Response header name '%s' contains invalid "
"characters, aborting request",
@@ -715,13 +716,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, APLOGNO(02430)
- "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, APLOGNO(02430)
+ "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_ARRAY_IDX(headers, i, apr_table_entry_t);
+ 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)