Unverified Commit ba189bad authored by 唐小鸭's avatar 唐小鸭 Committed by GitHub
Browse files

feat(s3s): allow custom content type (#389)



* don‘t check content_type

* ContentType change String

* fix build s3s-aws

* fix ci check

* Refactor extract_mime function to simplify content type parsing

* remove unwrap

* Update crates/s3s/src/ops/signature.rs

Co-authored-by: default avatarCopilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: default avatarNugine <nugine@foxmail.com>
Co-authored-by: default avatarCopilot <175728472+Copilot@users.noreply.github.com>
parent 85144c53
Loading
Loading
Loading
Loading
+0 −13
Original line number Diff line number Diff line
@@ -69,19 +69,6 @@ impl AwsConversion for s3s::dto::Timestamp {
    }
}

impl AwsConversion for s3s::dto::ContentType {
    type Target = String;
    type Error = S3Error;

    fn try_from_aws(x: Self::Target) -> S3Result<Self> {
        x.parse::<Self>().map_err(S3Error::internal_error)
    }

    fn try_into_aws(x: Self) -> S3Result<Self::Target> {
        Ok(x.to_string())
    }
}

impl AwsConversion for s3s::dto::CopySource {
    type Target = String;
    type Error = S3Error;
+1 −1
Original line number Diff line number Diff line
@@ -289,7 +289,7 @@ impl S3 for FileSystem {
        let object_metadata = self.load_metadata(&input.bucket, &input.key, None).await?;

        // TODO: detect content type
        let content_type = mime::APPLICATION_OCTET_STREAM;
        let content_type = ContentType::from("application/octet-stream");

        let output = HeadObjectOutput {
            content_length: Some(try_!(i64::try_from(file_len))),
+1 −30
Original line number Diff line number Diff line
use crate::http;

use hyper::header::InvalidHeaderValue;

pub type ContentType = mime::Mime;

#[derive(Debug, thiserror::Error)]
pub enum ParseContentTypeError {
    #[error("Expected UTF-8")]
    ExpectedUtf8,
    #[error("Mime: {0}")]
    Mime(mime::FromStrError),
}

impl http::TryFromHeaderValue for ContentType {
    type Error = ParseContentTypeError;

    fn try_from_header_value(val: &http::HeaderValue) -> Result<Self, Self::Error> {
        let val = val.to_str().map_err(|_| ParseContentTypeError::ExpectedUtf8)?;
        val.parse().map_err(ParseContentTypeError::Mime)
    }
}

impl http::TryIntoHeaderValue for ContentType {
    type Error = InvalidHeaderValue;

    fn try_into_header_value(self) -> Result<http::HeaderValue, Self::Error> {
        http::HeaderValue::from_str(self.as_ref())
    }
}
pub type ContentType = String;
+5 −8
Original line number Diff line number Diff line
@@ -144,18 +144,15 @@ fn extract_headers(headers: &HeaderMap) -> S3Result<OrderedHeaders<'_>> {
    OrderedHeaders::from_headers(headers).map_err(|source| invalid_request!(source, "invalid headers"))
}

fn extract_mime(hs: &OrderedHeaders<'_>) -> S3Result<Option<Mime>> {
    let Some(content_type) = hs.get_unique(crate::header::CONTENT_TYPE) else { return Ok(None) };
fn extract_mime(hs: &OrderedHeaders<'_>) -> Option<Mime> {
    let content_type = hs.get_unique(crate::header::CONTENT_TYPE)?;

    // https://github.com/s3s-project/s3s/issues/361
    if content_type.is_empty() {
        return Ok(None);
        return None;
    }

    match content_type.parse::<Mime>() {
        Ok(x) => Ok(Some(x)),
        Err(e) => Err(invalid_request!(e, "invalid content type: {content_type:?}")),
    }
    content_type.parse::<Mime>().ok()
}

fn extract_content_length(req: &Request) -> Option<u64> {
@@ -302,7 +299,7 @@ async fn prepare(req: &mut Request, ccx: &CallContext<'_>) -> S3Result<Prepare>
        content_length = extract_content_length(req);

        let hs = extract_headers(&req.headers)?;
        let mime = extract_mime(&hs)?;
        let mime = extract_mime(&hs);
        let decoded_content_length = extract_decoded_content_length(&hs)?;

        let body_changed;
+3 −1
Original line number Diff line number Diff line
@@ -115,7 +115,9 @@ impl SignatureContext<'_> {
    #[tracing::instrument(skip(self))]
    async fn check_post_signature(&mut self) -> S3Result<CredentialsExt> {
        let multipart = {
            let mime = self.mime.as_ref().unwrap(); // assume: multipart
            let Some(mime) = self.mime.as_ref() else {
                return Err(invalid_request!("internal error: mime was unexpectedly None"));
            };

            let boundary = mime
                .get_param(mime::BOUNDARY)