diff --git a/core/codegen/src/lib.rs b/core/codegen/src/lib.rs index 10d70a92..fe035993 100644 --- a/core/codegen/src/lib.rs +++ b/core/codegen/src/lib.rs @@ -667,7 +667,7 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream { /// # #[macro_use] extern crate rocket; /// # use std::fs::File; /// # use rocket::http::ContentType; -/// # use rocket::response::NamedFile; +/// # use rocket::fs::NamedFile; /// # type Other = usize; /// # /// #[derive(Responder)] @@ -710,7 +710,7 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream { /// ```rust /// # #[macro_use] extern crate rocket; /// # use rocket::http::ContentType; -/// # use rocket::response::NamedFile; +/// # use rocket::fs::NamedFile; /// # type Other = usize; /// # type InnerResponder = String; /// # diff --git a/core/codegen/tests/from_form.rs b/core/codegen/tests/from_form.rs index 2b6c65df..cdda26ed 100644 --- a/core/codegen/tests/from_form.rs +++ b/core/codegen/tests/from_form.rs @@ -568,7 +568,7 @@ fn test_nested_multi() { fn test_multipart() { use rocket::http::ContentType; use rocket::local::blocking::Client; - use rocket::data::TempFile; + use rocket::fs::TempFile; #[derive(FromForm)] struct MyForm<'r> { diff --git a/core/lib/src/data/capped.rs b/core/lib/src/data/capped.rs index 3627abe1..e1e2aa2a 100644 --- a/core/lib/src/data/capped.rs +++ b/core/lib/src/data/capped.rs @@ -41,7 +41,8 @@ impl std::ops::Deref for N { /// /// ```rust /// # #[macro_use] extern crate rocket; -/// use rocket::data::{Capped, TempFile}; +/// use rocket::data::Capped; +/// use rocket::fs::TempFile; /// /// #[post("/upload", data = "")] /// async fn upload(mut file: Capped>) -> std::io::Result<()> { @@ -58,7 +59,7 @@ impl std::ops::Deref for N { /// [`DataStream`]: crate::data::DataStream /// [`FromData`]: crate::data::FromData /// [`FromForm`]: crate::form::FromForm -/// [`TempFile`]: crate::data::TempFile +/// [`TempFile`]: crate::fs::TempFile // TODO: `Capped` not particularly usable outside Rocket due to coherence. #[derive(Debug, Copy, Clone)] pub struct Capped { diff --git a/core/lib/src/data/limits.rs b/core/lib/src/data/limits.rs index 714e83bc..f7b65f1c 100644 --- a/core/lib/src/data/limits.rs +++ b/core/lib/src/data/limits.rs @@ -67,7 +67,7 @@ use crate::http::uncased::Uncased; /// | `json` | 1MiB | [`Json`] | JSON data and form payloads | /// | `msgpack` | 1MiB | [`MsgPack`] | MessagePack data and form payloads | /// -/// [`TempFile`]: crate::data::TempFile +/// [`TempFile`]: crate::fs::TempFile /// [`Json`]: crate::serde::json::Json /// [`MsgPack`]: crate::serde::msgpack::MsgPack /// diff --git a/core/lib/src/data/mod.rs b/core/lib/src/data/mod.rs index fd90316e..2d6691e5 100644 --- a/core/lib/src/data/mod.rs +++ b/core/lib/src/data/mod.rs @@ -6,7 +6,6 @@ mod data; mod data_stream; mod from_data; mod limits; -mod temp_file; pub use self::data::Data; pub use self::data_stream::DataStream; @@ -14,6 +13,5 @@ pub use self::from_data::{FromData, Outcome}; pub use self::limits::Limits; pub use self::capped::{N, Capped}; pub use ubyte::{ByteUnit, ToByteUnit}; -pub use temp_file::TempFile; pub(crate) use self::data_stream::StreamReader; diff --git a/core/lib/src/form/field.rs b/core/lib/src/form/field.rs index 0f887538..9bd80876 100644 --- a/core/lib/src/form/field.rs +++ b/core/lib/src/form/field.rs @@ -1,7 +1,7 @@ -use crate::form::name::{NameView, FileName}; -use crate::form::error::{Error, ErrorKind, Entity}; +use crate::form::{name::NameView, error::{Error, ErrorKind, Entity}}; use crate::http::{ContentType, RawStr}; use crate::{Request, Data}; +use crate::fs::FileName; /// A form field with a string value. /// diff --git a/core/lib/src/form/from_form.rs b/core/lib/src/form/from_form.rs index cce8f824..4b336ee9 100644 --- a/core/lib/src/form/from_form.rs +++ b/core/lib/src/form/from_form.rs @@ -129,7 +129,7 @@ use crate::http::uncased::AsUncased; /// [`Lenient`]: crate::form::Lenient /// [`HashMap`]: std::collections::HashMap /// [`BTreeMap`]: std::collections::BTreeMap -/// [`TempFile`]: crate::data::TempFile +/// [`TempFile`]: crate::fs::TempFile /// [`Capped`]: crate::data::Capped /// [`time::DateTime`]: time::PrimitiveDateTime /// [`IpAddr`]: std::net::IpAddr diff --git a/core/lib/src/form/name/mod.rs b/core/lib/src/form/name/mod.rs index bfbd90ea..82e05853 100644 --- a/core/lib/src/form/name/mod.rs +++ b/core/lib/src/form/name/mod.rs @@ -4,10 +4,8 @@ mod name; mod view; mod key; mod buf; -mod file_name; pub use name::Name; pub use view::NameView; pub use key::Key; pub use buf::NameBuf; -pub use file_name::FileName; diff --git a/core/lib/src/form/parser.rs b/core/lib/src/form/parser.rs index 9e050a65..eb57b4ed 100644 --- a/core/lib/src/form/parser.rs +++ b/core/lib/src/form/parser.rs @@ -183,7 +183,7 @@ impl<'r, 'i> MultipartParser<'r, 'i> { content_type, request: self.request, name: NameView::new(name), - file_name: file_name.map(FileName::new), + file_name: file_name.map(crate::fs::FileName::new), data: Data::from(field), }) } else { diff --git a/core/lib/src/form/validate.rs b/core/lib/src/form/validate.rs index b4d08e6a..71a3f001 100644 --- a/core/lib/src/form/validate.rs +++ b/core/lib/src/form/validate.rs @@ -86,7 +86,7 @@ use std::fmt::Debug; use crate::data::ByteUnit; use rocket_http::ContentType; -use crate::{data::TempFile, form::{Result, Error}}; +use crate::{fs::TempFile, form::{Result, Error}}; crate::export! { /// A helper macro for custom validation error messages. @@ -360,7 +360,8 @@ impl> Len for Result<'_, T> { /// ```rust /// use rocket::http::ContentType; /// use rocket::form::{FromForm, FromFormField}; -/// use rocket::data::{TempFile, ToByteUnit}; +/// use rocket::data::ToByteUnit; +/// use rocket::fs::TempFile; /// /// #[derive(FromForm)] /// struct Foo<'r> { @@ -724,8 +725,9 @@ pub fn one_of<'v, V, I, R>(value: V, items: R) -> Result<'v, ()> /// /// ```rust /// use rocket::form::FromForm; -/// use rocket::data::{ToByteUnit, TempFile}; +/// use rocket::data::ToByteUnit; /// use rocket::http::ContentType; +/// use rocket::fs::TempFile; /// /// #[derive(FromForm)] /// struct Foo<'r> { diff --git a/core/lib/src/form/name/file_name.rs b/core/lib/src/fs/file_name.rs similarity index 96% rename from core/lib/src/form/name/file_name.rs rename to core/lib/src/fs/file_name.rs index 8fc61ea9..831da79d 100644 --- a/core/lib/src/form/name/file_name.rs +++ b/core/lib/src/fs/file_name.rs @@ -2,7 +2,7 @@ use ref_cast::RefCast; use crate::http::RawStr; -/// A file name in a file attachment or multipart [`DataField`]. +/// A file name in a [`TempFile`] or multipart [`DataField`]. /// /// A `Content-Disposition` header, either in a response or a multipart field, /// can optionally specify a `filename` directive as identifying information for @@ -21,8 +21,9 @@ use crate::http::RawStr; /// may also prefer to avoid the value in the directive entirely by using a /// safe, application-generated name instead. /// -/// [`TempFile::name()`]: crate::data::TempFile::name +/// [`TempFile::name()`]: crate::fs::TempFile::name /// [`DataField`]: crate::form::DataField +/// [`TempFile`]: crate::fs::TempFile #[repr(transparent)] #[derive(RefCast, Debug)] pub struct FileName(str); @@ -33,7 +34,7 @@ impl FileName { /// # Example /// /// ```rust - /// use rocket::form::name::FileName; + /// use rocket::fs::FileName; /// /// let name = FileName::new("some-file.txt"); /// assert_eq!(name.as_str(), Some("some-file")); @@ -72,7 +73,7 @@ impl FileName { /// # Example /// /// ```rust - /// use rocket::form::name::FileName; + /// use rocket::fs::FileName; /// /// let name = FileName::new("some-file.txt"); /// assert_eq!(name.as_str(), Some("some-file")); @@ -177,7 +178,7 @@ impl FileName { /// # Example /// /// ```rust - /// use rocket::form::name::FileName; + /// use rocket::fs::FileName; /// /// let name = FileName::new("some-file.txt"); /// assert_eq!(name.as_str(), Some("some-file")); @@ -216,7 +217,7 @@ impl FileName { /// # Example /// /// ```rust - /// use rocket::form::name::FileName; + /// use rocket::fs::FileName; /// /// let name = FileName::new("some-file.txt"); /// assert_eq!(name.dangerous_unsafe_unsanitized_raw(), "some-file.txt"); diff --git a/core/lib/src/fs/mod.rs b/core/lib/src/fs/mod.rs index b61e50a0..dd00f179 100644 --- a/core/lib/src/fs/mod.rs +++ b/core/lib/src/fs/mod.rs @@ -1,6 +1,12 @@ -//! File serving, file accepting, and file system types. +//! File serving, file accepting, and file metadata types. mod server; +mod named_file; +mod temp_file; +mod file_name; pub use server::*; +pub use named_file::*; +pub use temp_file::*; +pub use file_name::*; pub use server::relative; diff --git a/core/lib/src/response/named_file.rs b/core/lib/src/fs/named_file.rs similarity index 80% rename from core/lib/src/response/named_file.rs rename to core/lib/src/fs/named_file.rs index e810ceeb..29093582 100644 --- a/core/lib/src/response/named_file.rs +++ b/core/lib/src/fs/named_file.rs @@ -8,8 +8,33 @@ use crate::request::Request; use crate::response::{self, Responder}; use crate::http::ContentType; -/// A file with an associated name; responds with the Content-Type based on the -/// file extension. +/// A [`Responder`] that sends a file with a Content-Type based on its name. +/// +/// # Example +/// +/// A simple static file server mimicking [`FileServer`]: +/// +/// ```rust +/// # use rocket::get; +/// use std::path::{PathBuf, Path}; +/// +/// use rocket::fs::{NamedFile, relative}; +/// +/// #[get("/file/")] +/// pub async fn second(path: PathBuf) -> Option { +/// let mut path = Path::new(relative!("static")).join(path); +/// if path.is_dir() { +/// path.push("index.html"); +/// } +/// +/// NamedFile::open(path).await.ok() +/// } +/// ``` +/// +/// Always prefer to use [`FileServer`] which has more functionality and a +/// pithier API. +/// +/// [`FileServer`]: crate::fs::FileServer #[derive(Debug)] pub struct NamedFile(PathBuf, File); @@ -26,7 +51,7 @@ impl NamedFile { /// /// ```rust /// # use rocket::get; - /// use rocket::response::NamedFile; + /// use rocket::fs::NamedFile; /// /// #[get("/")] /// async fn index() -> Option { @@ -47,7 +72,7 @@ impl NamedFile { /// # Example /// /// ```rust - /// use rocket::response::NamedFile; + /// use rocket::fs::NamedFile; /// /// # async fn f() -> std::io::Result<()> { /// let named_file = NamedFile::open("index.html").await?; @@ -65,7 +90,7 @@ impl NamedFile { /// # Example /// /// ```rust - /// use rocket::response::NamedFile; + /// use rocket::fs::NamedFile; /// /// # async fn f() -> std::io::Result<()> { /// let mut named_file = NamedFile::open("index.html").await?; @@ -83,7 +108,7 @@ impl NamedFile { /// # Example /// /// ```rust - /// use rocket::response::NamedFile; + /// use rocket::fs::NamedFile; /// /// # async fn f() -> std::io::Result<()> { /// let named_file = NamedFile::open("index.html").await?; @@ -101,7 +126,7 @@ impl NamedFile { /// # Examples /// /// ```rust - /// use rocket::response::NamedFile; + /// use rocket::fs::NamedFile; /// /// # async fn demo_path() -> std::io::Result<()> { /// let file = NamedFile::open("foo.txt").await?; diff --git a/core/lib/src/fs/server.rs b/core/lib/src/fs/server.rs index 33058810..86e94f9c 100644 --- a/core/lib/src/fs/server.rs +++ b/core/lib/src/fs/server.rs @@ -2,8 +2,9 @@ use std::path::{PathBuf, Path}; use crate::{Request, Data}; use crate::http::{Method, uri::Segments, ext::IntoOwned}; -use crate::response::{NamedFile, Redirect}; use crate::route::{Route, Handler, Outcome}; +use crate::response::Redirect; +use crate::fs::NamedFile; /// Custom handler for serving static files. /// diff --git a/core/lib/src/data/temp_file.rs b/core/lib/src/fs/temp_file.rs similarity index 96% rename from core/lib/src/data/temp_file.rs rename to core/lib/src/fs/temp_file.rs index b7a6378f..47d29a19 100644 --- a/core/lib/src/data/temp_file.rs +++ b/core/lib/src/fs/temp_file.rs @@ -1,23 +1,24 @@ use std::{io, mem}; use std::path::{PathBuf, Path}; +use crate::Request; use crate::http::{ContentType, Status}; use crate::data::{FromData, Data, Capped, N, Limits}; -use crate::form::{FromFormField, ValueField, DataField, error::Errors, name::FileName}; +use crate::form::{FromFormField, ValueField, DataField, error::Errors}; use crate::outcome::IntoOutcome; -use crate::request::Request; +use crate::fs::FileName; use tokio::fs::{self, File}; use tokio::io::AsyncWriteExt; use tempfile::{NamedTempFile, TempPath}; use either::Either; -/// A file in temporary storage, deleted when dropped unless persisted. +/// A data and form guard that streams data into a temporary file. /// /// `TempFile` is a data and form field (both value and data fields) guard that /// streams incoming data into file in a temporary location. The file is deleted -/// when the `TempFile` handle is dropped. The file can be persisted with -/// [`TempFile::persist_to()`]. +/// when the `TempFile` handle is dropped unless it is persisted with +/// [`TempFile::persist_to()`] or copied with [`TempFile::copy_to()`]. /// /// # Hazards /// @@ -67,7 +68,7 @@ use either::Either; /// /// ```rust /// # use rocket::post; -/// use rocket::data::TempFile; +/// use rocket::fs::TempFile; /// /// #[post("/upload", data = "")] /// async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -80,7 +81,7 @@ use either::Either; /// /// ```rust /// # #[macro_use] extern crate rocket; -/// use rocket::data::TempFile; +/// use rocket::fs::TempFile; /// use rocket::form::Form; /// /// #[derive(FromForm)] @@ -147,7 +148,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -216,7 +217,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -285,7 +286,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -319,7 +320,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// fn handler(file: TempFile<'_>) { @@ -342,7 +343,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -381,7 +382,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -402,7 +403,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// async fn handle(mut file: TempFile<'_>) { @@ -424,7 +425,7 @@ impl<'v> TempFile<'v> { /// /// ```rust /// # #[macro_use] extern crate rocket; - /// use rocket::data::TempFile; + /// use rocket::fs::TempFile; /// /// #[post("/", data = "")] /// fn handle(file: TempFile<'_>) { diff --git a/core/lib/src/response/debug.rs b/core/lib/src/response/debug.rs index 6225217a..2c6e5c26 100644 --- a/core/lib/src/response/debug.rs +++ b/core/lib/src/response/debug.rs @@ -18,7 +18,7 @@ use yansi::Paint; /// use std::io; /// /// # use rocket::get; -/// use rocket::response::NamedFile; +/// use rocket::fs::NamedFile; /// /// #[get("/")] /// async fn index() -> io::Result { diff --git a/core/lib/src/response/mod.rs b/core/lib/src/response/mod.rs index f9d7afef..b8c799de 100644 --- a/core/lib/src/response/mod.rs +++ b/core/lib/src/response/mod.rs @@ -25,7 +25,6 @@ mod responder; mod redirect; -mod named_file; mod response; mod debug; mod body; @@ -44,7 +43,6 @@ pub use self::body::Body; pub use self::responder::Responder; pub use self::redirect::Redirect; pub use self::flash::Flash; -pub use self::named_file::NamedFile; pub use self::debug::Debug; /// Type alias for the `Result` of a [`Responder::respond_to()`] call. diff --git a/core/lib/src/response/responder.rs b/core/lib/src/response/responder.rs index 7be1ad80..7c302a98 100644 --- a/core/lib/src/response/responder.rs +++ b/core/lib/src/response/responder.rs @@ -69,7 +69,7 @@ use crate::request::Request; /// /// Responds with a streamed body containing the data in the `File`. No /// `Content-Type` is set. To automatically have a `Content-Type` set based -/// on the file's extension, use [`NamedFile`](crate::response::NamedFile). +/// on the file's extension, use [`NamedFile`](crate::fs::NamedFile). /// /// * **()** /// diff --git a/examples/forms/src/main.rs b/examples/forms/src/main.rs index a8930f26..8ea49b05 100644 --- a/examples/forms/src/main.rs +++ b/examples/forms/src/main.rs @@ -2,7 +2,7 @@ use rocket::http::{Status, ContentType}; use rocket::form::{Form, Contextual, FromForm, FromFormField, Context}; -use rocket::data::TempFile; +use rocket::fs::TempFile; use rocket::fs::{FileServer, relative}; use rocket_contrib::templates::Template; diff --git a/examples/responders/src/main.rs b/examples/responders/src/main.rs index bcbf082a..934574ec 100644 --- a/examples/responders/src/main.rs +++ b/examples/responders/src/main.rs @@ -8,8 +8,8 @@ use std::{io, env}; use rocket::tokio::fs; -use rocket::data::{Capped, TempFile}; -use rocket::response::NamedFile; +use rocket::data::Capped; +use rocket::fs::{NamedFile, TempFile}; // Upload your `big_file.dat` by POSTing it to /upload. // try `curl --data-binary @file.txt http://127.0.0.1:8000/stream/file` diff --git a/examples/static-files/src/main.rs b/examples/static-files/src/main.rs index fce5f5b5..53c42708 100644 --- a/examples/static-files/src/main.rs +++ b/examples/static-files/src/main.rs @@ -6,7 +6,7 @@ use rocket::fs::{FileServer, relative}; // prefer to use `FileServer`! mod manual { use std::path::{PathBuf, Path}; - use rocket::response::NamedFile; + use rocket::fs::NamedFile; #[rocket::get("/second/")] pub async fn second(path: PathBuf) -> Option { diff --git a/site/guide/3-overview.md b/site/guide/3-overview.md index a9058f5d..0ad54870 100644 --- a/site/guide/3-overview.md +++ b/site/guide/3-overview.md @@ -303,7 +303,7 @@ use rocket::response::Debug; #[get("/blocking_task")] async fn blocking_task() -> Result, Debug> { - // In a real app, use rocket::response::NamedFile or tokio::fs::File. + // In a real app, use rocket::fs::NamedFile or tokio::fs::File. let vec = spawn_blocking(|| std::fs::read("data.txt")).await .map_err(|e| io::Error::new(io::ErrorKind::Interrupted, e))??; diff --git a/site/guide/4-requests.md b/site/guide/4-requests.md index b0021faa..61a50ff7 100644 --- a/site/guide/4-requests.md +++ b/site/guide/4-requests.md @@ -141,7 +141,7 @@ implemented in just 4 lines: # fn main() {} use std::path::{Path, PathBuf}; -use rocket::response::NamedFile; +use rocket::fs::NamedFile; #[get("/")] async fn files(file: PathBuf) -> Option { @@ -642,7 +642,7 @@ the be persisted. It makes accepting file uploads trivial: ```rust # #[macro_use] extern crate rocket; -use rocket::data::TempFile; +use rocket::fs::TempFile; #[post("/upload", format = "plain", data = "")] async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> { @@ -651,7 +651,7 @@ async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> { } ``` -[`TempFile`]: @api/rocket/data/struct.TempFile.html +[`TempFile`]: @api/rocket/fs/struct.TempFile.html ### Streaming diff --git a/site/guide/5-responses.md b/site/guide/5-responses.md index 5b8fe9a4..b0354e13 100644 --- a/site/guide/5-responses.md +++ b/site/guide/5-responses.md @@ -227,7 +227,7 @@ found and a `404` when a file is not found in just 4, idiomatic lines: # fn main() {} # use std::path::{Path, PathBuf}; -use rocket::response::NamedFile; +use rocket::fs::NamedFile; #[get("/")] async fn files(file: PathBuf) -> Option { @@ -252,7 +252,7 @@ follows: # fn main() {} # use std::path::{Path, PathBuf}; -use rocket::response::NamedFile; +use rocket::fs::NamedFile; use rocket::response::status::NotFound; #[get("/")]