mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
Merge r1777460, r1777672 from trunk:
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.2.x-merge-http-strict@1778094 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user