Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init multipart #175

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ anyhow = "1.0.26"

# features: cookies
cookie = { version = "0.14.0", features = ["percent-encode"], optional = true }
futures-core = "0.3.5"
infer = "0.2.3"
pin-project-lite = "0.2.0"
url = { version = "2.1.1", features = ["serde"] }
Expand All @@ -47,6 +48,7 @@ serde_urlencoded = "0.7.0"
rand = "0.7.3"
serde_qs = "0.7.0"
base64 = "0.13.0"
multipart = { version = "0.17.0", default-features = false, features = ["server"] }

[dev-dependencies]
http = "0.2.0"
Expand Down
25 changes: 23 additions & 2 deletions src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ pin_project_lite::pin_project! {
reader: Box<dyn AsyncBufRead + Unpin + Send + Sync + 'static>,
mime: Mime,
length: Option<usize>,
bytes_read: usize
bytes_read: usize,
pub(crate) file_name: Option<String>,
}
}

Expand All @@ -80,6 +81,7 @@ impl Body {
mime: mime::BYTE_STREAM,
length: Some(0),
bytes_read: 0,
file_name: None,
}
}

Expand Down Expand Up @@ -111,6 +113,7 @@ impl Body {
mime: mime::BYTE_STREAM,
length: len,
bytes_read: 0,
file_name: None,
}
}

Expand Down Expand Up @@ -155,6 +158,7 @@ impl Body {
length: Some(bytes.len()),
reader: Box::new(io::Cursor::new(bytes)),
bytes_read: 0,
file_name: None,
}
}

Expand Down Expand Up @@ -205,6 +209,7 @@ impl Body {
length: Some(s.len()),
reader: Box::new(io::Cursor::new(s.into_bytes())),
bytes_read: 0,
file_name: None,
}
}

Expand Down Expand Up @@ -251,6 +256,7 @@ impl Body {
reader: Box::new(io::Cursor::new(bytes)),
mime: mime::JSON,
bytes_read: 0,
file_name: None,
};
Ok(body)
}
Expand Down Expand Up @@ -316,6 +322,7 @@ impl Body {
reader: Box::new(io::Cursor::new(bytes)),
mime: mime::FORM,
bytes_read: 0,
file_name: None,
};
Ok(body)
}
Expand Down Expand Up @@ -370,7 +377,7 @@ impl Body {
P: AsRef<std::path::Path>,
{
let path = path.as_ref();
let mut file = async_std::fs::File::open(path).await?;
let mut file = async_std::fs::File::open(&path).await?;
let len = file.metadata().await?.len();

// Look at magic bytes first, look at extension second, fall back to
Expand All @@ -385,6 +392,7 @@ impl Body {
length: Some(len as usize),
reader: Box::new(io::BufReader::new(file)),
bytes_read: 0,
file_name: Some(path.to_string_lossy().to_string()),
})
}

Expand Down Expand Up @@ -419,6 +427,19 @@ impl Body {
pub fn set_mime(&mut self, mime: impl Into<Mime>) {
self.mime = mime.into();
}

/// Get the file name of the `Body`, if it's set.
pub fn file_name(&self) -> Option<&str> {
self.file_name.as_deref()
}

/// Set the file name of the `Body`.
pub fn set_file_name<S>(&mut self, file_name: Option<S>)
where
S: AsRef<str>,
{
self.file_name = file_name.map(|v| v.as_ref().to_owned());
}
}

impl Debug for Body {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub mod conditional;
pub mod content;
pub mod headers;
pub mod mime;
pub mod multipart;
pub mod other;
pub mod proxies;
pub mod server;
Expand Down
151 changes: 151 additions & 0 deletions src/multipart/entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::{Body, Mime};

use std::fmt::{self, Debug};
// use std::path::Path;
use std::pin::Pin;
use std::task::{Context, Poll};

use futures_lite::{io, prelude::*};

pin_project_lite::pin_project! {
/// A single multipart entry.
///
/// Structurally Multipart entries are similar to `Body`.
pub struct Entry {
name: String,
body: Body,
}
}

impl Entry {
/// Create a new `Entry`.
pub fn new<S, B>(name: S, body: B) -> Self
where
S: AsRef<str>,
B: Into<Body>,
{
Self {
name: name.as_ref().to_owned(),
body: body.into(),
}
}

/// Create an empty `Entry`.
pub fn empty<S>(name: S) -> Self
where
S: AsRef<str>,
{
Self::new(name, Body::empty())
}

/// Create an `Entry` from a file.
#[cfg(all(feature = "async_std", not(target_os = "unknown")))]
pub async fn from_file<S, P>(name: S, path: P) -> crate::Result<Self>
where
S: AsRef<str>,
P: AsRef<Path>,
{
let body = Body::from_file(path).await?;
Ok(Self::new(name, body))
}

/// Get the entry name.
pub fn name(&self) -> &String {
&self.name
}

/// Set the entry name.
pub fn set_name<S>(&mut self, name: S)
where
S: AsRef<str>,
{
self.name = name.as_ref().to_owned();
}

/// Returns the mime type of this Body.
pub fn mime(&self) -> &Mime {
self.body.mime()
}

/// Sets the mime type of this Body.
pub fn set_mime(&mut self, mime: Mime) {
self.body.set_mime(mime)
}

/// Get the file name of the entry, if it's set.
pub fn file_name(&self) -> Option<&str> {
self.body.file_name()
}

/// Set the file name of the `Body`.
pub fn set_file_name<P>(&mut self, file_name: Option<P>)
where
P: AsRef<str>,
{
self.body.set_file_name(file_name);
}
}

impl Debug for Entry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Entry")
.field("name", &self.name)
.field("body", &self.body)
.finish()
}
}

impl AsyncRead for Entry {
#[allow(missing_doc_code_examples)]
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.body).poll_read(cx, buf)
}
}

impl AsyncBufRead for Entry {
#[allow(missing_doc_code_examples)]
#[allow(unused_mut)]
#[allow(unused_variables)]
fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
// Pin::new(&mut self.body).poll_fill_buf(cx)
todo!("Pin::new(&mut self.body).poll_fill_buf(cx)")
}

fn consume(mut self: Pin<&mut Self>, amt: usize) {
Pin::new(&mut self.body).consume(amt)
}
}

impl AsRef<Body> for Entry {
fn as_ref(&self) -> &Body {
&self.body
}
}

impl AsMut<Body> for Entry {
fn as_mut(&mut self) -> &mut Body {
&mut self.body
}
}

impl Into<Body> for Entry {
fn into(self) -> Body {
self.body
}
}

impl From<Body> for Entry {
fn from(body: Body) -> Self {
match body.file_name.clone() {
Some(name) => Self { body, name },
None => Self {
body,
name: String::new(),
},
}
}
}
Loading