Skip to content

Commit f397468

Browse files
yoshuawuytsFishrock123
authored andcommitted
Init multipart
1 parent a6cbf95 commit f397468

File tree

5 files changed

+127
-1
lines changed

5 files changed

+127
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ serde_urlencoded = "0.7.0"
4444
rand = "0.7.3"
4545
serde_qs = "0.7.0"
4646
base64 = "0.13.0"
47+
multipart = { version = "0.16.1", default-features = false, features = ["server"], optional = true }
4748

4849
[dev-dependencies]
4950
http = "0.2.0"

src/body.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use futures_lite::{io, prelude::*};
22
use serde::{de::DeserializeOwned, Serialize};
33

44
use std::fmt::{self, Debug};
5+
use std::path::PathBuf;
56
use std::pin::Pin;
67
use std::task::{Context, Poll};
78

@@ -56,6 +57,7 @@ pin_project_lite::pin_project! {
5657
reader: Box<dyn AsyncBufRead + Unpin + Send + Sync + 'static>,
5758
mime: Mime,
5859
length: Option<usize>,
60+
pub(crate) file_name: Option<PathBuf>,
5961
}
6062
}
6163

@@ -78,6 +80,7 @@ impl Body {
7880
reader: Box::new(io::empty()),
7981
mime: mime::BYTE_STREAM,
8082
length: Some(0),
83+
file_name: None,
8184
}
8285
}
8386

@@ -108,6 +111,7 @@ impl Body {
108111
reader: Box::new(reader),
109112
mime: mime::BYTE_STREAM,
110113
length: len,
114+
file_name: None,
111115
}
112116
}
113117

@@ -151,6 +155,7 @@ impl Body {
151155
mime: mime::BYTE_STREAM,
152156
length: Some(bytes.len()),
153157
reader: Box::new(io::Cursor::new(bytes)),
158+
file_name: None,
154159
}
155160
}
156161

@@ -200,6 +205,7 @@ impl Body {
200205
mime: mime::PLAIN,
201206
length: Some(s.len()),
202207
reader: Box::new(io::Cursor::new(s.into_bytes())),
208+
file_name: None,
203209
}
204210
}
205211

@@ -245,6 +251,7 @@ impl Body {
245251
length: Some(bytes.len()),
246252
reader: Box::new(io::Cursor::new(bytes)),
247253
mime: mime::JSON,
254+
file_name: None,
248255
};
249256
Ok(body)
250257
}
@@ -309,6 +316,7 @@ impl Body {
309316
length: Some(bytes.len()),
310317
reader: Box::new(io::Cursor::new(bytes)),
311318
mime: mime::FORM,
319+
file_name: None,
312320
};
313321
Ok(body)
314322
}
@@ -363,7 +371,7 @@ impl Body {
363371
P: AsRef<std::path::Path>,
364372
{
365373
let path = path.as_ref();
366-
let mut file = async_std::fs::File::open(path).await?;
374+
let mut file = async_std::fs::File::open(&path).await?;
367375
let len = file.metadata().await?.len();
368376

369377
// Look at magic bytes first, look at extension second, fall back to
@@ -377,6 +385,7 @@ impl Body {
377385
mime,
378386
length: Some(len as usize),
379387
reader: Box::new(io::BufReader::new(file)),
388+
file_name: Some(path.to_path_buf()),
380389
})
381390
}
382391

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ mod version;
142142
pub mod trace;
143143
cfg_unstable! {
144144
pub mod upgrade;
145+
pub mod multipart;
145146
}
146147

147148
pub use body::Body;

src/multipart/entry.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use crate::Body;
2+
3+
use std::fmt::{self, Debug};
4+
use std::path::PathBuf;
5+
6+
/// A single multipart entry.
7+
///
8+
/// Structurally Multipart entries are similar to `Body`.
9+
pub struct Entry {
10+
name: String,
11+
body: Body,
12+
}
13+
14+
impl Entry {
15+
/// Create a new `Entry`.
16+
pub fn new(name: impl AsRef<str>, body: impl Into<Body>) -> Self {
17+
Self {
18+
name: name.as_ref().to_owned(),
19+
body: body.into(),
20+
}
21+
}
22+
23+
/// Get the entry name.
24+
pub fn name(&self) -> &String {
25+
&self.name
26+
}
27+
28+
/// Get the file name of the entry, if it's set.
29+
pub fn file_name(&self) -> Option<&PathBuf> {
30+
self.body.file_name.as_ref()
31+
}
32+
}
33+
34+
impl Debug for Entry {
35+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36+
f.debug_struct("Entry")
37+
.field("name", &self.name)
38+
.field("body", &self.body)
39+
.finish()
40+
}
41+
}
42+
43+
// TODO
44+
// impl AsyncRead for Entry {}
45+
// impl AsRef<Body> for Entry {}
46+
// impl AsMut<Body> for Entry {}
47+
// impl Into<Body> for Entry {}

src/multipart/mod.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//! Multipart/form-data types.
2+
//!
3+
//! # Examples
4+
//!
5+
//! Request:
6+
//! ```
7+
//! let mut req = Request::new(Method::Get, "http://example.website");
8+
//!
9+
//! let mut multi = Multipart::new();
10+
//! multi.push("hello world");
11+
//! multi.push(Body::from_file("./cats.jpeg").await?);
12+
//!
13+
//! req.set_body(multi);
14+
//! ```
15+
//!
16+
//! Response:
17+
//!
18+
//! ```
19+
//! let mut res = Response::new(200); // get this from somewhere
20+
//!
21+
//! let mut entries = res.body_multipart();
22+
//! while let Some(entry) = entries.await {
23+
//! println!("name: {}", entry.name());
24+
//! println!("data: {}", entry.into_string()?);
25+
//! }
26+
//! ```
27+
28+
use crate::Body;
29+
pub use entry::Entry;
30+
31+
mod entry;
32+
33+
/// A multipart response body.
34+
#[derive(Debug)]
35+
pub struct Multipart {
36+
entries: Vec<Entry>,
37+
body: Option<Body>,
38+
}
39+
40+
impl Multipart {
41+
/// Create a new instance of `Multipart`.
42+
pub fn new() -> Self {
43+
Self {
44+
entries: vec![],
45+
body: None,
46+
}
47+
}
48+
49+
/// Parse a `Body` stream as a `Multipart` instance.
50+
pub fn from_body(body: Body) -> Self {
51+
Self {
52+
entries: vec![],
53+
body: Some(body),
54+
}
55+
}
56+
57+
/// Add a new entry to the `Multipart` instance.
58+
pub fn push(&mut self, name: impl AsRef<str>, body: impl Into<Body>) {
59+
let entry = Entry::new(name, body);
60+
self.entries.push(entry);
61+
}
62+
}
63+
64+
// TODO
65+
// impl Stream for Multipart {}
66+
67+
// TODO
68+
// impl From<Multipart> for Body {}

0 commit comments

Comments
 (0)