[−][src]Struct salvo::http::multipart::Multipart
The server-side implementation of multipart/form-data
requests.
After constructing with either the ::with_body()
or
::try_from_request()
, two different workflows for processing the
request are provided, assuming any Poll::Pending
and Ready(Err(_))
/Ready(Some(Err(_)))
results are handled in the typical fashion:
High-Level Flow
- Await the next field with
.next_field()
. - Read the field data via the
Stream
impl onField::data
. - Repeat until
.next_field()
returnsNone
.
Low-Level Flow
-
Poll for the first field boundary with
.poll_has_next_field()
; if it returnstrue
proceed to the next step, iffalse
the request is at an end. -
Poll for the field's headers containing its name, content-type and other info with
.poll_field_headers()
. -
Poll for the field's data chunks with [
.poll_field_chunk()](#method.poll_field_chunk) until
None` is returned, then loop back to step 2.
Any data before the first boundary and past the end of the terminating boundary is ignored as it is out-of-spec and should not be expected to be left in the underlying stream intact. Please open an issue if you have a legitimate use-case for extraneous data in a multipart request.
Methods
impl<S> Multipart<S> where
S: TryStream,
S::Ok: BodyChunk,
S::Error: Into<ReadError>,
[src]
S: TryStream,
S::Ok: BodyChunk,
S::Error: Into<ReadError>,
pub fn with_body<B: Into<String>>(stream: S, boundary: B) -> Self
[src]
Construct a new Multipart
with the given body reader and boundary.
The boundary should be taken directly from the Content-Type: multipart/form-data
header
of the request. This will add the requisite --
to the boundary as per
IETF RFC 7578 section 4.1.
pub fn try_from_body_headers(
body: S,
headers: &HeaderMap
) -> Result<Self, ReadError>
[src]
body: S,
headers: &HeaderMap
) -> Result<Self, ReadError>
ⓘImportant traits for NextField<'a, S>pub fn next_field(&mut self) -> NextField<S> where
Self: Unpin,
[src]
Self: Unpin,
Get a future yielding the next field in the stream, if the stream is not at an end.
If a field was previously being read, its contents will be discarded.
use futures::prelude::*; use std::error::Error; use salvo::http::errors::ReadError; use salvo::http::multipart::Multipart; async fn example<S>(stream: S) -> Result<(), Box<dyn Error>> where S: Stream<Ok = &'static [u8]> + Unpin, ReadError: Error + 'static { let mut multipart = Multipart::with_body(stream, "boundary"); while let Some(mut field) = multipart.next_field().await? { println!("field: {:?}", field.headers); if field.headers.is_text() { println!("field text: {:?}", field.data.read_to_string().await?); } else { // this gives us `Result<Option<&'static [u8]>>` so `?` works in this function while let Some(chunk) = field.data.try_next().await? { println!("field data chunk: {:?}", chunk); } } } Ok(()) }
ⓘImportant traits for NextField<'a, S>pub fn next_field_pinned(self: Pin<&mut Self>) -> NextField<S>
[src]
Same as .next_field()
but with a receiver of Pin<&mut Self>
.
pub fn poll_has_next_field(
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Result<bool, ReadError>>
[src]
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Result<bool, ReadError>>
Poll for the next boundary, returning true
if a field should follow that boundary,
or false
if the request is at an end. See above for the overall flow.
If this returns Ready(Ok(true))
, you may then begin
polling for the headers of the next field.
If a field was being read, its contents will be discarded.
This is a low-level call and is expected to be supplemented/replaced by a more ergonomic API once more design work has taken place.
pub fn poll_field_headers(
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Result<FieldHeaders, ReadError>>
[src]
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Result<FieldHeaders, ReadError>>
Poll for the headers of the next field, returning the headers or an error otherwise.
Once you have the field headers, you may then begin polling for field chunks.
In addition to bubbling up errors from the underlying stream, this will also return an error if:
- the headers were corrupted, or:
- did not contain a
Content-Disposition: form-data
header with aname
parameter, or: - the end of stream was reached before the header segment terminator
\r\n\r\n
, or: - the buffer for the headers exceeds a preset size.
This is a low-level call and is expected to be supplemented/replaced by a more ergonomic API once more design work has taken place.
Note: Calling This Is Not Enforced
If this step is skipped then .poll_field_chunk()
will return chunks of the header segment which may or may not be desirable depending
on your use-case.
If you do want to inspect the raw field headers, they are separated by one CRLF (\r\n
) and
terminated by two CRLFs (\r\n\r\n
) after which the field chunks follow.
pub fn poll_field_chunk(
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Option<Result<S::Ok, ReadError>>>
[src]
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Option<Result<S::Ok, ReadError>>>
Poll for the next chunk of the current field.
This returns Ready(Some(Ok(chunk)))
as long as there are chunks in the field,
yielding Ready(None)
when the next boundary is reached.
You may then begin the next field with
.poll_has_next_field()
.
This is a low-level call and is expected to be supplemented/replaced by a more ergonomic API once more design work has taken place.
Note: Call .poll_field_headers()
First for Correct Data
If .poll_field_headers()
is skipped then this call
will return chunks of the header segment which may or may not be desirable depending
on your use-case.
If you do want to inspect the raw field headers, they are separated by one CRLF (\r\n
) and
terminated by two CRLFs (\r\n\r\n
) after which the field chunks follow.
Auto Trait Implementations
impl<S> RefUnwindSafe for Multipart<S> where
S: RefUnwindSafe,
<S as TryStream>::Ok: RefUnwindSafe,
S: RefUnwindSafe,
<S as TryStream>::Ok: RefUnwindSafe,
impl<S> Send for Multipart<S> where
S: Send,
<S as TryStream>::Ok: Send,
S: Send,
<S as TryStream>::Ok: Send,
impl<S> Sync for Multipart<S> where
S: Sync,
<S as TryStream>::Ok: Sync,
S: Sync,
<S as TryStream>::Ok: Sync,
impl<S> Unpin for Multipart<S> where
S: Unpin,
<S as TryStream>::Ok: Unpin,
S: Unpin,
<S as TryStream>::Ok: Unpin,
impl<S> UnwindSafe for Multipart<S> where
S: UnwindSafe,
<S as TryStream>::Ok: UnwindSafe,
S: UnwindSafe,
<S as TryStream>::Ok: UnwindSafe,
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
ⓘImportant traits for &'_ mut Ifn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> SendSyncUnwindSafe for T where
T: Send + Sync + UnwindSafe + ?Sized,
[src]
T: Send + Sync + UnwindSafe + ?Sized,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
V: MultiLane<T>,