Make multipart an optional feature (default off) (#1128)

This commit is contained in:
nickelc
2021-01-04 22:20:17 +01:00
committed by GitHub
parent 1f425a0244
commit afed48cafd
12 changed files with 51 additions and 9 deletions

View File

@@ -63,6 +63,7 @@ jobs:
- "feat.: gzip" - "feat.: gzip"
- "feat.: brotli" - "feat.: brotli"
- "feat.: json" - "feat.: json"
- "feat.: multipart"
- "feat.: stream" - "feat.: stream"
- "feat.: socks/default-tls" - "feat.: socks/default-tls"
- "feat.: socks/rustls-tls" - "feat.: socks/rustls-tls"
@@ -84,21 +85,21 @@ jobs:
- name: windows / stable-x86_64-msvc - name: windows / stable-x86_64-msvc
os: windows-latest os: windows-latest
target: x86_64-pc-windows-msvc target: x86_64-pc-windows-msvc
features: "--features blocking,gzip,brotli,json" features: "--features blocking,gzip,brotli,json,multipart"
- name: windows / stable-i686-msvc - name: windows / stable-i686-msvc
os: windows-latest os: windows-latest
target: i686-pc-windows-msvc target: i686-pc-windows-msvc
features: "--features blocking,gzip,brotli,json" features: "--features blocking,gzip,brotli,json,multipart"
- name: windows / stable-x86_64-gnu - name: windows / stable-x86_64-gnu
os: windows-latest os: windows-latest
rust: stable-x86_64-pc-windows-gnu rust: stable-x86_64-pc-windows-gnu
target: x86_64-pc-windows-gnu target: x86_64-pc-windows-gnu
features: "--features blocking,gzip,brotli,json" features: "--features blocking,gzip,brotli,json,multipart"
- name: windows / stable-i686-gnu - name: windows / stable-i686-gnu
os: windows-latest os: windows-latest
rust: stable-i686-pc-windows-gnu rust: stable-i686-pc-windows-gnu
target: i686-pc-windows-gnu target: i686-pc-windows-gnu
features: "--features blocking,gzip,brotli,json" features: "--features blocking,gzip,brotli,json,multipart"
- name: "feat.: default-tls disabled" - name: "feat.: default-tls disabled"
features: "--no-default-features" features: "--no-default-features"
@@ -120,6 +121,8 @@ jobs:
features: "--features brotli" features: "--features brotli"
- name: "feat.: json" - name: "feat.: json"
features: "--features json" features: "--features json"
- name: "feat.: multipart"
features: "--features multipart"
- name: "feat.: stream" - name: "feat.: stream"
features: "--features stream" features: "--features stream"
- name: "feat.: socks/default-tls" - name: "feat.: socks/default-tls"

View File

@@ -21,6 +21,7 @@ features = [
"blocking", "blocking",
"cookies", "cookies",
"json", "json",
"multipart",
] ]
[features] [features]
@@ -49,6 +50,8 @@ brotli = ["async-compression", "async-compression/brotli", "tokio-util"]
json = ["serde_json"] json = ["serde_json"]
multipart = ["mime_guess"]
trust-dns = ["trust-dns-resolver"] trust-dns = ["trust-dns-resolver"]
stream = [] stream = []
@@ -74,9 +77,13 @@ url = "2.2"
bytes = "1.0" bytes = "1.0"
serde = "1.0" serde = "1.0"
serde_urlencoded = "0.7" serde_urlencoded = "0.7"
mime_guess = "2.0"
# Optional deps...
## json ## json
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
## multipart
mime_guess = { version = "2.0", default-features = false, optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
base64 = "0.13" base64 = "0.13"
@@ -206,3 +213,8 @@ required-features = ["gzip"]
name = "brotli" name = "brotli"
path = "tests/brotli.rs" path = "tests/brotli.rs"
required-features = ["brotli"] required-features = ["brotli"]
[[test]]
name = "multipart"
path = "tests/multipart.rs"
required-features = ["multipart"]

View File

@@ -152,6 +152,7 @@ impl Body {
ImplStream(self) ImplStream(self)
} }
#[cfg(feature = "multipart")]
pub(crate) fn content_length(&self) -> Option<u64> { pub(crate) fn content_length(&self) -> Option<u64> {
match self.inner { match self.inner {
Inner::Reusable(ref bytes) => Some(bytes.len() as u64), Inner::Reusable(ref bytes) => Some(bytes.len() as u64),

View File

@@ -9,6 +9,7 @@ pub(crate) use self::decoder::Decoder;
pub mod body; pub mod body;
pub mod client; pub mod client;
pub mod decoder; pub mod decoder;
#[cfg(feature = "multipart")]
pub mod multipart; pub mod multipart;
pub(crate) mod request; pub(crate) mod request;
mod response; mod response;

View File

@@ -11,9 +11,12 @@ use serde_json;
use super::body::Body; use super::body::Body;
use super::client::{Client, Pending}; use super::client::{Client, Pending};
#[cfg(feature = "multipart")]
use super::multipart; use super::multipart;
use super::response::Response; use super::response::Response;
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_LENGTH, CONTENT_TYPE}; use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
#[cfg(feature = "multipart")]
use crate::header::CONTENT_LENGTH;
use crate::{Method, Url}; use crate::{Method, Url};
use http::{Request as HttpRequest, request::Parts}; use http::{Request as HttpRequest, request::Parts};
@@ -260,6 +263,7 @@ impl RequestBuilder {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[cfg(feature = "multipart")]
pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder { pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
let mut builder = self.header( let mut builder = self.header(
CONTENT_TYPE, CONTENT_TYPE,

View File

@@ -1,7 +1,9 @@
use std::fmt; use std::fmt;
use std::fs::File; use std::fs::File;
use std::future::Future; use std::future::Future;
use std::io::{self, Cursor, Read}; use std::io::{self, Read};
#[cfg(feature = "multipart")]
use std::io::Cursor;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
@@ -113,6 +115,7 @@ impl Body {
} }
} }
#[cfg(feature = "multipart")]
pub(crate) fn len(&self) -> Option<u64> { pub(crate) fn len(&self) -> Option<u64> {
match self.kind { match self.kind {
Kind::Reader(_, len) => len, Kind::Reader(_, len) => len,
@@ -120,6 +123,7 @@ impl Body {
} }
} }
#[cfg(feature = "multipart")]
pub(crate) fn into_reader(self) -> Reader { pub(crate) fn into_reader(self) -> Reader {
match self.kind { match self.kind {
Kind::Reader(r, _) => Reader::Reader(r), Kind::Reader(r, _) => Reader::Reader(r),
@@ -236,11 +240,13 @@ impl<'a> fmt::Debug for DebugLength<'a> {
} }
} }
#[cfg(feature = "multipart")]
pub(crate) enum Reader { pub(crate) enum Reader {
Reader(Box<dyn Read + Send>), Reader(Box<dyn Read + Send>),
Bytes(Cursor<Bytes>), Bytes(Cursor<Bytes>),
} }
#[cfg(feature = "multipart")]
impl Read for Reader { impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self { match *self {

View File

@@ -59,6 +59,7 @@
mod body; mod body;
mod client; mod client;
#[cfg(feature = "multipart")]
pub mod multipart; pub mod multipart;
mod request; mod request;
mod response; mod response;

View File

@@ -10,6 +10,7 @@ use serde_json;
use serde_urlencoded; use serde_urlencoded;
use super::body::{self, Body}; use super::body::{self, Body};
#[cfg(feature = "multipart")]
use super::multipart; use super::multipart;
use super::Client; use super::Client;
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE}; use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
@@ -508,6 +509,7 @@ impl RequestBuilder {
/// ``` /// ```
/// ///
/// See [`multipart`](multipart/) for more examples. /// See [`multipart`](multipart/) for more examples.
#[cfg(feature = "multipart")]
pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder { pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
let mut builder = self.header( let mut builder = self.header(
CONTENT_TYPE, CONTENT_TYPE,

View File

@@ -182,6 +182,7 @@
//! - **gzip**: Provides response body gzip decompression. //! - **gzip**: Provides response body gzip decompression.
//! - **brotli**: Provides response body brotli decompression. //! - **brotli**: Provides response body brotli decompression.
//! - **json**: Provides serialization and deserialization for JSON bodies. //! - **json**: Provides serialization and deserialization for JSON bodies.
//! - **multipart**: Provides functionality for multipart forms.
//! - **stream**: Adds support for `futures::Stream`. //! - **stream**: Adds support for `futures::Stream`.
//! - **socks**: Provides SOCKS5 proxy support. //! - **socks**: Provides SOCKS5 proxy support.
//! - **trust-dns**: Enables a trust-dns async resolver instead of default //! - **trust-dns**: Enables a trust-dns async resolver instead of default
@@ -290,11 +291,13 @@ if_hyper! {
doctest!("../README.md"); doctest!("../README.md");
pub use self::async_impl::{ pub use self::async_impl::{
multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
}; };
pub use self::proxy::Proxy; pub use self::proxy::Proxy;
#[cfg(feature = "__tls")] #[cfg(feature = "__tls")]
pub use self::tls::{Certificate, Identity}; pub use self::tls::{Certificate, Identity};
#[cfg(feature = "multipart")]
pub use self::async_impl::multipart;
mod async_impl; mod async_impl;
@@ -316,5 +319,7 @@ if_wasm! {
mod wasm; mod wasm;
mod util; mod util;
pub use self::wasm::{multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response}; pub use self::wasm::{Body, Client, ClientBuilder, Request, RequestBuilder, Response};
#[cfg(feature = "multipart")]
pub use self::wasm::multipart;
} }

View File

@@ -1,3 +1,4 @@
#[cfg(feature = "multipart")]
use super::multipart::Form; use super::multipart::Form;
/// dox /// dox
use bytes::Bytes; use bytes::Bytes;
@@ -18,6 +19,7 @@ pub struct Body {
enum Inner { enum Inner {
Bytes(Bytes), Bytes(Bytes),
#[cfg(feature = "multipart")]
Multipart(Form), Multipart(Form),
} }
@@ -30,6 +32,7 @@ impl Body {
let js_value: &JsValue = body_array.as_ref(); let js_value: &JsValue = body_array.as_ref();
Ok(js_value.to_owned()) Ok(js_value.to_owned())
} }
#[cfg(feature = "multipart")]
Inner::Multipart(form) => { Inner::Multipart(form) => {
let form_data = form.to_form_data()?; let form_data = form.to_form_data()?;
let js_value: &JsValue = form_data.as_ref(); let js_value: &JsValue = form_data.as_ref();
@@ -39,6 +42,7 @@ impl Body {
} }
#[inline] #[inline]
#[cfg(feature = "multipart")]
pub(crate) fn from_form(f: Form) -> Body { pub(crate) fn from_form(f: Form) -> Body {
Self { Self {
inner: Inner::Multipart(f), inner: Inner::Multipart(f),
@@ -48,6 +52,7 @@ impl Body {
pub(crate) fn is_empty(&self) -> bool { pub(crate) fn is_empty(&self) -> bool {
match &self.inner { match &self.inner {
Inner::Bytes(bytes) => bytes.is_empty(), Inner::Bytes(bytes) => bytes.is_empty(),
#[cfg(feature = "multipart")]
Inner::Multipart(form) => form.is_empty(), Inner::Multipart(form) => form.is_empty(),
} }
} }

View File

@@ -5,6 +5,7 @@ mod client;
mod request; mod request;
mod response; mod response;
/// TODO /// TODO
#[cfg(feature = "multipart")]
pub mod multipart; pub mod multipart;
pub use self::body::Body; pub use self::body::Body;

View File

@@ -191,6 +191,7 @@ impl RequestBuilder {
} }
/// TODO /// TODO
#[cfg(feature = "multipart")]
pub fn multipart(mut self, multipart: super::multipart::Form) -> RequestBuilder { pub fn multipart(mut self, multipart: super::multipart::Form) -> RequestBuilder {
if let Ok(ref mut req) = self.request { if let Ok(ref mut req) = self.request {
*req.body_mut() = Some(Body::from_form(multipart)) *req.body_mut() = Some(Body::from_form(multipart))