feat(lib): update Tokio, bytes, http, h2, and http-body

This commit is contained in:
Sean McArthur
2019-12-03 14:36:20 -08:00
parent 131962c86a
commit cb3f39c2dc
51 changed files with 985 additions and 1305 deletions

View File

@@ -5,7 +5,7 @@ use std::marker::PhantomData;
use bytes::{Buf, Bytes};
use http::{HeaderMap, Method, Version};
use http::header::{HeaderValue, CONNECTION};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::Chunk;
use crate::common::{Pin, Poll, Unpin, task};
@@ -915,7 +915,11 @@ mod tests {
*conn.io.read_buf_mut() = ::bytes::BytesMut::from(&s[..]);
conn.state.cached_headers = Some(HeaderMap::with_capacity(2));
let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap();
let mut rt = tokio::runtime::Builder::new()
.enable_all()
.basic_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(futures_util::future::poll_fn(|cx| {

View File

@@ -328,7 +328,7 @@ impl StdError for IncompleteBody {
mod tests {
use std::time::Duration;
use std::pin::Pin;
use tokio_io::AsyncRead;
use tokio::io::AsyncRead;
use super::*;
impl<'a> MemRead for &'a [u8] {
@@ -336,7 +336,7 @@ mod tests {
let n = ::std::cmp::min(len, self.len());
if n > 0 {
let (a, b) = self.split_at(n);
let buf = Bytes::from(a);
let buf = Bytes::copy_from_slice(a);
*self = b;
Poll::Ready(Ok(buf))
} else {
@@ -349,7 +349,7 @@ mod tests {
fn read_mem(&mut self, cx: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
let mut v = vec![0; len];
let n = ready!(Pin::new(self).poll_read(cx, &mut v)?);
Poll::Ready(Ok(Bytes::from(&v[..n])))
Poll::Ready(Ok(Bytes::copy_from_slice(&v[..n])))
}
}

View File

@@ -2,7 +2,7 @@ use std::error::Error as StdError;
use bytes::{Buf, Bytes};
use http::{Request, Response, StatusCode};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::body::{Body, Payload};
use crate::common::{Future, Never, Poll, Pin, Unpin, task};
@@ -605,7 +605,7 @@ mod tests {
fn client_read_bytes_before_writing_request() {
let _ = pretty_env_logger::try_init();
tokio_test::task::mock(|cx| {
tokio_test::task::spawn(()).enter(|cx, _| {
let (io, mut handle) = tokio_test::io::Builder::new()
.build_with_handle();
@@ -637,36 +637,32 @@ mod tests {
});
}
#[test]
fn body_empty_chunks_ignored() {
#[tokio::test]
async fn body_empty_chunks_ignored() {
let _ = pretty_env_logger::try_init();
tokio_test::clock::mock(|_timer| {
tokio_test::task::mock(|cx| {
let io = tokio_test::io::Builder::new()
// no reading or writing, just be blocked for the test...
.wait(Duration::from_secs(5))
.build();
let io = tokio_test::io::Builder::new()
// no reading or writing, just be blocked for the test...
.wait(Duration::from_secs(5))
.build();
let (mut tx, rx) = crate::client::dispatch::channel();
let conn = Conn::<_, crate::Chunk, ClientTransaction>::new(io);
let mut dispatcher = Dispatcher::new(Client::new(rx), conn);
let (mut tx, rx) = crate::client::dispatch::channel();
let conn = Conn::<_, crate::Chunk, ClientTransaction>::new(io);
let mut dispatcher = tokio_test::task::spawn(Dispatcher::new(Client::new(rx), conn));
// First poll is needed to allow tx to send...
assert!(Pin::new(&mut dispatcher).poll(cx).is_pending());
// First poll is needed to allow tx to send...
assert!(dispatcher.poll().is_pending());
let body = {
let (mut tx, body) = crate::Body::channel();
tx.try_send_data("".into()).unwrap();
body
};
let body = {
let (mut tx, body) = crate::Body::channel();
tx.try_send_data("".into()).unwrap();
body
};
let _res_rx = tx.try_send(crate::Request::new(body)).unwrap();
let _res_rx = tx.try_send(crate::Request::new(body)).unwrap();
// Ensure conn.write_body wasn't called with the empty chunk.
// If it is, it will trigger an assertion.
assert!(Pin::new(&mut dispatcher).poll(cx).is_pending());
});
});
// Ensure conn.write_body wasn't called with the empty chunk.
// If it is, it will trigger an assertion.
assert!(dispatcher.poll().is_pending());
}
}

View File

@@ -1,12 +1,13 @@
use std::fmt;
use std::io::IoSlice;
use bytes::{Buf, IntoBuf};
use bytes::buf::{Chain, Take};
use iovec::IoVec;
use bytes::Buf;
use bytes::buf::ext::{BufExt, Chain, Take};
use crate::common::StaticBuf;
use super::io::WriteBuf;
type StaticBuf = &'static [u8];
/// Encoders to handle different Transfer-Encodings.
#[derive(Debug, Clone, PartialEq)]
pub struct Encoder {
@@ -84,17 +85,16 @@ impl Encoder {
match self.kind {
Kind::Length(0) => Ok(None),
Kind::Chunked => Ok(Some(EncodedBuf {
kind: BufKind::ChunkedEnd(StaticBuf(b"0\r\n\r\n")),
kind: BufKind::ChunkedEnd(b"0\r\n\r\n"),
})),
_ => Err(NotEof),
}
}
pub fn encode<B>(&mut self, msg: B) -> EncodedBuf<B::Buf>
pub fn encode<B>(&mut self, msg: B) -> EncodedBuf<B>
where
B: IntoBuf,
B: Buf,
{
let msg = msg.into_buf();
let len = msg.remaining();
debug_assert!(len > 0, "encode() called with empty buf");
@@ -103,7 +103,7 @@ impl Encoder {
trace!("encoding chunked {}B", len);
let buf = ChunkSize::new(len)
.chain(msg)
.chain(StaticBuf(b"\r\n"));
.chain(b"\r\n" as &'static [u8]);
BufKind::Chunked(buf)
},
Kind::Length(ref mut remaining) => {
@@ -127,11 +127,10 @@ impl Encoder {
}
}
pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B::Buf>>) -> bool
pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>) -> bool
where
B: IntoBuf,
B: Buf,
{
let msg = msg.into_buf();
let len = msg.remaining();
debug_assert!(len > 0, "encode() called with empty buf");
@@ -140,7 +139,7 @@ impl Encoder {
trace!("encoding chunked {}B", len);
let buf = ChunkSize::new(len)
.chain(msg)
.chain(StaticBuf(b"\r\n0\r\n\r\n"));
.chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf);
!self.is_last
},
@@ -176,11 +175,10 @@ impl Encoder {
/// This is used in conjunction with Payload::__hyper_full_data(), which
/// means we can trust that the buf has the correct size (the buf itself
/// was checked to make the headers).
pub(super) fn danger_full_buf<B>(self, msg: B, dst: &mut WriteBuf<EncodedBuf<B::Buf>>)
pub(super) fn danger_full_buf<B>(self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>)
where
B: IntoBuf,
B: Buf,
{
let msg = msg.into_buf();
debug_assert!(msg.remaining() > 0, "encode() called with empty buf");
debug_assert!(match self.kind {
Kind::Length(len) => len == msg.remaining() as u64,
@@ -193,7 +191,7 @@ impl Encoder {
trace!("encoding chunked {}B", len);
let buf = ChunkSize::new(len)
.chain(msg)
.chain(StaticBuf(b"\r\n0\r\n\r\n"));
.chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf);
},
_ => {
@@ -238,12 +236,12 @@ where
}
#[inline]
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
fn bytes_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
match self.kind {
BufKind::Exact(ref b) => b.bytes_vec(dst),
BufKind::Limited(ref b) => b.bytes_vec(dst),
BufKind::Chunked(ref b) => b.bytes_vec(dst),
BufKind::ChunkedEnd(ref b) => b.bytes_vec(dst),
BufKind::Exact(ref b) => b.bytes_vectored(dst),
BufKind::Limited(ref b) => b.bytes_vectored(dst),
BufKind::Chunked(ref b) => b.bytes_vectored(dst),
BufKind::ChunkedEnd(ref b) => b.bytes_vectored(dst),
}
}
}

View File

@@ -2,11 +2,10 @@ use std::cell::Cell;
use std::cmp;
use std::collections::VecDeque;
use std::fmt;
use std::io;
use std::io::{self, IoSlice};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use iovec::IoVec;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, Unpin, task};
use super::{Http1Transaction, ParseContext, ParsedMessage};
@@ -105,6 +104,12 @@ where
&mut self.read_buf
}
/// Return the "allocated" available space, not the potential space
/// that could be allocated in the future.
fn read_buf_remaining_mut(&self) -> usize {
self.read_buf.capacity() - self.read_buf.len()
}
pub fn headers_buf(&mut self) -> &mut Vec<u8> {
let buf = self.write_buf.headers_mut();
&mut buf.bytes
@@ -170,7 +175,7 @@ where
pub fn poll_read_from_io(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<usize>> {
self.read_blocked = false;
let next = self.read_buf_strategy.next();
if self.read_buf.remaining_mut() < next {
if self.read_buf_remaining_mut() < next {
self.read_buf.reserve(next);
}
match Pin::new(&mut self.io).poll_read_buf(cx, &mut self.read_buf) {
@@ -520,9 +525,9 @@ impl<B: Buf> Buf for WriteBuf<B> {
}
#[inline]
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
let n = self.headers.bytes_vec(dst);
self.queue.bytes_vec(&mut dst[n..]) + n
fn bytes_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
let n = self.headers.bytes_vectored(dst);
self.queue.bytes_vectored(&mut dst[n..]) + n
}
}
@@ -562,9 +567,9 @@ impl<'a, B: Buf> Buf for WriteBufAuto<'a, B> {
}
#[inline]
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
fn bytes_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
self.bytes_vec_called.set(true);
self.inner.bytes_vec(dst)
self.inner.bytes_vectored(dst)
}
}
@@ -638,13 +643,13 @@ impl<T: Buf> Buf for BufDeque<T> {
}
#[inline]
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
fn bytes_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
if dst.is_empty() {
return 0;
}
let mut vecs = 0;
for buf in &self.bufs {
vecs += buf.bytes_vec(&mut dst[vecs..]);
vecs += buf.bytes_vectored(&mut dst[vecs..]);
if vecs == dst.len() {
break;
}

View File

@@ -23,7 +23,7 @@ macro_rules! header_name {
{
match HeaderName::from_bytes($bytes) {
Ok(name) => name,
Err(_) => panic!("illegal header name from httparse: {:?}", ::bytes::Bytes::from($bytes)),
Err(_) => panic!("illegal header name from httparse: {:?}", ::bytes::Bytes::copy_from_slice($bytes)),
}
}
@@ -40,7 +40,7 @@ macro_rules! header_value {
#[cfg(debug_assertions)]
{
let __hvb: ::bytes::Bytes = $bytes;
match HeaderValue::from_shared(__hvb.clone()) {
match HeaderValue::from_maybe_shared(__hvb.clone()) {
Ok(name) => name,
Err(_) => panic!("illegal header value from httparse: {:?}", __hvb),
}
@@ -50,7 +50,7 @@ macro_rules! header_value {
{
// Unsafe: httparse already validated header value
unsafe {
HeaderValue::from_shared_unchecked($bytes)
HeaderValue::from_maybe_shared_unchecked($bytes)
}
}
});
@@ -153,7 +153,7 @@ impl Http1Transaction for Server {
for header in &headers_indices[..headers_len] {
let name = header_name!(&slice[header.name.0..header.name.1]);
let value = header_value!(slice.slice(header.value.0, header.value.1));
let value = header_value!(slice.slice(header.value.0..header.value.1));
match name {
header::TRANSFER_ENCODING => {
@@ -302,10 +302,40 @@ impl Http1Transaction for Server {
let mut encoder = Encoder::length(0);
let mut wrote_date = false;
'headers: for (name, mut values) in msg.head.headers.drain() {
match name {
let mut cur_name = None;
let mut is_name_written = false;
let mut must_write_chunked = false;
let mut prev_con_len = None;
macro_rules! handle_is_name_written {
() => ({
if is_name_written {
// we need to clean up and write the newline
debug_assert_ne!(
&dst[dst.len() - 2 ..],
b"\r\n",
"previous header wrote newline but set is_name_written"
);
if must_write_chunked {
extend(dst, b", chunked\r\n");
} else {
extend(dst, b"\r\n");
}
}
})
}
'headers: for (opt_name, value) in msg.head.headers.drain() {
if let Some(n) = opt_name {
cur_name = Some(n);
handle_is_name_written!();
is_name_written = false;
}
let name = cur_name.as_ref().expect("current header name");
match *name {
header::CONTENT_LENGTH => {
if wrote_len {
if wrote_len && !is_name_written {
warn!("unexpected content-length found, canceling");
rewind(dst);
return Err(crate::Error::new_user_header());
@@ -319,77 +349,56 @@ impl Http1Transaction for Server {
//
// In debug builds, we'll assert they are the
// same to help developers find bugs.
encoder = Encoder::length(known_len);
#[cfg(debug_assertions)]
{
let mut folded = None::<(u64, HeaderValue)>;
for value in values {
if let Some(len) = headers::content_length_parse(&value) {
if let Some(fold) = folded {
if fold.0 != len {
panic!("multiple Content-Length values found: [{}, {}]", fold.0, len);
}
folded = Some(fold);
} else {
folded = Some((len, value));
}
} else {
panic!("illegal Content-Length value: {:?}", value);
}
}
if let Some((len, value)) = folded {
if let Some(len) = headers::content_length_parse(&value) {
assert!(
len == known_len,
"payload claims content-length of {}, custom content-length header claims {}",
known_len,
len,
);
extend(dst, b"content-length: ");
extend(dst, value.as_bytes());
extend(dst, b"\r\n");
wrote_len = true;
continue 'headers;
} else {
// No values in content-length... ignore?
continue 'headers;
}
}
if !is_name_written {
encoder = Encoder::length(known_len);
extend(dst, b"content-length: ");
extend(dst, value.as_bytes());
wrote_len = true;
is_name_written = true;
}
continue 'headers;
},
Some(BodyLength::Unknown) => {
// The Payload impl didn't know how long the
// body is, but a length header was included.
// We have to parse the value to return our
// Encoder...
let mut folded = None::<(u64, HeaderValue)>;
for value in values {
if let Some(len) = headers::content_length_parse(&value) {
if let Some(fold) = folded {
if fold.0 != len {
warn!("multiple Content-Length values found: [{}, {}]", fold.0, len);
rewind(dst);
return Err(crate::Error::new_user_header());
}
folded = Some(fold);
} else {
folded = Some((len, value));
if let Some(len) = headers::content_length_parse(&value) {
if let Some(prev) = prev_con_len {
if prev != len {
warn!("multiple Content-Length values found: [{}, {}]", prev, len);
rewind(dst);
return Err(crate::Error::new_user_header());
}
debug_assert!(is_name_written);
continue 'headers;
} else {
warn!("illegal Content-Length value: {:?}", value);
rewind(dst);
return Err(crate::Error::new_user_header());
// we haven't written content-lenght yet!
encoder = Encoder::length(len);
extend(dst, b"content-length: ");
extend(dst, value.as_bytes());
wrote_len = true;
is_name_written = true;
prev_con_len = Some(len);
continue 'headers;
}
}
if let Some((len, value)) = folded {
encoder = Encoder::length(len);
extend(dst, b"content-length: ");
extend(dst, value.as_bytes());
extend(dst, b"\r\n");
wrote_len = true;
continue 'headers;
} else {
// No values in content-length... ignore?
continue 'headers;
warn!("illegal Content-Length value: {:?}", value);
rewind(dst);
return Err(crate::Error::new_user_header());
}
},
None => {
@@ -402,10 +411,8 @@ impl Http1Transaction for Server {
if msg.req_method == &Some(Method::HEAD) {
debug_assert_eq!(encoder, Encoder::length(0));
} else {
for value in values {
if value.as_bytes() != b"0" {
warn!("content-length value found, but empty body provided: {:?}", value);
}
if value.as_bytes() != b"0" {
warn!("content-length value found, but empty body provided: {:?}", value);
}
continue 'headers;
}
@@ -414,7 +421,7 @@ impl Http1Transaction for Server {
wrote_len = true;
},
header::TRANSFER_ENCODING => {
if wrote_len {
if wrote_len && !is_name_written {
warn!("unexpected transfer-encoding found, canceling");
rewind(dst);
return Err(crate::Error::new_user_header());
@@ -424,44 +431,36 @@ impl Http1Transaction for Server {
continue;
}
wrote_len = true;
encoder = Encoder::chunked();
// Must check each value, because `chunked` needs to be the
// last encoding, or else we add it.
must_write_chunked = !headers::is_chunked_(&value);
extend(dst, b"transfer-encoding: ");
let mut saw_chunked;
if let Some(te) = values.next() {
extend(dst, te.as_bytes());
saw_chunked = headers::is_chunked_(&te);
for value in values {
extend(dst, b", ");
extend(dst, value.as_bytes());
saw_chunked = headers::is_chunked_(&value);
}
if !saw_chunked {
extend(dst, b", chunked\r\n");
} else {
extend(dst, b"\r\n");
}
if !is_name_written {
encoder = Encoder::chunked();
is_name_written = true;
extend(dst, b"transfer-encoding: ");
extend(dst, value.as_bytes());
} else {
// zero lines? add a chunked line then
extend(dst, b"chunked\r\n");
extend(dst, b", ");
extend(dst, value.as_bytes());
}
continue 'headers;
},
header::CONNECTION => {
if !is_last {
for value in values {
extend(dst, name.as_str().as_bytes());
extend(dst, b": ");
extend(dst, value.as_bytes());
extend(dst, b"\r\n");
if headers::connection_close(&value) {
is_last = true;
}
if headers::connection_close(&value) {
is_last = true;
}
continue 'headers;
}
if !is_name_written {
is_name_written = true;
extend(dst, b"connection: ");
extend(dst, value.as_bytes());
} else {
extend(dst, b", ");
extend(dst, value.as_bytes());
}
continue 'headers;
},
header::DATE => {
wrote_date = true;
@@ -470,14 +469,21 @@ impl Http1Transaction for Server {
}
//TODO: this should perhaps instead combine them into
//single lines, as RFC7230 suggests is preferable.
for value in values {
extend(dst, name.as_str().as_bytes());
extend(dst, b": ");
extend(dst, value.as_bytes());
extend(dst, b"\r\n");
}
// non-special write Name and Value
debug_assert!(
!is_name_written,
"{:?} set is_name_written and didn't continue loop",
name,
);
extend(dst, name.as_str().as_bytes());
extend(dst, b": ");
extend(dst, value.as_bytes());
extend(dst, b"\r\n");
}
handle_is_name_written!();
if !wrote_len {
encoder = match msg.body {
Some(BodyLength::Unknown) => {
@@ -629,7 +635,7 @@ impl Http1Transaction for Client {
headers.reserve(headers_len);
for header in &headers_indices[..headers_len] {
let name = header_name!(&slice[header.name.0..header.name.1]);
let value = header_value!(slice.slice(header.value.0, header.value.1));
let value = header_value!(slice.slice(header.value.0..header.value.1));
if let header::CONNECTION = name {
// keep_alive was previously set to default for Version
@@ -820,8 +826,7 @@ impl Client {
// If the user set a transfer-encoding, respect that. Let's just
// make sure `chunked` is the final encoding.
let encoder = match headers.entry(header::TRANSFER_ENCODING)
.expect("TRANSFER_ENCODING is valid HeaderName") {
let encoder = match headers.entry(header::TRANSFER_ENCODING) {
Entry::Occupied(te) => {
should_remove_con_len = true;
if headers::is_chunked(te.iter()) {
@@ -906,8 +911,7 @@ fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
// so perhaps only do that while the user is developing/testing.
if cfg!(debug_assertions) {
match headers.entry(header::CONTENT_LENGTH)
.expect("CONTENT_LENGTH is valid HeaderName") {
match headers.entry(header::CONTENT_LENGTH) {
Entry::Occupied(mut cl) => {
// Internal sanity check, we should have already determined
// that the header was illegal before calling this function.
@@ -1067,7 +1071,7 @@ mod tests {
#[test]
fn test_parse_request() {
let _ = pretty_env_logger::try_init();
let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
let mut raw = BytesMut::from("GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
let mut method = None;
let msg = Server::parse(&mut raw, ParseContext {
cached_headers: &mut None,
@@ -1086,7 +1090,7 @@ mod tests {
#[test]
fn test_parse_response() {
let _ = pretty_env_logger::try_init();
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec());
let mut raw = BytesMut::from("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
let ctx = ParseContext {
cached_headers: &mut None,
req_method: &mut Some(crate::Method::GET),
@@ -1101,7 +1105,7 @@ mod tests {
#[test]
fn test_parse_request_errors() {
let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
let mut raw = BytesMut::from("GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
let ctx = ParseContext {
cached_headers: &mut None,
req_method: &mut None,
@@ -1480,7 +1484,7 @@ mod tests {
#[bench]
fn bench_parse_incoming(b: &mut Bencher) {
let mut raw = BytesMut::from(
b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
&b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
_up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
@@ -1496,7 +1500,7 @@ mod tests {
X-Content-Duration: None\r\nX-Content-Security-Policy: None\
\r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
Something important obviously\r\nX-Requested-With: Nothing\
\r\n\r\n".to_vec()
\r\n\r\n"[..]
);
let len = raw.len();
let mut headers = Some(HeaderMap::new());
@@ -1526,7 +1530,7 @@ mod tests {
#[bench]
fn bench_parse_short(b: &mut Bencher) {
let s = &b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"[..];
let mut raw = BytesMut::from(s.to_vec());
let mut raw = BytesMut::from(s);
let len = raw.len();
let mut headers = Some(HeaderMap::new());

View File

@@ -2,7 +2,7 @@ use futures_channel::{mpsc, oneshot};
use futures_util::future::{self, FutureExt as _, TryFutureExt as _, Either};
use futures_util::stream::StreamExt as _;
use h2::client::{Builder, SendRequest};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::headers::content_length_parse_all;
use crate::body::Payload;
@@ -71,7 +71,7 @@ where
}
};
exec.execute(conn_task)?;
exec.execute(conn_task);
Ok(ClientTask {
conn_drop_ref,
@@ -155,7 +155,7 @@ where
drop(conn_drop_ref);
x
});
self.executor.execute(pipe)?;
self.executor.execute(pipe);
}
}
}
@@ -175,7 +175,7 @@ where
}
}
});
self.executor.execute(cb.send_when(fut))?;
self.executor.execute(cb.send_when(fut));
continue;
},

View File

@@ -4,7 +4,7 @@ use std::marker::Unpin;
use pin_project::{pin_project, project};
use h2::Reason;
use h2::server::{Builder, Connection, Handshake, SendResponse};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::body::Payload;
use crate::common::exec::H2Exec;
@@ -175,7 +175,7 @@ where
crate::Body::h2(stream, content_length)
});
let fut = H2Stream::new(service.call(req), respond);
exec.execute_h2stream(fut)?;
exec.execute_h2stream(fut);
},
Some(Err(e)) => {
return Poll::Ready(Err(crate::Error::new_h2(e)));
@@ -285,7 +285,6 @@ where
res
.headers_mut()
.entry(::http::header::DATE)
.expect("DATE is a valid HeaderName")
.or_insert_with(crate::proto::h1::date::update_and_header_value);