Guess mime type based on path

Try to determine the mime type of a file first based on its path, then
based on its content.

The previous behavior (looking only at the file content) inferred a
mime type of `text/xml` for `.svg` files (instead of `image/svg+xml`)
which prevented them from being shown when embedded e.g. in a markdown
document.
This commit is contained in:
Defelo
2025-09-15 12:53:33 +02:00
parent ed41e5529a
commit 23d608d433
3 changed files with 29 additions and 9 deletions
+17
View File
@@ -1468,6 +1468,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "miniz_oxide"
version = "0.7.4"
@@ -2019,6 +2029,7 @@ dependencies = [
"infer",
"lexopt",
"lru",
"mime_guess",
"nonempty 0.12.0",
"pretty_assertions",
"radicle",
@@ -2941,6 +2952,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicase"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
[[package]]
name = "unicode-display-width"
version = "0.3.0"
+1
View File
@@ -30,6 +30,7 @@ hyper = { version = "1.6.0", default-features = false }
infer = { version = "0.19.0" }
lexopt = { version = "0.3.1" }
lru = { version = "0.16.0" }
mime_guess = { version = "2.0.5" }
nonempty = { version = "0.12.0", features = ["serialize"] }
radicle = { version = "0.18.0" }
radicle-surf = { version = "0.22.0", default-features = false, features = ["serde"] }
+11 -9
View File
@@ -74,7 +74,7 @@ async fn file_by_commit_handler(
let repo: Repository = repo.backend.into();
let blob = repo.blob(sha, &path)?;
blob_response(blob)
blob_response(blob, &path)
}
async fn archive_by_refname_handler(
@@ -173,22 +173,24 @@ async fn file_by_canonical_head_handler(
let repo: Repository = repo.backend.into();
let blob = repo.blob(sha, &path)?;
blob_response(blob)
blob_response(blob, &path)
}
fn blob_response(blob: Blob<BlobRef>) -> Result<(StatusCode, HeaderMap, Vec<u8>), Error> {
fn blob_response(
blob: Blob<BlobRef>,
path: &str,
) -> Result<(StatusCode, HeaderMap, Vec<u8>), Error> {
let mut response_headers = HeaderMap::new();
if blob.size() > MAX_BLOB_SIZE {
return Ok::<_, Error>((StatusCode::PAYLOAD_TOO_LARGE, response_headers, vec![]));
}
let content = blob.content();
let mime = infer::get(content).map(|i| i.mime_type().to_string());
let mime = mime_guess::from_path(path)
.first_raw()
.or_else(|| infer::get(blob.content()).map(|i| i.mime_type()))
.unwrap_or("application/octet-stream");
response_headers.insert(
header::CONTENT_TYPE,
HeaderValue::from_str(&mime.unwrap_or("application/octet-stream".to_string()))?,
);
response_headers.insert(header::CONTENT_TYPE, HeaderValue::from_str(mime)?);
Ok::<_, Error>((StatusCode::OK, response_headers, blob.content().to_owned()))
}