Skip to main content

MultipartForm

Struct MultipartForm 

Source
pub struct MultipartForm { /* private fields */ }
Expand description

The parsed parts of a multipart body: text fields and files, by field name.

Obtained from the Multipart extractor. Text fields are read with MultipartForm::form (all at once, into a struct) or MultipartForm::text (one by one); files are taken with MultipartForm::file. Parts without a name are skipped; a text field that is not UTF-8 is a 400.

§Examples

use ocre::storage::MultipartForm;

// An empty form, as `Default` builds it.
let mut form = MultipartForm::default();
assert_eq!(form.text("title"), None);
assert!(form.file("image").is_none());

Implementations§

Source§

impl MultipartForm

Source

pub fn form<T: DeserializeOwned>(&self) -> Result<T>

Deserializes the text fields into T, exactly like axum’s Form.

Numbers and booleans are parsed from their text, #[serde(default)] fills in missing fields, and file fields are ignored. Unchecked HTML checkboxes send nothing, so give bool fields #[serde(default)].

§Errors

Error::BadRequest (400) Invalid form: ... when a field is missing or T cannot parse it.

§Examples
use serde::Deserialize;

#[derive(Deserialize)]
struct Profile {
    name: String,
    age: u8,
    #[serde(default)]
    public: bool,
}

let body = "--x\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nAda\r\n\
            --x\r\nContent-Disposition: form-data; name=\"age\"\r\n\r\n36\r\n--x--\r\n";
let request = Request::post("/profile")
    .header("content-type", "multipart/form-data; boundary=x")
    .body(Body::from(body))
    .unwrap();
let Multipart(form) = block_on(Multipart::<1024>::from_request(request, &())).unwrap();

let profile: Profile = form.form()?;
assert_eq!((profile.name.as_str(), profile.age, profile.public), ("Ada", 36, false));

#[derive(Debug, Deserialize)]
struct Strict {
    #[allow(dead_code)]
    email: String,
}
let err = form.form::<Strict>().unwrap_err();
assert!(matches!(err, ocre::Error::BadRequest(message) if message == "Invalid form: missing field `email`"));
Source

pub fn text(&self, name: &str) -> Option<&str>

Returns the first text field named name, or None when it was not sent.

File fields are not text fields: use MultipartForm::file for them.

§Examples
let body = "--x\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nHoliday\r\n--x--\r\n";
let request = Request::post("/photos")
    .header("content-type", "multipart/form-data; boundary=x")
    .body(Body::from(body))
    .unwrap();
let Multipart(form) = block_on(Multipart::<1024>::from_request(request, &())).unwrap();
assert_eq!(form.text("title"), Some("Holiday"));
assert_eq!(form.text("missing"), None);
Source

pub fn file(&mut self, name: &str) -> Option<Upload>

Takes the first file sent as name, leaving the others.

None when the field is missing or no file was chosen (browsers then send an empty, nameless file, which is dropped while parsing). Taking moves the Upload out without copying its bytes; a second call for the same name returns the next file with that name, if any.

§Examples
let body = "--x\r\n\
    Content-Disposition: form-data; name=\"image\"; filename=\"C:\\\\photos\\\\beach.png\"\r\n\
    Content-Type: Image/PNG\r\n\r\n\
    PNG...\r\n\
    --x\r\n\
    Content-Disposition: form-data; name=\"notes\"; filename=\"\"\r\n\
    Content-Type: application/octet-stream\r\n\r\n\
    \r\n\
    --x--\r\n";
let request = Request::post("/photos")
    .header("content-type", "multipart/form-data; boundary=x")
    .body(Body::from(body))
    .unwrap();
let Multipart(mut form) = block_on(Multipart::<1024>::from_request(request, &())).unwrap();

let image = form.file("image").unwrap();
assert_eq!(image.filename, "beach.png");
assert_eq!(image.content_type, "image/png");
assert_eq!(image.size(), 6);
assert!(form.file("image").is_none()); // taken
assert!(form.file("notes").is_none()); // no file chosen
Source

pub fn files(&mut self, name: &str) -> Vec<Upload>

Takes every file sent as name or name[] (an <input type="file" multiple>), in order.

§Examples
let body = "--x\r\nContent-Disposition: form-data; name=\"photos\"; filename=\"a.png\"\r\n\
    Content-Type: image/png\r\n\r\nA\r\n\
    --x\r\nContent-Disposition: form-data; name=\"photos\"; filename=\"b.png\"\r\n\
    Content-Type: image/png\r\n\r\nB\r\n--x--\r\n";
let request = Request::post("/albums/1/photos")
    .header("content-type", "multipart/form-data; boundary=x")
    .body(Body::from(body))
    .unwrap();
let Multipart(mut form) = block_on(Multipart::<1024>::from_request(request, &())).unwrap();
let names: Vec<String> = form.files("photos").into_iter().map(|file| file.filename).collect();
assert_eq!(names, ["a.png", "b.png"]);
assert!(form.files("photos").is_empty()); // taken

Trait Implementations§

Source§

impl Clone for MultipartForm

Source§

fn clone(&self) -> MultipartForm

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MultipartForm

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for MultipartForm

Source§

fn default() -> MultipartForm

Returns the “default value” for a type. Read more
Source§

impl PartialEq for MultipartForm

Source§

fn eq(&self, other: &MultipartForm) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for MultipartForm

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V