From df8ba04e317becc42d132644b849fd340877c5a9 Mon Sep 17 00:00:00 2001 From: strawberry Date: Mon, 3 Jun 2024 18:52:02 -0400 Subject: [PATCH] media: trust client Content-Type again Signed-off-by: strawberry --- src/api/client_server/media.rs | 32 +++++++-------------------- src/core/utils/content_disposition.rs | 25 --------------------- 2 files changed, 8 insertions(+), 49 deletions(-) diff --git a/src/api/client_server/media.rs b/src/api/client_server/media.rs index 7b492913..84a51f33 100644 --- a/src/api/client_server/media.rs +++ b/src/api/client_server/media.rs @@ -22,9 +22,7 @@ use crate::{ services, utils::{ self, - content_disposition::{ - content_disposition_type, make_content_disposition, make_content_type, sanitise_filename, - }, + content_disposition::{content_disposition_type, make_content_disposition, sanitise_filename}, }, Error, Result, Ruma, RumaResponse, }; @@ -131,8 +129,6 @@ pub(crate) async fn create_content_route( utils::random_string(MXC_LENGTH) ); - let content_type = Some(make_content_type(&body.file, &body.content_type).to_owned()); - services() .media .create( @@ -143,12 +139,12 @@ pub(crate) async fn create_content_route( .map(|filename| { format!( "{}; filename={}", - content_disposition_type(&body.file, &content_type), + content_disposition_type(&body.file, &body.content_type), sanitise_filename(filename.to_owned()) ) }) .as_deref(), - content_type.as_deref(), + body.content_type.as_deref(), &body.file, ) .await?; @@ -193,7 +189,6 @@ pub(crate) async fn get_content_route(body: Ruma) -> R }) = services().media.get(mxc.clone()).await? { let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition, None)); - let content_type = Some(make_content_type(&file, &content_type).to_owned()); Ok(get_content::v3::Response { file, @@ -222,11 +217,10 @@ pub(crate) async fn get_content_route(body: Ruma) -> R response.content_disposition, None, )); - let content_type = Some(make_content_type(&response.file, &response.content_type).to_owned()); Ok(get_content::v3::Response { file: response.file, - content_type, + content_type: response.content_type, content_disposition, cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()), @@ -279,7 +273,6 @@ pub(crate) async fn get_content_as_filename_route( content_disposition, Some(body.filename.clone()), )); - let content_type = Some(make_content_type(&file, &content_type).to_owned()); Ok(get_content_as_filename::v3::Response { file, @@ -305,13 +298,10 @@ pub(crate) async fn get_content_as_filename_route( remote_content_response.content_disposition, None, )); - let content_type = Some( - make_content_type(&remote_content_response.file, &remote_content_response.content_type).to_owned(), - ); Ok(get_content_as_filename::v3::Response { content_disposition, - content_type, + content_type: remote_content_response.content_type, file: remote_content_response.file, cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()), @@ -376,7 +366,6 @@ pub(crate) async fn get_content_thumbnail_route( .await? { let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition, None)); - let content_type = Some(make_content_type(&file, &content_type).to_owned()); Ok(get_content_thumbnail::v3::Response { file, @@ -434,13 +423,10 @@ pub(crate) async fn get_content_thumbnail_route( get_thumbnail_response.content_disposition, None, )); - let content_type = Some( - make_content_type(&get_thumbnail_response.file, &get_thumbnail_response.content_type).to_owned(), - ); Ok(get_content_thumbnail::v3::Response { file: get_thumbnail_response.file, - content_type, + content_type: get_thumbnail_response.content_type, cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()), content_disposition, @@ -509,22 +495,20 @@ async fn get_remote_content( None, )); - let content_type = Some(make_content_type(&content_response.file, &content_response.content_type).to_owned()); - services() .media .create( None, mxc.to_owned(), content_disposition.as_deref(), - content_type.as_deref(), + content_response.content_type.as_deref(), &content_response.file, ) .await?; Ok(get_content::v3::Response { file: content_response.file, - content_type, + content_type: content_response.content_type, content_disposition, cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()), diff --git a/src/core/utils/content_disposition.rs b/src/core/utils/content_disposition.rs index be182548..90a85c25 100644 --- a/src/core/utils/content_disposition.rs +++ b/src/core/utils/content_disposition.rs @@ -2,8 +2,6 @@ use crate::debug_info; const ATTACHMENT: &str = "attachment"; const INLINE: &str = "inline"; -const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; -const IMAGE_SVG_XML: &str = "image/svg+xml"; /// as defined by MSC2702 const ALLOWED_INLINE_CONTENT_TYPES: [&str; 26] = [ @@ -56,29 +54,6 @@ pub fn content_disposition_type(buf: &[u8], content_type: &Option) -> &' } } -/// overrides the Content-Type with what we detected -/// -/// SVG is special-cased due to the MIME type being classified as `text/xml` but -/// browsers need `image/svg+xml` -#[must_use] -#[tracing::instrument(skip(buf))] -pub fn make_content_type(buf: &[u8], content_type: &Option) -> &'static str { - let Some(claimed_content_type) = content_type else { - return APPLICATION_OCTET_STREAM; - }; - - let Some(file_type) = infer::get(buf) else { - debug_info!("Failed to infer the file's contents"); - return APPLICATION_OCTET_STREAM; - }; - - if claimed_content_type.contains("svg") && file_type.mime_type().contains("xml") { - return IMAGE_SVG_XML; - } - - file_type.mime_type() -} - /// sanitises the file name for the Content-Disposition using /// `sanitize_filename` crate #[tracing::instrument]