feat(body): change Payload::Data to be a Buf
Closes #1508 BREAKING CHANGE: Each payload chunk must implement `Buf`, instead of just `AsRef<[u8]>`.
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::{Buf, Bytes};
|
||||||
use futures::{Async, Future, Poll, Stream};
|
use futures::{Async, Future, Poll, Stream};
|
||||||
use futures::sync::{mpsc, oneshot};
|
use futures::sync::{mpsc, oneshot};
|
||||||
use h2;
|
use h2;
|
||||||
@@ -34,7 +34,7 @@ type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;
|
|||||||
/// don't need to customize a send stream for your own application.
|
/// don't need to customize a send stream for your own application.
|
||||||
pub trait Payload: Send + 'static {
|
pub trait Payload: Send + 'static {
|
||||||
/// A buffer of bytes representing a single chunk of a body.
|
/// A buffer of bytes representing a single chunk of a body.
|
||||||
type Data: AsRef<[u8]> + Send;
|
type Data: Buf + Send;
|
||||||
|
|
||||||
/// The error type of this stream.
|
/// The error type of this stream.
|
||||||
type Error: Into<Box<::std::error::Error + Send + Sync>>;
|
type Error: Into<Box<::std::error::Error + Send + Sync>>;
|
||||||
|
|||||||
19
src/chunk.rs
19
src/chunk.rs
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::{Buf, Bytes};
|
||||||
use h2::ReleaseCapacity;
|
use h2::ReleaseCapacity;
|
||||||
|
|
||||||
/// A piece of a message body.
|
/// A piece of a message body.
|
||||||
@@ -53,6 +53,23 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Buf for Chunk {
|
||||||
|
#[inline]
|
||||||
|
fn remaining(&self) -> usize {
|
||||||
|
self.bytes.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn bytes(&self) -> &[u8] {
|
||||||
|
&self.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn advance(&mut self, cnt: usize) {
|
||||||
|
self.bytes.advance(cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Vec<u8>> for Chunk {
|
impl From<Vec<u8>> for Chunk {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(v: Vec<u8>) -> Chunk {
|
fn from(v: Vec<u8>) -> Chunk {
|
||||||
|
|||||||
@@ -626,7 +626,6 @@ impl<T: Send, B: Send> AssertSend for Connection<T, B>
|
|||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + Send + 'static,
|
T: AsyncRead + AsyncWrite + Send + 'static,
|
||||||
B: Payload + 'static,
|
B: Payload + 'static,
|
||||||
B::Data: Send + 'static,
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::fmt;
|
|||||||
use std::io::{self};
|
use std::io::{self};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::{Buf, Bytes};
|
||||||
use futures::{Async, AsyncSink, Poll, StartSend};
|
use futures::{Async, AsyncSink, Poll, StartSend};
|
||||||
use futures::task::Task;
|
use futures::task::Task;
|
||||||
use http::{Method, Version};
|
use http::{Method, Version};
|
||||||
@@ -10,7 +10,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
|||||||
|
|
||||||
use ::Chunk;
|
use ::Chunk;
|
||||||
use proto::{BodyLength, Decode, Http1Transaction, MessageHead};
|
use proto::{BodyLength, Decode, Http1Transaction, MessageHead};
|
||||||
use super::io::{Cursor, Buffered};
|
use super::io::{Buffered};
|
||||||
use super::{EncodedBuf, Encoder, Decoder};
|
use super::{EncodedBuf, Encoder, Decoder};
|
||||||
|
|
||||||
|
|
||||||
@@ -22,25 +22,14 @@ use super::{EncodedBuf, Encoder, Decoder};
|
|||||||
/// determine if this connection can be kept alive after the message,
|
/// determine if this connection can be kept alive after the message,
|
||||||
/// or if it is complete.
|
/// or if it is complete.
|
||||||
pub(crate) struct Conn<I, B, T> {
|
pub(crate) struct Conn<I, B, T> {
|
||||||
io: Buffered<I, EncodedBuf<Cursor<B>>>,
|
io: Buffered<I, EncodedBuf<B>>,
|
||||||
state: State,
|
state: State,
|
||||||
_marker: PhantomData<T>
|
_marker: PhantomData<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl<I, B> Conn<I, B, ClientTransaction>
|
|
||||||
where I: AsyncRead + AsyncWrite,
|
|
||||||
B: AsRef<[u8]>,
|
|
||||||
{
|
|
||||||
pub fn new_client(io: I) -> Conn<I, B, ClientTransaction> {
|
|
||||||
Conn::new(io)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl<I, B, T> Conn<I, B, T>
|
impl<I, B, T> Conn<I, B, T>
|
||||||
where I: AsyncRead + AsyncWrite,
|
where I: AsyncRead + AsyncWrite,
|
||||||
B: AsRef<[u8]>,
|
B: Buf,
|
||||||
T: Http1Transaction,
|
T: Http1Transaction,
|
||||||
{
|
{
|
||||||
pub fn new(io: I) -> Conn<I, B, T> {
|
pub fn new(io: I) -> Conn<I, B, T> {
|
||||||
@@ -488,7 +477,7 @@ where I: AsyncRead + AsyncWrite,
|
|||||||
if !self.can_buffer_body() {
|
if !self.can_buffer_body() {
|
||||||
if let Async::NotReady = self.flush()? {
|
if let Async::NotReady = self.flush()? {
|
||||||
// if chunk is Some(&[]), aka empty, whatever, just skip it
|
// if chunk is Some(&[]), aka empty, whatever, just skip it
|
||||||
if chunk.as_ref().map(|c| c.as_ref().is_empty()).unwrap_or(false) {
|
if chunk.as_ref().map(|c| c.remaining() == 0).unwrap_or(false) {
|
||||||
return Ok(AsyncSink::Ready);
|
return Ok(AsyncSink::Ready);
|
||||||
} else {
|
} else {
|
||||||
return Ok(AsyncSink::NotReady(chunk));
|
return Ok(AsyncSink::NotReady(chunk));
|
||||||
@@ -499,11 +488,11 @@ where I: AsyncRead + AsyncWrite,
|
|||||||
let state = match self.state.writing {
|
let state = match self.state.writing {
|
||||||
Writing::Body(ref mut encoder) => {
|
Writing::Body(ref mut encoder) => {
|
||||||
if let Some(chunk) = chunk {
|
if let Some(chunk) = chunk {
|
||||||
if chunk.as_ref().is_empty() {
|
if chunk.remaining() == 0 {
|
||||||
return Ok(AsyncSink::Ready);
|
return Ok(AsyncSink::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
let encoded = encoder.encode(Cursor::new(chunk));
|
let encoded = encoder.encode(chunk);
|
||||||
self.io.buffer(encoded);
|
self.io.buffer(encoded);
|
||||||
|
|
||||||
if encoder.is_eof() {
|
if encoder.is_eof() {
|
||||||
@@ -612,7 +601,7 @@ where I: AsyncRead + AsyncWrite,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, B: AsRef<[u8]>, T> fmt::Debug for Conn<I, B, T> {
|
impl<I, B: Buf, T> fmt::Debug for Conn<I, B, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("Conn")
|
f.debug_struct("Conn")
|
||||||
.field("state", &self.state)
|
.field("state", &self.state)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use bytes::Bytes;
|
use bytes::{Buf, Bytes};
|
||||||
use futures::{Async, Future, Poll, Stream};
|
use futures::{Async, Future, Poll, Stream};
|
||||||
use http::{Request, Response, StatusCode};
|
use http::{Request, Response, StatusCode};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@@ -241,7 +241,7 @@ where
|
|||||||
if self.conn.can_write_body() {
|
if self.conn.can_write_body() {
|
||||||
self.conn.write_body(Some(chunk)).map_err(::Error::new_body_write)?;
|
self.conn.write_body(Some(chunk)).map_err(::Error::new_body_write)?;
|
||||||
// This allows when chunk is `None`, or `Some([])`.
|
// This allows when chunk is `None`, or `Some([])`.
|
||||||
} else if chunk.as_ref().len() == 0 {
|
} else if chunk.remaining() == 0 {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
warn!("unexpected chunk when body cannot write");
|
warn!("unexpected chunk when body cannot write");
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use http::HeaderMap;
|
|||||||
use http::header::{CONNECTION, TRANSFER_ENCODING};
|
use http::header::{CONNECTION, TRANSFER_ENCODING};
|
||||||
|
|
||||||
use ::body::Payload;
|
use ::body::Payload;
|
||||||
use ::proto::h1::Cursor;
|
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod server;
|
mod server;
|
||||||
@@ -74,11 +73,11 @@ where
|
|||||||
let is_eos = self.stream.is_end_stream();
|
let is_eos = self.stream.is_end_stream();
|
||||||
trace!(
|
trace!(
|
||||||
"send body chunk: {} bytes, eos={}",
|
"send body chunk: {} bytes, eos={}",
|
||||||
chunk.as_ref().len(),
|
chunk.remaining(),
|
||||||
is_eos,
|
is_eos,
|
||||||
);
|
);
|
||||||
|
|
||||||
let buf = SendBuf(Some(Cursor::new(chunk)));
|
let buf = SendBuf(Some(chunk));
|
||||||
self.body_tx.send_data(buf, is_eos)
|
self.body_tx.send_data(buf, is_eos)
|
||||||
.map_err(::Error::new_body_write)?;
|
.map_err(::Error::new_body_write)?;
|
||||||
|
|
||||||
@@ -104,9 +103,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SendBuf<B>(Option<Cursor<B>>);
|
struct SendBuf<B>(Option<B>);
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> Buf for SendBuf<B> {
|
impl<B: Buf> Buf for SendBuf<B> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remaining(&self) -> usize {
|
fn remaining(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
|
|||||||
Reference in New Issue
Block a user