header validation after content-* are eval'ed

Submitted By: ylavic



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1916770 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index ca3d68d..daf6640 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -59,6 +59,7 @@
 
 static apr_bucket *create_trailers_bucket(request_rec *r, apr_bucket_alloc_t *bucket_alloc);
 static apr_bucket *create_response_bucket(request_rec *r, apr_bucket_alloc_t *bucket_alloc);
+static void merge_response_headers(request_rec *r);
 
 typedef struct http_filter_ctx
 {
@@ -1239,12 +1240,16 @@
             ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
                           "ap_http_header_filter prep response status %d",
                           r->status);
+            merge_response_headers(r);
             if (!check_headers(r)) {
                 /* We may come back here from ap_die() below,
                  * so clear anything from this response.
                  */
                 apr_table_clear(r->headers_out);
                 apr_table_clear(r->err_headers_out);
+                r->content_type = r->content_encoding = NULL;
+                r->content_languages = NULL;
+                r->clength = r->chunked = 0;
                 apr_brigade_cleanup(b);
 
                 /* Don't recall ap_die() if we come back here (from its own internal
@@ -1261,8 +1266,6 @@
                 APR_BRIGADE_INSERT_TAIL(b, e);
                 e = apr_bucket_eos_create(c->bucket_alloc);
                 APR_BRIGADE_INSERT_TAIL(b, e);
-                r->content_type = r->content_encoding = NULL;
-                r->content_languages = NULL;
                 ap_set_content_length(r, 0);
                 recursive_error = 1;
             }
@@ -2044,7 +2047,7 @@
     return NULL;
 }
 
-static apr_bucket *create_response_bucket(request_rec *r, apr_bucket_alloc_t *bucket_alloc)
+static void merge_response_headers(request_rec *r)
 {
     const char *ctype;
 
@@ -2056,6 +2059,7 @@
     if (!apr_is_empty_table(r->err_headers_out)) {
         r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
                                            r->headers_out);
+        apr_table_clear(r->err_headers_out);
     }
 
     ap_set_std_response_headers(r);
@@ -2077,6 +2081,9 @@
         fixup_vary(r);
     }
 
+    /* Determine the protocol and whether we should use keepalives. */
+    basic_http_header_check(r);
+
     /*
      * Now remove any ETag response header field if earlier processing
      * says so (such as a 'FileETag None' directive).
@@ -2085,10 +2092,19 @@
         apr_table_unset(r->headers_out, "ETag");
     }
 
-    /* determine the protocol and whether we should use keepalives. */
-    basic_http_header_check(r);
+    /*
+     * Control cachability for non-cacheable responses if not already set by
+     * some other part of the server configuration.
+     */
+    if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
+        char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
+        ap_recent_rfc822_date(date, r->request_time);
+        apr_table_addn(r->headers_out, "Expires", date);
+    }
 
+    /* 204/304 responses don't have content related headers */
     if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
+        apr_table_unset(r->headers_out, "Transfer-Encoding");
         apr_table_unset(r->headers_out, "Content-Length");
         r->content_type = r->content_encoding = NULL;
         r->content_languages = NULL;
@@ -2124,17 +2140,10 @@
         field = apr_array_pstrcat(r->pool, r->content_languages, ',');
         apr_table_setn(r->headers_out, "Content-Language", field);
     }
+}
 
-    /*
-     * Control cachability for non-cacheable responses if not already set by
-     * some other part of the server configuration.
-     */
-    if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
-        char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
-        ap_recent_rfc822_date(date, r->request_time);
-        apr_table_addn(r->headers_out, "Expires", date);
-    }
-
+static apr_bucket *create_response_bucket(request_rec *r, apr_bucket_alloc_t *bucket_alloc)
+{
     /* r->headers_out fully prepared. Create a headers bucket
      * containing the response to send down the filter chain.
      */