perf(h1): remove book keeping on final body writes
This commit is contained in:
34
src/common/buf.rs
Normal file
34
src/common/buf.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use bytes::Buf;
|
||||||
|
use iovec::IoVec;
|
||||||
|
|
||||||
|
/// A `Buf` wrapping a static byte slice.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct StaticBuf(pub(crate) &'static [u8]);
|
||||||
|
|
||||||
|
impl Buf for StaticBuf {
|
||||||
|
#[inline]
|
||||||
|
fn remaining(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn bytes(&self) -> &[u8] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn advance(&mut self, cnt: usize) {
|
||||||
|
self.0 = &self.0[cnt..];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
|
||||||
|
if dst.is_empty() {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
dst[0] = self.0.into();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
mod buf;
|
||||||
mod exec;
|
mod exec;
|
||||||
mod never;
|
mod never;
|
||||||
|
|
||||||
|
pub(crate) use self::buf::StaticBuf;
|
||||||
pub(crate) use self::exec::Exec;
|
pub(crate) use self::exec::Exec;
|
||||||
pub use self::never::Never;
|
pub use self::never::Never;
|
||||||
|
|||||||
@@ -482,20 +482,13 @@ where I: AsyncRead + AsyncWrite,
|
|||||||
debug_assert!(chunk.remaining() != 0);
|
debug_assert!(chunk.remaining() != 0);
|
||||||
|
|
||||||
let state = match self.state.writing {
|
let state = match self.state.writing {
|
||||||
Writing::Body(ref mut encoder) => {
|
Writing::Body(ref encoder) => {
|
||||||
self.io.buffer(encoder.encode(chunk));
|
let (encoded, can_keep_alive) = encoder.encode_and_end(chunk);
|
||||||
match encoder.end() {
|
self.io.buffer(encoded);
|
||||||
Ok(end) => {
|
if can_keep_alive {
|
||||||
if let Some(end) = end {
|
Writing::KeepAlive
|
||||||
self.io.buffer(end);
|
} else {
|
||||||
}
|
Writing::Closed
|
||||||
if encoder.is_last() {
|
|
||||||
Writing::Closed
|
|
||||||
} else {
|
|
||||||
Writing::KeepAlive
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_not_eof) => Writing::Closed,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => unreachable!("write_body invalid state: {:?}", self.state.writing),
|
_ => unreachable!("write_body invalid state: {:?}", self.state.writing),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
//use std::cmp;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::{Buf, IntoBuf};
|
use bytes::{Buf, IntoBuf};
|
||||||
use bytes::buf::{Chain, Take};
|
use bytes::buf::{Chain, Take};
|
||||||
use iovec::IoVec;
|
use iovec::IoVec;
|
||||||
|
|
||||||
|
use common::StaticBuf;
|
||||||
|
|
||||||
/// Encoders to handle different Transfer-Encodings.
|
/// Encoders to handle different Transfer-Encodings.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Encoder {
|
pub struct Encoder {
|
||||||
@@ -39,8 +40,8 @@ enum Kind {
|
|||||||
enum BufKind<B> {
|
enum BufKind<B> {
|
||||||
Exact(B),
|
Exact(B),
|
||||||
Limited(Take<B>),
|
Limited(Take<B>),
|
||||||
Chunked(Chain<ChunkSize, Chain<B, CrLf>>),
|
Chunked(Chain<Chain<ChunkSize, B>, StaticBuf>),
|
||||||
ChunkedEnd(CrLf),
|
ChunkedEnd(StaticBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encoder {
|
impl Encoder {
|
||||||
@@ -81,7 +82,7 @@ impl Encoder {
|
|||||||
match self.kind {
|
match self.kind {
|
||||||
Kind::Length(0) => Ok(None),
|
Kind::Length(0) => Ok(None),
|
||||||
Kind::Chunked => Ok(Some(EncodedBuf {
|
Kind::Chunked => Ok(Some(EncodedBuf {
|
||||||
kind: BufKind::ChunkedEnd(CrLf(b"0\r\n\r\n")),
|
kind: BufKind::ChunkedEnd(StaticBuf(b"0\r\n\r\n")),
|
||||||
})),
|
})),
|
||||||
_ => Err(NotEof),
|
_ => Err(NotEof),
|
||||||
}
|
}
|
||||||
@@ -93,13 +94,15 @@ impl Encoder {
|
|||||||
{
|
{
|
||||||
let msg = msg.into_buf();
|
let msg = msg.into_buf();
|
||||||
let len = msg.remaining();
|
let len = msg.remaining();
|
||||||
assert!(len > 0, "encode() called with empty buf");
|
debug_assert!(len > 0, "encode() called with empty buf");
|
||||||
|
|
||||||
let buf = match self.kind {
|
let kind = match self.kind {
|
||||||
Kind::Chunked => {
|
Kind::Chunked => {
|
||||||
trace!("encoding chunked {}B", len);
|
trace!("encoding chunked {}B", len);
|
||||||
BufKind::Chunked(ChunkSize::new(len)
|
let buf = ChunkSize::new(len)
|
||||||
.chain(msg.chain(CrLf(b"\r\n"))))
|
.chain(msg)
|
||||||
|
.chain(StaticBuf(b"\r\n"));
|
||||||
|
BufKind::Chunked(buf)
|
||||||
},
|
},
|
||||||
Kind::Length(ref mut remaining) => {
|
Kind::Length(ref mut remaining) => {
|
||||||
trace!("sized write, len = {}", len);
|
trace!("sized write, len = {}", len);
|
||||||
@@ -118,9 +121,52 @@ impl Encoder {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
EncodedBuf {
|
EncodedBuf {
|
||||||
kind: buf,
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encode_and_end<B>(&self, msg: B) -> (EncodedBuf<B::Buf>, bool)
|
||||||
|
where
|
||||||
|
B: IntoBuf,
|
||||||
|
{
|
||||||
|
let msg = msg.into_buf();
|
||||||
|
let len = msg.remaining();
|
||||||
|
debug_assert!(len > 0, "encode() called with empty buf");
|
||||||
|
|
||||||
|
let (kind, eof) = match self.kind {
|
||||||
|
Kind::Chunked => {
|
||||||
|
trace!("encoding chunked {}B", len);
|
||||||
|
let buf = ChunkSize::new(len)
|
||||||
|
.chain(msg)
|
||||||
|
.chain(StaticBuf(b"\r\n0\r\n\r\n"));
|
||||||
|
(BufKind::Chunked(buf), !self.is_last)
|
||||||
|
},
|
||||||
|
Kind::Length(remaining) => {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
trace!("sized write, len = {}", len);
|
||||||
|
match (len as u64).cmp(&remaining) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
(BufKind::Limited(msg.take(remaining as usize)), !self.is_last)
|
||||||
|
},
|
||||||
|
Ordering::Equal => {
|
||||||
|
(BufKind::Exact(msg), !self.is_last)
|
||||||
|
},
|
||||||
|
Ordering::Less => {
|
||||||
|
(BufKind::Exact(msg), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Kind::CloseDelimited => {
|
||||||
|
trace!("close delimited write {}B", len);
|
||||||
|
(BufKind::Exact(msg), false)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(EncodedBuf {
|
||||||
|
kind,
|
||||||
|
}, eof)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Buf for EncodedBuf<B>
|
impl<B> Buf for EncodedBuf<B>
|
||||||
@@ -236,36 +282,6 @@ impl fmt::Write for ChunkSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct CrLf(&'static [u8]);
|
|
||||||
|
|
||||||
impl Buf for CrLf {
|
|
||||||
#[inline]
|
|
||||||
fn remaining(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bytes(&self) -> &[u8] {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn advance(&mut self, cnt: usize) {
|
|
||||||
self.0 = &self.0[cnt..];
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
|
|
||||||
if dst.is_empty() {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
dst[0] = self.0.into();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bytes::{BufMut};
|
use bytes::{BufMut};
|
||||||
|
|||||||
Reference in New Issue
Block a user