Commit 5a52455e authored by Yann Ylavic's avatar Yann Ylavic
Browse files

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
parent e73f480d
Loading
Loading
Loading
Loading
+54 −15
Original line number Diff line number Diff line
@@ -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,14 +715,52 @@ static int check_header(void *arg, const char *name, const char *val)
        return 0;
    }

    test = ap_scan_http_field_content(val);
    if (*test) {
    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, val);
                              "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)