pub enum TempFile<'v> {
// some variants omitted
}
Expand description
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 unless it is persisted with
TempFile::persist_to()
or copied with TempFile::copy_to()
.
Hazards
Temporary files are cleaned by system file cleaners periodically. While an
attempt is made not to delete temporary files in use, detection of when a
temporary file is being used is unreliable. As a result, a time-of-check to
time-of-use race condition from the creation of a TempFile
to the
persistence of the TempFile
may occur. Specifically, the following
sequence may occur:
- A
TempFile
is created at random pathfoo
. - The system cleaner removes the file at path
foo
. - Another application creates a file at path
foo
. - The
TempFile
, ostensibly at pathfoo
, is persisted unexpectedly with contents different from those in step 1.
To safe-guard against this issue, you should ensure that your temporary file cleaner, if any, does not delete files too eagerly.
Configuration
TempFile
is configured via the following config
parameters:
Name | Default | Description |
---|---|---|
temp_dir | env::temp_dir() | Directory for temporary file storage. |
limits.file | 1MiB | Default limit for all file extensions. |
limits.file/$ext | N/A | Limit for files with extension $ext . |
When used as a form guard, the extension $ext
is identified by the form
field’s Content-Type
(ContentType::extension()
). When used as a data
guard, the extension is identified by the Content-Type of the request, if
any. If there is no Content-Type, the limit file
is used.
Cappable
A data stream can be partially read into a TempFile
even if the incoming
stream exceeds the data limit via the Capped<TempFile>
data and form
guard.
Examples
Data Guard
use rocket::fs::TempFile;
#[post("/upload", data = "<file>")]
async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> {
file.persist_to("/tmp/complete/file.txt").await?;
Ok(())
}
Form Field
use rocket::fs::TempFile;
use rocket::form::Form;
#[derive(FromForm)]
struct Upload<'f> {
upload: TempFile<'f>
}
#[post("/form", data = "<form>")]
async fn upload(mut form: Form<Upload<'_>>) -> std::io::Result<()> {
form.upload.persist_to("/tmp/complete/file.txt").await?;
Ok(())
}
See also the Capped
documentation for an example of Capped<TempFile>
as a data guard.
Implementations§
source§impl<'v> TempFile<'v>
impl<'v> TempFile<'v>
sourcepub async fn persist_to<P>(&mut self, path: P) -> Result<()>where
P: AsRef<Path>,
pub async fn persist_to<P>(&mut self, path: P) -> Result<()>where P: AsRef<Path>,
Persists the temporary file, moving it to path
. If a file exists at
the target path, self
will atomically replace it. self.path()
is
updated to path
.
This method does not create a copy of self
, nor a new link to the
contents of self
: it renames the temporary file to path
and marks it
as non-temporary. As a result, this method cannot be used to create
multiple copies of self
. To create multiple links, use
std::fs::hard_link()
with path
as the src
after calling this
method.
Cross-Device Persistence
Attempting to persist a temporary file across logical devices (or mount points) will result in an error. This is a limitation of the underlying OS. Your options are thus:
-
Store temporary file in the same logical device.
Change the
temp_dir
configuration parameter to be in the same logical device as the permanent location. This is the preferred solution. -
Copy the temporary file using
TempFile::copy_to()
orTempFile::move_copy_to()
instead.This is a full copy of the file, creating a duplicate version of the file at the destination. This should be avoided for performance reasons.
Example
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> {
file.persist_to(&some_path).await?;
assert_eq!(file.path(), Some(&*some_path));
Ok(())
}
sourcepub async fn copy_to<P>(&mut self, path: P) -> Result<()>where
P: AsRef<Path>,
pub async fn copy_to<P>(&mut self, path: P) -> Result<()>where P: AsRef<Path>,
Persists the temporary file at its temporary path and creates a full
copy at path
. The self.path()
is not updated, unless no temporary
file existed prior, and the temporary file is not removed. Thus, there
will be two files with the same contents.
Unlike TempFile::persist_to()
, this method does not incur
cross-device limitations, at the performance cost of a full copy. Prefer
to use persist_to()
with a valid temp_dir
configuration parameter if
no more than one copy of a file is required.
Example
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> {
file.copy_to(&some_path).await?;
file.copy_to(&some_other_path).await?;
assert_eq!(file.path(), Some(&*some_path));
Ok(())
}
sourcepub async fn move_copy_to<P>(&mut self, path: P) -> Result<()>where
P: AsRef<Path>,
pub async fn move_copy_to<P>(&mut self, path: P) -> Result<()>where P: AsRef<Path>,
Persists the temporary file at its temporary path, creates a full copy
at path
, and then deletes the temporary file. self.path()
is updated
to path
.
Like TempFile::copy_to()
and unlike TempFile::persist_to()
, this
method does not incur cross-device limitations, at the performance cost
of a full copy and file deletion. Prefer to use persist_to()
with a
valid temp_dir
configuration parameter if no more than one copy of a
file is required.
Example
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> {
file.move_copy_to(&some_path).await?;
Ok(())
}
sourcepub async fn open(&self) -> Result<impl AsyncBufRead + '_>
pub async fn open(&self) -> Result<impl AsyncBufRead + '_>
Open the file for reading, returning an async
stream of the file.
This method should be used sparingly. TempFile
is intended to be used
when the incoming data is destined to be stored on disk. If the incoming
data is intended to be streamed elsewhere, prefer to implement a custom
form guard via FromFormField
that directly streams the incoming data
to the ultimate destination.
Example
use rocket::fs::TempFile;
use rocket::tokio::io;
#[post("/", data = "<file>")]
async fn handle(file: TempFile<'_>) -> std::io::Result<()> {
let mut stream = file.open().await?;
io::copy(&mut stream, &mut io::stdout()).await?;
Ok(())
}
sourcepub fn len(&self) -> u64
pub fn len(&self) -> u64
Returns the size, in bytes, of the file.
This method does not perform any system calls.
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
fn handler(file: TempFile<'_>) {
let file_len = file.len();
}
sourcepub fn path(&self) -> Option<&Path>
pub fn path(&self) -> Option<&Path>
Returns the path to the file if it is known.
Once a file is persisted with TempFile::persist_to()
, this method is
guaranteed to return Some
. Prior to this point, however, this method
may return Some
or None
, depending on whether the file is on disk or
partially buffered in memory.
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> {
file.persist_to(&some_path).await?;
assert_eq!(file.path(), Some(&*some_path));
Ok(())
}
sourcepub fn name(&self) -> Option<&str>
pub fn name(&self) -> Option<&str>
Returns the sanitized file name as specified in the form field.
A multipart data form field can optionally specify the name of a file. A browser will typically send the actual name of a user’s selected file in this field, but clients are also able to specify any name, including invalid or dangerous file names. This method returns a sanitized version of that value, if it was specified, suitable and safe for use as a permanent file name.
Note that you will likely want to prepend or append random or user-specific components to the name to avoid collisions; UUIDs make for a good “random” data.
See FileName::as_str()
for specifics on sanitization.
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) -> std::io::Result<()> {
if let Some(name) = file.name() {
// Because of Rocket's sanitization, this is safe.
file.persist_to(&some_dir.join(name)).await?;
}
Ok(())
}
sourcepub fn raw_name(&self) -> Option<&FileName>
pub fn raw_name(&self) -> Option<&FileName>
Returns the raw name of the file as specified in the form field.
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
async fn handle(mut file: TempFile<'_>) {
let raw_name = file.raw_name();
}
sourcepub fn content_type(&self) -> Option<&ContentType>
pub fn content_type(&self) -> Option<&ContentType>
Returns the Content-Type of the file as specified in the form field.
A multipart data form field can optionally specify the content-type of a file. A browser will typically sniff the file’s extension to set the content-type. This method returns that value, if it was specified.
use rocket::fs::TempFile;
#[post("/", data = "<file>")]
fn handle(file: TempFile<'_>) {
let content_type = file.content_type();
}
Trait Implementations§
source§impl<'r> FromData<'r> for TempFile<'_>
impl<'r> FromData<'r> for TempFile<'_>
§type Error = <Capped<TempFile<'_>> as FromData<'r>>::Error
type Error = <Capped<TempFile<'_>> as FromData<'r>>::Error
source§fn from_data<'life0, 'async_trait>(
r: &'r Request<'life0>,
d: Data<'r>
) -> Pin<Box<dyn Future<Output = Outcome<'r, Self>> + Send + 'async_trait>>where
Self: 'async_trait,
'r: 'async_trait,
'life0: 'async_trait,
fn from_data<'life0, 'async_trait>( r: &'r Request<'life0>, d: Data<'r> ) -> Pin<Box<dyn Future<Output = Outcome<'r, Self>> + Send + 'async_trait>>where Self: 'async_trait, 'r: 'async_trait, 'life0: 'async_trait,
Self
from the incoming request body data. Read moresource§impl<'v> FromFormField<'v> for TempFile<'v>
impl<'v> FromFormField<'v> for TempFile<'v>
Auto Trait Implementations§
impl<'v> RefUnwindSafe for TempFile<'v>
impl<'v> Send for TempFile<'v>
impl<'v> Sync for TempFile<'v>
impl<'v> Unpin for TempFile<'v>
impl<'v> UnwindSafe for TempFile<'v>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<'v, T> FromForm<'v> for Twhere
T: FromFormField<'v>,
impl<'v, T> FromForm<'v> for Twhere T: FromFormField<'v>,
source§fn init(opts: Options) -> <T as FromForm<'v>>::Context
fn init(opts: Options) -> <T as FromForm<'v>>::Context
Self
.source§fn push_value(ctxt: &mut <T as FromForm<'v>>::Context, field: ValueField<'v>)
fn push_value(ctxt: &mut <T as FromForm<'v>>::Context, field: ValueField<'v>)
field
.source§fn push_data<'life0, 'life1, 'async_trait>(
ctxt: &'life0 mut FromFieldContext<'v, T>,
field: DataField<'v, 'life1>
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait, Global>>where
'v: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
T: 'async_trait,
fn push_data<'life0, 'life1, 'async_trait>( ctxt: &'life0 mut FromFieldContext<'v, T>, field: DataField<'v, 'life1> ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait, Global>>where 'v: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, T: 'async_trait,
field
.source§fn finalize(ctxt: <T as FromForm<'v>>::Context) -> Result<T, Errors<'v>>
fn finalize(ctxt: <T as FromForm<'v>>::Context) -> Result<T, Errors<'v>>
Errors
otherwise.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoCollection<T> for T
impl<T> IntoCollection<T> for T
source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere T: ?Sized,
source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the foreground set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red()
and
green()
, which have the same functionality but are
pithier.
Example
Set foreground color to white using fg()
:
use yansi::{Paint, Color};
painted.fg(Color::White);
Set foreground color to white using white()
.
use yansi::Paint;
painted.white();
source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Returns self
with the
fg()
set to
Color::BrightYellow
.
Example
println!("{}", value.bright_yellow());
source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Returns self
with the
fg()
set to
Color::BrightMagenta
.
Example
println!("{}", value.bright_magenta());
source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the background set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red()
and
on_green()
, which have the same functionality but
are pithier.
Example
Set background color to red using fg()
:
use yansi::{Paint, Color};
painted.bg(Color::Red);
Set background color to red using on_red()
.
use yansi::Paint;
painted.on_red();
source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightBlack
.
Example
println!("{}", value.on_bright_black());
source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightGreen
.
Example
println!("{}", value.on_bright_green());
source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightYellow
.
Example
println!("{}", value.on_bright_yellow());
source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightBlue
.
Example
println!("{}", value.on_bright_blue());
source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightMagenta
.
Example
println!("{}", value.on_bright_magenta());
source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightCyan
.
Example
println!("{}", value.on_bright_cyan());
source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Returns self
with the
bg()
set to
Color::BrightWhite
.
Example
println!("{}", value.on_bright_white());
source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute
value
.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold()
and
underline()
, which have the same functionality
but are pithier.
Example
Make text bold using attr()
:
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);
Make text bold using using bold()
.
use yansi::Paint;
painted.bold();
source§fn underline(&self) -> Painted<&T>
fn underline(&self) -> Painted<&T>
Returns self
with the
attr()
set to
Attribute::Underline
.
Example
println!("{}", value.underline());
source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Returns self
with the
attr()
set to
Attribute::RapidBlink
.
Example
println!("{}", value.rapid_blink());
source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi
Quirk
value
.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask()
and
wrap()
, which have the same functionality but are
pithier.
Example
Enable wrapping using .quirk()
:
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);
Enable wrapping using wrap()
.
use yansi::Paint;
painted.wrap();
source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition
value
applies. Replaces any previous condition.
See the crate level docs for more details.
Example
Enable styling painted
only when both stdout
and stderr
are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);