Skip to content

Commit bf5ace6

Browse files
authored
Merge pull request #318 from sunfishcode/main
Rename Body::from_file to Body::from_path, add Body::from_file, handle filename-based MIME-type guessing for File objects
2 parents d6f16af + 096c24c commit bf5ace6

File tree

2 files changed

+63
-10
lines changed

2 files changed

+63
-10
lines changed

src/body.rs

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,11 @@ impl Body {
351351
Ok(serde_urlencoded::from_str(&s).status(StatusCode::UnprocessableEntity)?)
352352
}
353353

354-
/// Create a `Body` from a file.
354+
/// Create a `Body` from a file named by a path.
355355
///
356-
/// The Mime type set to `application/octet-stream` if no other mime type has
357-
/// been set or can be sniffed.
356+
/// The Mime type is sniffed from the file contents if possible, otherwise
357+
/// it is inferred from the path's extension if possible, otherwise is set
358+
/// to `application/octet-stream`.
358359
///
359360
/// # Examples
360361
///
@@ -363,16 +364,68 @@ impl Body {
363364
/// use http_types::{Body, Response, StatusCode};
364365
///
365366
/// let mut res = Response::new(StatusCode::Ok);
366-
/// res.set_body(Body::from_file("/path/to/file").await?);
367+
/// res.set_body(Body::from_path("/path/to/file").await?);
367368
/// # Ok(()) }) }
368369
/// ```
369370
#[cfg(all(feature = "fs", not(target_os = "unknown")))]
370-
pub async fn from_file<P>(path: P) -> io::Result<Self>
371+
pub async fn from_path<P>(path: P) -> io::Result<Self>
371372
where
372373
P: AsRef<std::path::Path>,
373374
{
374375
let path = path.as_ref();
375-
let mut file = async_std::fs::File::open(path).await?;
376+
let file = async_std::fs::File::open(path).await?;
377+
Self::from_file_with_path(file, path).await
378+
}
379+
380+
/// Create a `Body` from an already-open file.
381+
///
382+
/// The Mime type is sniffed from the file contents if possible, otherwise
383+
/// is set to `application/octet-stream`.
384+
///
385+
/// # Examples
386+
///
387+
/// ```no_run
388+
/// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
389+
/// use http_types::{Body, Response, StatusCode};
390+
///
391+
/// let mut res = Response::new(StatusCode::Ok);
392+
/// let path = std::path::Path::new("/path/to/file");
393+
/// let file = async_std::fs::File::open(path).await?;
394+
/// res.set_body(Body::from_file(file).await?);
395+
/// # Ok(()) }) }
396+
/// ```
397+
#[cfg(all(feature = "fs", not(target_os = "unknown")))]
398+
#[inline]
399+
pub async fn from_file(file: async_std::fs::File) -> io::Result<Self> {
400+
Self::from_file_with_path(file, std::path::Path::new("")).await
401+
}
402+
403+
/// Create a `Body` from an already-open file.
404+
///
405+
/// The Mime type is sniffed from the file contents if possible, otherwise
406+
/// it is inferred from the path's extension if possible, otherwise is set
407+
/// to `application/octet-stream`.
408+
///
409+
/// The path here is only used to provide an extension for guessing the Mime
410+
/// type, and may be empty if the path is unknown.
411+
///
412+
/// # Examples
413+
///
414+
/// ```no_run
415+
/// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
416+
/// use http_types::{Body, Response, StatusCode};
417+
///
418+
/// let mut res = Response::new(StatusCode::Ok);
419+
/// let path = std::path::Path::new("/path/to/file");
420+
/// let file = async_std::fs::File::open(path).await?;
421+
/// res.set_body(Body::from_file_with_path(file, path).await?);
422+
/// # Ok(()) }) }
423+
/// ```
424+
#[cfg(all(feature = "fs", not(target_os = "unknown")))]
425+
pub async fn from_file_with_path(
426+
mut file: async_std::fs::File,
427+
path: &std::path::Path,
428+
) -> io::Result<Self> {
376429
let len = file.metadata().await?.len();
377430

378431
// Look at magic bytes first, look at extension second, fall back to

tests/mime.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod tests {
66

77
#[async_std::test]
88
async fn guess_plain_text_mime() -> io::Result<()> {
9-
let body = Body::from_file("tests/fixtures/index.html").await?;
9+
let body = Body::from_path("tests/fixtures/index.html").await?;
1010
let mut res = Response::new(200);
1111
res.set_body(body);
1212
assert_eq!(res.content_type(), Some(mime::HTML));
@@ -15,7 +15,7 @@ mod tests {
1515

1616
#[async_std::test]
1717
async fn guess_binary_mime() -> http_types::Result<()> {
18-
let body = Body::from_file("tests/fixtures/nori.png").await?;
18+
let body = Body::from_path("tests/fixtures/nori.png").await?;
1919
let mut res = Response::new(200);
2020
res.set_body(body);
2121
assert_eq!(res.content_type(), Some(mime::PNG));
@@ -29,7 +29,7 @@ mod tests {
2929

3030
#[async_std::test]
3131
async fn guess_mime_fallback() -> io::Result<()> {
32-
let body = Body::from_file("tests/fixtures/unknown.custom").await?;
32+
let body = Body::from_path("tests/fixtures/unknown.custom").await?;
3333
let mut res = Response::new(200);
3434
res.set_body(body);
3535
assert_eq!(res.content_type(), Some(mime::BYTE_STREAM));
@@ -38,7 +38,7 @@ mod tests {
3838

3939
#[async_std::test]
4040
async fn parse_empty_files() -> http_types::Result<()> {
41-
let body = Body::from_file("tests/fixtures/empty.custom").await?;
41+
let body = Body::from_path("tests/fixtures/empty.custom").await?;
4242
let mut res = Response::new(200);
4343
res.set_body(body);
4444
assert_eq!(res.content_type(), Some(mime::BYTE_STREAM));

0 commit comments

Comments
 (0)