From 554554b0ebb14d6578adb70a389c57a0d5f18a3b Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 24 Jun 2024 17:54:34 +0000
Subject: [PATCH] Merge r1918551 from trunk:

add ap_set_content_type_ex to differentiate

trusted sources



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918560 13f79535-47bb-0310-9956-ffa450edef68

Conflict:NA
Reference:https://github.com/apache/httpd/commit/554554b0ebb14d6578adb70a389c57a0d5f18a3b

---
 include/http_protocol.h           | 11 +++++++++++
 include/httpd.h                   |  7 +++++++
 modules/http/http_protocol.c      |  6 ++++++
 modules/http/mod_mime.c           | 20 ++++++++++----------
 modules/mappers/mod_actions.c     |  6 ++++--
 modules/mappers/mod_negotiation.c |  8 ++++----
 modules/mappers/mod_rewrite.c     |  2 +-
 modules/metadata/mod_headers.c    |  6 +++---
 modules/metadata/mod_mime_magic.c |  4 ++--
 server/config.c                   |  2 +-
 server/core.c                     |  2 +-
 11 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/include/http_protocol.h b/include/http_protocol.h
index 94c481e..f2c99c9 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -438,6 +438,17 @@ AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l);
  */
 AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct);
 
+/**
+ * Set the content type for this request (r->content_type).
+ * @param r The current request
+ * @param ct The new content type
+ * @param trusted If non-zero, The content-type should come from a
+ *        trusted source such as server configuration rather
+ *        than application output.
+ * for the AddOutputFilterByType directive to work correctly.
+ */
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted);
+
 /**
  * Set the Accept-Ranges header for this response
  * @param r The current request
diff --git a/include/httpd.h b/include/httpd.h
index 1549be0..61e02a9 100644
--- a/include/httpd.h
+++ b/include/httpd.h
@@ -667,6 +667,7 @@ typedef apr_uint64_t ap_request_bnotes_t;
  *
  */
 #define AP_REQUEST_STRONG_ETAG 1 >> 0
+#define AP_REQUEST_TRUSTED_CT  1 << 1
 
 /**
  * This is a convenience macro to ease with getting specific request
@@ -689,6 +690,12 @@ typedef apr_uint64_t ap_request_bnotes_t;
         AP_REQUEST_GET_BNOTE((r), AP_REQUEST_STRONG_ETAG)
 /** @} */
 
+/**
+ * Returns true if the content-type field is from a trusted source
+ */
+#define AP_REQUEST_IS_TRUSTED_CT(r) \
+    (!!AP_REQUEST_GET_BNOTE((r), AP_REQUEST_TRUSTED_CT))
+/** @} */
 
 /**
  * @defgroup module_magic Module Magic mime types
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index d031f24..c31e873 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1097,8 +1097,14 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct)
     }
     else if (!r->content_type || strcmp(r->content_type, ct)) {
         r->content_type = ct;
+        AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, 0);
     }
 }
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
+{
+    ap_set_content_type(r, ct);
+    AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, trusted ? AP_REQUEST_TRUSTED_CT : 0);
+}
 
 AP_DECLARE(void) ap_set_accept_ranges(request_rec *r)
 {
diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c
index 700f824..51095a0 100644
--- a/modules/http/mod_mime.c
+++ b/modules/http/mod_mime.c
@@ -759,7 +759,7 @@ static int find_ct(request_rec *r)
     int found_metadata = 0;
 
     if (r->finfo.filetype == APR_DIR) {
-        ap_set_content_type(r, DIR_MAGIC_TYPE);
+        ap_set_content_type_ex(r, DIR_MAGIC_TYPE, 1);
         return OK;
     }
 
@@ -850,7 +850,7 @@ static int find_ct(request_rec *r)
         if (exinfo == NULL || !exinfo->forced_type) {
             if ((type = apr_hash_get(mime_type_extensions, ext,
                                      APR_HASH_KEY_STRING)) != NULL) {
-                ap_set_content_type(r, (char*) type);
+                ap_set_content_type_ex(r, (char*) type, 1);
                 found = 1;
             }
         }
@@ -859,7 +859,7 @@ static int find_ct(request_rec *r)
 
             /* empty string is treated as special case for RemoveType */
             if (exinfo->forced_type && *exinfo->forced_type) {
-                ap_set_content_type(r, exinfo->forced_type);
+                ap_set_content_type_ex(r, exinfo->forced_type, 1);
                 found = 1;
             }
 
@@ -964,33 +964,33 @@ static int find_ct(request_rec *r)
             memcpy(tmp, ctp->subtype, ctp->subtype_len);
             tmp += ctp->subtype_len;
             *tmp = 0;
-            ap_set_content_type(r, base_content_type);
+            ap_set_content_type_ex(r, base_content_type, AP_REQUEST_IS_TRUSTED_CT(r));
             while (pp != NULL) {
                 if (charset && !strcmp(pp->attr, "charset")) {
                     if (!override) {
-                        ap_set_content_type(r,
+                        ap_set_content_type_ex(r,
                                             apr_pstrcat(r->pool,
                                                         r->content_type,
                                                         "; charset=",
                                                         charset,
-                                                        NULL));
+                                                        NULL), AP_REQUEST_IS_TRUSTED_CT(r));
                         override = 1;
                     }
                 }
                 else {
-                    ap_set_content_type(r,
+                    ap_set_content_type_ex(r,
                                         apr_pstrcat(r->pool,
                                                     r->content_type,
                                                     "; ", pp->attr,
                                                     "=", pp->val,
-                                                    NULL));
+                                                    NULL), AP_REQUEST_IS_TRUSTED_CT(r));
                 }
                 pp = pp->next;
             }
             if (charset && !override) {
-                ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type,
+                ap_set_content_type_ex(r, apr_pstrcat(r->pool, r->content_type,
                                                    "; charset=", charset,
-                                                   NULL));
+                                                   NULL), AP_REQUEST_IS_TRUSTED_CT(r));
             }
         }
     }
diff --git a/modules/mappers/mod_actions.c b/modules/mappers/mod_actions.c
index ac9c3b7..5e398b5 100644
--- a/modules/mappers/mod_actions.c
+++ b/modules/mappers/mod_actions.c
@@ -182,8 +182,10 @@ static int action_handler(request_rec *r)
         return DECLINED;
 
     /* Second, check for actions (which override the method scripts) */
-    action = r->handler ? r->handler :
-        ap_field_noparam(r->pool, r->content_type);
+    action = r->handler;
+    if (!action && AP_REQUEST_IS_TRUSTED_CT(r)) {
+        action = ap_field_noparam(r->pool, r->content_type);
+    }
 
     if (action && (t = apr_table_get(conf->action_types, action))) {
         int virtual = (*t++ == '0' ? 0 : 1);
diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c
index c056b28..a528f81 100644
--- a/modules/mappers/mod_negotiation.c
+++ b/modules/mappers/mod_negotiation.c
@@ -1167,7 +1167,7 @@ static int read_types_multi(negotiation_state *neg)
          * might be doing.
          */
         if (sub_req->handler && !sub_req->content_type) {
-            ap_set_content_type(sub_req, CGI_MAGIC_TYPE);
+            ap_set_content_type_ex(sub_req, CGI_MAGIC_TYPE, 1);
         }
 
         /*
@@ -3003,14 +3003,14 @@ static int handle_map_file(request_rec *r)
         /* set MIME type and charset as negotiated */
         if (best->mime_type && *best->mime_type) {
             if (best->content_charset && *best->content_charset) {
-                ap_set_content_type(r, apr_pstrcat(r->pool,
+                ap_set_content_type_ex(r, apr_pstrcat(r->pool,
                                                    best->mime_type,
                                                    "; charset=",
                                                    best->content_charset,
-                                                   NULL));
+                                                   NULL), 1);
             }
             else {
-                ap_set_content_type(r, apr_pstrdup(r->pool, best->mime_type));
+                ap_set_content_type_ex(r, apr_pstrdup(r->pool, best->mime_type), 1);
             }
         }
 
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 024808b..78847f9 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -5454,7 +5454,7 @@ static int hook_mimetype(request_rec *r)
         rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'",
                     r->filename, t));
 
-        ap_set_content_type(r, t);
+        ap_set_content_type_ex(r, t, 1);
     }
 
     /* handler */
diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c
index ef812cd..4838bd6 100644
--- a/modules/metadata/mod_headers.c
+++ b/modules/metadata/mod_headers.c
@@ -783,14 +783,14 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
             break;
         case hdr_set:
             if (!ap_cstr_casecmp(hdr->header, "Content-Type")) {
-                 ap_set_content_type(r, process_tags(hdr, r));
+                 ap_set_content_type_ex(r, process_tags(hdr, r), 1);
             }
             apr_table_setn(headers, hdr->header, process_tags(hdr, r));
             break;
         case hdr_setifempty:
             if (NULL == apr_table_get(headers, hdr->header)) {
                 if (!ap_cstr_casecmp(hdr->header, "Content-Type")) {
-                    ap_set_content_type(r, process_tags(hdr, r));
+                    ap_set_content_type_ex(r, process_tags(hdr, r), 1);
                 }
                 apr_table_setn(headers, hdr->header, process_tags(hdr, r));
             }
@@ -809,7 +809,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
                 const char *repl = process_regexp(hdr, r->content_type, r);
                 if (repl == NULL)
                     return 0;
-                ap_set_content_type(r, repl);
+                ap_set_content_type_ex(r, repl, 1);
             }
             if (apr_table_get(headers, hdr->header)) {
                 edit_do ed;
diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c
index 7dac4fd..1c96db4 100644
--- a/modules/metadata/mod_mime_magic.c
+++ b/modules/metadata/mod_mime_magic.c
@@ -788,7 +788,7 @@ static int magic_rsl_to_request(request_rec *r)
     /* XXX: this could be done at config time I'm sure... but I'm
      * confused by all this magic_rsl stuff. -djg */
     ap_content_type_tolower(tmp);
-    ap_set_content_type(r, tmp);
+    ap_set_content_type_ex(r, tmp, 1);
 
     if (state == rsl_encoding) {
         tmp = rsl_strdup(r, encoding_frag,
@@ -2326,7 +2326,7 @@ static int revision_suffix(request_rec *r)
 
     /* extract content type/encoding/language from sub-request */
     if (sub->content_type) {
-        ap_set_content_type(r, apr_pstrdup(r->pool, sub->content_type));
+        ap_set_content_type_ex(r, apr_pstrdup(r->pool, sub->content_type), 1);
 #if MIME_MAGIC_DEBUG
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01557)
                     MODNAME ": subrequest %s got %s",
diff --git a/server/config.c b/server/config.c
index 3d11ff5..635b65d 100644
--- a/server/config.c
+++ b/server/config.c
@@ -418,7 +418,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
     }
 
     if (!r->handler) {
-        if (r->content_type) {
+        if (r->content_type && AP_REQUEST_IS_TRUSTED_CT(r)) {
             handler = r->content_type;
             if ((p=ap_strchr_c(handler, ';')) != NULL) {
                 char *new_handler = (char *)apr_pmemdup(r->pool, handler,
diff --git a/server/core.c b/server/core.c
index ffe5d16..b19763b 100644
--- a/server/core.c
+++ b/server/core.c
@@ -4816,7 +4816,7 @@ static int core_override_type(request_rec *r)
     /* Check for overrides with ForceType / SetHandler
      */
     if (conf->mime_type && strcmp(conf->mime_type, "none"))
-        ap_set_content_type(r, (char*) conf->mime_type);
+        ap_set_content_type_ex(r, (char*) conf->mime_type, 1);
 
     if (conf->expr_handler) { 
         const char *err;
-- 
2.33.0

