1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-28 01:52:57 +01:00

fix chunked transfer encoding handling

This commit is contained in:
Nikolay Kim 2019-02-18 20:24:50 -08:00
parent d180b2a1e3
commit 842da939dc
6 changed files with 40 additions and 9 deletions

View File

@ -13,7 +13,6 @@ pub enum BodyLength {
Empty, Empty,
Sized(usize), Sized(usize),
Sized64(u64), Sized64(u64),
Chunked,
Stream, Stream,
} }
@ -331,7 +330,7 @@ where
E: Into<Error>, E: Into<Error>,
{ {
fn length(&self) -> BodyLength { fn length(&self) -> BodyLength {
BodyLength::Chunked BodyLength::Stream
} }
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> { fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {

View File

@ -47,7 +47,7 @@ where
// Content length // Content length
let _ = match length { let _ = match length {
BodyLength::Chunked | BodyLength::None => None, BodyLength::None => None,
BodyLength::Stream => { BodyLength::Stream => {
skip_len = false; skip_len = false;
None None

View File

@ -45,6 +45,8 @@ pub(crate) trait MessageType: Sized {
fn headers(&self) -> &HeaderMap; fn headers(&self) -> &HeaderMap;
fn chunked(&self) -> bool;
fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>; fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>;
fn encode_headers( fn encode_headers(
@ -71,8 +73,10 @@ pub(crate) trait MessageType: Sized {
} }
} }
match length { match length {
BodyLength::Chunked => { BodyLength::Stream => {
dst.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n") if self.chunked() {
dst.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
}
} }
BodyLength::Empty => { BodyLength::Empty => {
dst.extend_from_slice(b"\r\ncontent-length: 0\r\n"); dst.extend_from_slice(b"\r\ncontent-length: 0\r\n");
@ -83,7 +87,7 @@ pub(crate) trait MessageType: Sized {
write!(dst.writer(), "{}", len)?; write!(dst.writer(), "{}", len)?;
dst.extend_from_slice(b"\r\n"); dst.extend_from_slice(b"\r\n");
} }
BodyLength::None | BodyLength::Stream => dst.extend_from_slice(b"\r\n"), BodyLength::None => dst.extend_from_slice(b"\r\n"),
} }
// Connection // Connection
@ -159,6 +163,10 @@ impl MessageType for Response<()> {
Some(self.head().status) Some(self.head().status)
} }
fn chunked(&self) -> bool {
!self.head().no_chunking
}
fn connection_type(&self) -> Option<ConnectionType> { fn connection_type(&self) -> Option<ConnectionType> {
self.head().ctype self.head().ctype
} }
@ -188,6 +196,10 @@ impl MessageType for RequestHead {
self.ctype self.ctype
} }
fn chunked(&self) -> bool {
!self.no_chunking
}
fn headers(&self) -> &HeaderMap { fn headers(&self) -> &HeaderMap {
&self.headers &self.headers
} }
@ -236,8 +248,13 @@ impl<T: MessageType> MessageEncoder<T> {
BodyLength::Empty => TransferEncoding::empty(), BodyLength::Empty => TransferEncoding::empty(),
BodyLength::Sized(len) => TransferEncoding::length(len as u64), BodyLength::Sized(len) => TransferEncoding::length(len as u64),
BodyLength::Sized64(len) => TransferEncoding::length(len), BodyLength::Sized64(len) => TransferEncoding::length(len),
BodyLength::Chunked => TransferEncoding::chunked(), BodyLength::Stream => {
BodyLength::Stream => TransferEncoding::eof(), if message.chunked() {
TransferEncoding::chunked()
} else {
TransferEncoding::eof()
}
}
BodyLength::None => TransferEncoding::empty(), BodyLength::None => TransferEncoding::empty(),
}; };
} else { } else {

View File

@ -181,7 +181,7 @@ where
_ => (), _ => (),
} }
let _ = match length { let _ = match length {
BodyLength::Chunked | BodyLength::None | BodyLength::Stream => None, BodyLength::None | BodyLength::Stream => None,
BodyLength::Empty => res BodyLength::Empty => res
.headers_mut() .headers_mut()
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")), .insert(CONTENT_LENGTH, HeaderValue::from_static("0")),

View File

@ -36,6 +36,7 @@ pub trait Head: Default + 'static {
self.connection_type() == ConnectionType::Upgrade self.connection_type() == ConnectionType::Upgrade
} }
/// Check if keep-alive is enabled
fn keep_alive(&self) -> bool { fn keep_alive(&self) -> bool {
self.connection_type() == ConnectionType::KeepAlive self.connection_type() == ConnectionType::KeepAlive
} }
@ -50,6 +51,7 @@ pub struct RequestHead {
pub version: Version, pub version: Version,
pub headers: HeaderMap, pub headers: HeaderMap,
pub ctype: Option<ConnectionType>, pub ctype: Option<ConnectionType>,
pub no_chunking: bool,
pub extensions: RefCell<Extensions>, pub extensions: RefCell<Extensions>,
} }
@ -61,6 +63,7 @@ impl Default for RequestHead {
version: Version::HTTP_11, version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16), headers: HeaderMap::with_capacity(16),
ctype: None, ctype: None,
no_chunking: false,
extensions: RefCell::new(Extensions::new()), extensions: RefCell::new(Extensions::new()),
} }
} }
@ -120,6 +123,7 @@ pub struct ResponseHead {
pub status: StatusCode, pub status: StatusCode,
pub headers: HeaderMap, pub headers: HeaderMap,
pub reason: Option<&'static str>, pub reason: Option<&'static str>,
pub no_chunking: bool,
pub(crate) ctype: Option<ConnectionType>, pub(crate) ctype: Option<ConnectionType>,
} }
@ -130,6 +134,7 @@ impl Default for ResponseHead {
status: StatusCode::OK, status: StatusCode::OK,
headers: HeaderMap::with_capacity(16), headers: HeaderMap::with_capacity(16),
reason: None, reason: None,
no_chunking: false,
ctype: None, ctype: None,
} }
} }
@ -139,6 +144,7 @@ impl Head for ResponseHead {
fn clear(&mut self) { fn clear(&mut self) {
self.ctype = None; self.ctype = None;
self.reason = None; self.reason = None;
self.no_chunking = false;
self.headers.clear(); self.headers.clear();
} }

View File

@ -459,6 +459,15 @@ impl ResponseBuilder {
self self
} }
/// Disable chunked transfer encoding for HTTP/1.1 streaming responses.
#[inline]
pub fn no_chunking(&mut self) -> &mut Self {
if let Some(parts) = parts(&mut self.head, &self.err) {
parts.no_chunking = true;
}
self
}
/// Set response content type /// Set response content type
#[inline] #[inline]
pub fn content_type<V>(&mut self, value: V) -> &mut Self pub fn content_type<V>(&mut self, value: V) -> &mut Self