Add BodySize enum

This commit is contained in:
Deluvi
2020-06-26 15:35:37 +02:00
committed by Martin Algesten
parent e224a6d126
commit 7de192d3f1
3 changed files with 36 additions and 17 deletions

View File

@@ -43,11 +43,21 @@ impl Default for Payload {
} }
} }
/// The size of the body.
///
/// *Internal API*
#[derive(Debug)]
pub(crate) enum BodySize {
Empty,
Unknown,
Known(u64),
}
/// Payloads are turned into this type where we can hold both a size and the reader. /// Payloads are turned into this type where we can hold both a size and the reader.
/// ///
/// *Internal API* /// *Internal API*
pub(crate) struct SizedReader { pub(crate) struct SizedReader {
pub size: Option<usize>, pub size: BodySize,
pub reader: Box<dyn Read + 'static>, pub reader: Box<dyn Read + 'static>,
} }
@@ -58,7 +68,7 @@ impl fmt::Debug for SizedReader {
} }
impl SizedReader { impl SizedReader {
fn new(size: Option<usize>, reader: Box<dyn Read + 'static>) -> Self { fn new(size: BodySize, reader: Box<dyn Read + 'static>) -> Self {
SizedReader { size, reader } SizedReader { size, reader }
} }
} }
@@ -66,7 +76,7 @@ impl SizedReader {
impl Payload { impl Payload {
pub fn into_read(self) -> SizedReader { pub fn into_read(self) -> SizedReader {
match self { match self {
Payload::Empty => SizedReader::new(Some(0), Box::new(empty())), Payload::Empty => SizedReader::new(BodySize::Empty, Box::new(empty())),
Payload::Text(text, _charset) => { Payload::Text(text, _charset) => {
#[cfg(feature = "charset")] #[cfg(feature = "charset")]
let bytes = { let bytes = {
@@ -79,20 +89,20 @@ impl Payload {
let bytes = text.into_bytes(); let bytes = text.into_bytes();
let len = bytes.len(); let len = bytes.len();
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
SizedReader::new(Some(len), Box::new(cursor)) SizedReader::new(BodySize::Known(len as u64), Box::new(cursor))
} }
#[cfg(feature = "json")] #[cfg(feature = "json")]
Payload::JSON(v) => { Payload::JSON(v) => {
let bytes = serde_json::to_vec(&v).expect("Bad JSON in payload"); let bytes = serde_json::to_vec(&v).expect("Bad JSON in payload");
let len = bytes.len(); let len = bytes.len();
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
SizedReader::new(Some(len), Box::new(cursor)) SizedReader::new(BodySize::Known(len as u64), Box::new(cursor))
} }
Payload::Reader(read) => SizedReader::new(None, read), Payload::Reader(read) => SizedReader::new(BodySize::Unknown, read),
Payload::Bytes(bytes) => { Payload::Bytes(bytes) => {
let len = bytes.len(); let len = bytes.len();
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
SizedReader::new(Some(len), Box::new(cursor)) SizedReader::new(BodySize::Known(len as u64), Box::new(cursor))
} }
} }
} }

View File

@@ -8,6 +8,7 @@ use qstring::QString;
use url::{form_urlencoded, Url}; use url::{form_urlencoded, Url};
use crate::agent::{self, Agent, AgentState}; use crate::agent::{self, Agent, AgentState};
use crate::body::BodySize;
use crate::body::{Payload, SizedReader}; use crate::body::{Payload, SizedReader};
use crate::error::Error; use crate::error::Error;
use crate::header::{self, Header}; use crate::header::{self, Header};
@@ -604,8 +605,14 @@ impl Request {
// Sized bodies are retryable only if they are zero-length because of // Sized bodies are retryable only if they are zero-length because of
// coincidences of the current implementation - the function responsible // coincidences of the current implementation - the function responsible
// for retries doesn't have a way to replay a Payload. // for retries doesn't have a way to replay a Payload.
let no_body = body.size.is_none() || body.size.unwrap() > 0; let retryable_body = match body.size {
idempotent && no_body BodySize::Unknown => false,
BodySize::Known(0) => true,
BodySize::Known(_) => false,
BodySize::Empty => true,
};
idempotent && retryable_body
} }
} }

View File

@@ -8,7 +8,7 @@ use url::Url;
use cookie::{Cookie, CookieJar}; use cookie::{Cookie, CookieJar};
use crate::agent::AgentState; use crate::agent::AgentState;
use crate::body::{self, Payload, SizedReader}; use crate::body::{self, BodySize, Payload, SizedReader};
use crate::header; use crate::header;
use crate::resolve::ArcResolver; use crate::resolve::ArcResolver;
use crate::stream::{self, connect_test, Stream}; use crate::stream::{self, connect_test, Stream};
@@ -56,15 +56,17 @@ impl Unit {
// Content-Length, // Content-Length,
// otherwise, use the chunked Transfer-Encoding (only if no other Transfer-Encoding // otherwise, use the chunked Transfer-Encoding (only if no other Transfer-Encoding
// has been set // has been set
if let Some(size) = body.size { match body.size {
if size != 0 { BodySize::Known(size) => {
extra.push(Header::new("Content-Length", &format!("{}", size))); extra.push(Header::new("Content-Length", &format!("{}", size)))
} }
} else { BodySize::Unknown => {
if !is_transfer_encoding_set { if !is_transfer_encoding_set {
extra.push(Header::new("Transfer-Encoding", "chunked")); extra.push(Header::new("Transfer-Encoding", "chunked"));
is_chunked = true; is_chunked = true;
}
} }
BodySize::Empty => {}
} }
} }