httpd: Set a max allowed size of 4 MiB when serving files raw

Signed-off-by: xphoniex <dj.2dixx@gmail.com>
This commit is contained in:
xphoniex 2023-03-06 17:23:08 +00:00 committed by Alexis Sellier
parent 85df613682
commit 488468991c
No known key found for this signature in database
2 changed files with 97 additions and 5 deletions

View File

@ -35,6 +35,10 @@ pub enum Error {
/// Surf error.
#[error(transparent)]
Surf(#[from] radicle_surf::Error),
// Surf file error.
#[error(transparent)]
SurfFile(#[from] radicle_surf::fs::error::File),
}
impl Error {

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use axum::extract::State;
use axum::http::header;
use axum::http::{header, StatusCode};
use axum::response::IntoResponse;
use axum::routing::get;
use axum::Router;
@ -15,6 +15,80 @@ use radicle_surf::{Oid, Repository};
use crate::axum_extra::Path;
use crate::error::Error;
const MAX_BLOB_SIZE: usize = 4_194_304;
static MIMES: &[(&str, &str)] = &[
("3gp", "video/3gpp"),
("7z", "application/x-7z-compressed"),
("aac", "audio/aac"),
("avi", "video/x-msvideo"),
("bin", "application/octet-stream"),
("bmp", "image/bmp"),
("bz", "application/x-bzip"),
("bz2", "application/x-bzip2"),
("csh", "application/x-csh"),
("css", "text/css"),
("csv", "text/csv"),
("doc", "application/msword"),
(
"docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
),
("epub", "application/epub+zip"),
("gz", "application/gzip"),
("gif", "image/gif"),
("htm", "text/html"),
("html", "text/html"),
("ico", "image/vnd.microsoft.icon"),
("jar", "application/java-archive"),
("jpeg", "image/jpeg"),
("jpg", "image/jpeg"),
("js", "text/javascript"),
("json", "application/json"),
("mjs", "text/javascript"),
("mp3", "audio/mpeg"),
("mp4", "video/mp4"),
("mpeg", "video/mpeg"),
("odp", "application/vnd.oasis.opendocument.presentation"),
("ods", "application/vnd.oasis.opendocument.spreadsheet"),
("odt", "application/vnd.oasis.opendocument.text"),
("oga", "audio/ogg"),
("ogv", "video/ogg"),
("ogx", "application/ogg"),
("otf", "font/otf"),
("png", "image/png"),
("pdf", "application/pdf"),
("php", "application/x-httpd-php"),
("ppt", "application/vnd.ms-powerpoint"),
(
"pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
),
("rar", "application/vnd.rar"),
("rtf", "application/rtf"),
("sh", "application/x-sh"),
("svg", "image/svg+xml"),
("tar", "application/x-tar"),
("tif", "image/tiff"),
("tiff", "image/tiff"),
("ttf", "font/ttf"),
("txt", "text/plain"),
("wav", "audio/wav"),
("weba", "audio/webm"),
("webm", "video/webm"),
("webp", "image/webp"),
("woff", "font/woff"),
("woff2", "font/woff2"),
("xhtml", "application/xhtml+xml"),
("xls", "application/vnd.ms-excel"),
(
"xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
),
("xml", "application/xml"),
("zip", "application/zip"),
];
pub fn router(profile: Arc<Profile>) -> Router {
Router::new()
.route("/:project/:sha/*path", get(file_handler))
@ -27,12 +101,26 @@ async fn file_handler(
) -> impl IntoResponse {
let storage = &profile.storage;
let repo = Repository::open(paths::repository(storage, &project))?;
let blob = repo.blob(sha, &path)?;
let mut response_headers = HeaderMap::new();
response_headers.insert(header::CONTENT_TYPE, "text; charset=utf-8".parse().unwrap());
Ok::<_, Error>((response_headers, blob.content().to_owned()))
if repo.file(sha, &path)?.content(&repo)?.size() > MAX_BLOB_SIZE {
return Ok::<_, Error>((StatusCode::PAYLOAD_TOO_LARGE, response_headers, vec![]));
}
let blob = repo.blob(sha, &path)?;
let mime = {
if let Some(ext) = path.split('.').last() {
MIMES
.binary_search_by(|(k, _)| k.cmp(&ext))
.map(|k| MIMES[k].1)
.unwrap_or("text; charset=utf-8")
} else {
"application/octet-stream"
}
};
response_headers.insert(header::CONTENT_TYPE, mime.parse().unwrap());
Ok::<_, Error>((StatusCode::OK, response_headers, blob.content().to_owned()))
}
#[cfg(test)]