style(lib): run rustfmt and enforce in CI

This commit is contained in:
Sean McArthur
2019-12-05 13:30:53 -08:00
parent b0060f277e
commit 0dc89680cd
69 changed files with 2982 additions and 2499 deletions

View File

@@ -9,9 +9,31 @@ env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
jobs: jobs:
style:
name: Check Style
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: cargo fmt --check
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
test: test:
name: Test ${{ matrix.rust }} on ${{ matrix.os }} name: Test ${{ matrix.rust }} on ${{ matrix.os }}
needs: [style]
strategy: strategy:
matrix: matrix:
rust: rust:

View File

@@ -1 +0,0 @@
disable_all_formatting = true

View File

@@ -3,11 +3,11 @@
extern crate test; extern crate test;
use http::Uri;
use hyper::client::connect::HttpConnector;
use hyper::service::Service;
use std::net::SocketAddr; use std::net::SocketAddr;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use hyper::client::connect::{HttpConnector};
use hyper::service::Service;
use http::Uri;
#[bench] #[bench]
fn http_connector(b: &mut test::Bencher) { fn http_connector(b: &mut test::Bencher) {
@@ -17,7 +17,9 @@ fn http_connector(b: &mut test::Bencher) {
.basic_scheduler() .basic_scheduler()
.build() .build()
.expect("rt build"); .expect("rt build");
let mut listener = rt.block_on(TcpListener::bind(&SocketAddr::from(([127, 0, 0, 1], 0)))).expect("bind"); let mut listener = rt
.block_on(TcpListener::bind(&SocketAddr::from(([127, 0, 0, 1], 0))))
.expect("bind");
let addr = listener.local_addr().expect("local_addr"); let addr = listener.local_addr().expect("local_addr");
let dst: Uri = format!("http://{}/", addr).parse().expect("uri parse"); let dst: Uri = format!("http://{}/", addr).parse().expect("uri parse");
let mut connector = HttpConnector::new(); let mut connector = HttpConnector::new();
@@ -28,7 +30,6 @@ fn http_connector(b: &mut test::Bencher) {
} }
}); });
b.iter(|| { b.iter(|| {
rt.block_on(async { rt.block_on(async {
connector.call(dst.clone()).await.expect("connect"); connector.call(dst.clone()).await.expect("connect");

View File

@@ -7,15 +7,14 @@ use std::net::SocketAddr;
use futures_util::future::join_all; use futures_util::future::join_all;
use hyper::{body::HttpBody as _, Body, Method, Request, Response, Server};
use hyper::client::HttpConnector; use hyper::client::HttpConnector;
use hyper::{body::HttpBody as _, Body, Method, Request, Response, Server};
// HTTP1 // HTTP1
#[bench] #[bench]
fn http1_get(b: &mut test::Bencher) { fn http1_get(b: &mut test::Bencher) {
opts() opts().bench(b)
.bench(b)
} }
#[bench] #[bench]
@@ -48,9 +47,7 @@ fn http1_body_both_10mb(b: &mut test::Bencher) {
#[bench] #[bench]
fn http1_parallel_x10_empty(b: &mut test::Bencher) { fn http1_parallel_x10_empty(b: &mut test::Bencher) {
opts() opts().parallel(10).bench(b)
.parallel(10)
.bench(b)
} }
#[bench] #[bench]
@@ -76,19 +73,13 @@ fn http1_parallel_x10_req_10kb_100_chunks(b: &mut test::Bencher) {
#[bench] #[bench]
fn http1_parallel_x10_res_1mb(b: &mut test::Bencher) { fn http1_parallel_x10_res_1mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 1]; let body = &[b'x'; 1024 * 1024 * 1];
opts() opts().parallel(10).response_body(body).bench(b)
.parallel(10)
.response_body(body)
.bench(b)
} }
#[bench] #[bench]
fn http1_parallel_x10_res_10mb(b: &mut test::Bencher) { fn http1_parallel_x10_res_10mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 10]; let body = &[b'x'; 1024 * 1024 * 10];
opts() opts().parallel(10).response_body(body).bench(b)
.parallel(10)
.response_body(body)
.bench(b)
} }
// HTTP2 // HTTP2
@@ -97,9 +88,7 @@ const HTTP2_MAX_WINDOW: u32 = std::u32::MAX >> 1;
#[bench] #[bench]
fn http2_get(b: &mut test::Bencher) { fn http2_get(b: &mut test::Bencher) {
opts() opts().http2().bench(b)
.http2()
.bench(b)
} }
#[bench] #[bench]
@@ -123,10 +112,7 @@ fn http2_req_100kb(b: &mut test::Bencher) {
#[bench] #[bench]
fn http2_parallel_x10_empty(b: &mut test::Bencher) { fn http2_parallel_x10_empty(b: &mut test::Bencher) {
opts() opts().http2().parallel(10).bench(b)
.http2()
.parallel(10)
.bench(b)
} }
#[bench] #[bench]
@@ -293,9 +279,10 @@ impl Opts {
let make_request = || { let make_request = || {
let chunk_cnt = self.request_chunks; let chunk_cnt = self.request_chunks;
let body = if chunk_cnt > 0 { let body = if chunk_cnt > 0 {
let (mut tx, body) = Body::channel(); let (mut tx, body) = Body::channel();
let chunk = self.request_body.expect("request_chunks means request_body"); let chunk = self
.request_body
.expect("request_chunks means request_body");
exec.spawn(async move { exec.spawn(async move {
for _ in 0..chunk_cnt { for _ in 0..chunk_cnt {
tx.send_data(chunk.into()).await.expect("send_data"); tx.send_data(chunk.into()).await.expect("send_data");
@@ -303,8 +290,7 @@ impl Opts {
}); });
body body
} else { } else {
self self.request_body
.request_body
.map(Body::from) .map(Body::from)
.unwrap_or_else(|| Body::empty()) .unwrap_or_else(|| Body::empty())
}; };
@@ -328,11 +314,9 @@ impl Opts {
let req = make_request(); let req = make_request();
rt.block_on(send_request(req)); rt.block_on(send_request(req));
}); });
} else { } else {
b.iter(|| { b.iter(|| {
let futs = (0..self.parallel_cnt) let futs = (0..self.parallel_cnt).map(|_| {
.map(|_| {
let req = make_request(); let req = make_request();
send_request(req) send_request(req)
}); });
@@ -353,12 +337,16 @@ fn spawn_server(rt: &mut tokio::runtime::Runtime, opts: &Opts) -> SocketAddr {
.http2_only(opts.http2) .http2_only(opts.http2)
.http2_initial_stream_window_size(opts.http2_stream_window) .http2_initial_stream_window_size(opts.http2_stream_window)
.http2_initial_connection_window_size(opts.http2_conn_window) .http2_initial_connection_window_size(opts.http2_conn_window)
.serve(make_service_fn( move |_| async move { .serve(make_service_fn(move |_| {
Ok::<_, hyper::Error>(service_fn(move |req: Request<Body>| async move { async move {
Ok::<_, hyper::Error>(service_fn(move |req: Request<Body>| {
async move {
let mut req_body = req.into_body(); let mut req_body = req.into_body();
while let Some(_chunk) = req_body.data().await {} while let Some(_chunk) = req_body.data().await {}
Ok::<_, hyper::Error>(Response::new(Body::from(body))) Ok::<_, hyper::Error>(Response::new(Body::from(body)))
}
})) }))
}
})) }))
}); });
let addr = srv.local_addr(); let addr = srv.local_addr();
@@ -367,5 +355,5 @@ fn spawn_server(rt: &mut tokio::runtime::Runtime, opts: &Opts) -> SocketAddr {
panic!("server error: {}", err); panic!("server error: {}", err);
} }
}); });
return addr return addr;
} }

View File

@@ -4,14 +4,14 @@
extern crate test; extern crate test;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::{TcpStream}; use std::net::TcpStream;
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use hyper::{Body, Response, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Response, Server};
const PIPELINED_REQUESTS: usize = 16; const PIPELINED_REQUESTS: usize = 16;
@@ -25,10 +25,12 @@ fn hello_world(b: &mut test::Bencher) {
std::thread::spawn(move || { std::thread::spawn(move || {
let addr = "127.0.0.1:0".parse().unwrap(); let addr = "127.0.0.1:0".parse().unwrap();
let make_svc = make_service_fn(|_| async { let make_svc = make_service_fn(|_| {
Ok::<_, hyper::Error>(service_fn(|_| async { async {
Ok::<_, hyper::Error>(Response::new(Body::from("Hello, World!"))) Ok::<_, hyper::Error>(service_fn(|_| {
async { Ok::<_, hyper::Error>(Response::new(Body::from("Hello, World!"))) }
})) }))
}
}); });
let mut rt = tokio::runtime::Builder::new() let mut rt = tokio::runtime::Builder::new()
@@ -44,8 +46,7 @@ fn hello_world(b: &mut test::Bencher) {
addr_tx.send(srv.local_addr()).unwrap(); addr_tx.send(srv.local_addr()).unwrap();
let graceful = srv let graceful = srv.with_graceful_shutdown(async {
.with_graceful_shutdown(async {
until_rx.await.ok(); until_rx.await.ok();
}); });
@@ -66,7 +67,8 @@ fn hello_world(b: &mut test::Bencher) {
let total_bytes = { let total_bytes = {
let mut tcp = TcpStream::connect(addr).unwrap(); let mut tcp = TcpStream::connect(addr).unwrap();
tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n").unwrap(); tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")
.unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
tcp.read_to_end(&mut buf).unwrap() tcp.read_to_end(&mut buf).unwrap()
} * PIPELINED_REQUESTS; } * PIPELINED_REQUESTS;
@@ -85,4 +87,3 @@ fn hello_world(b: &mut test::Bencher) {
assert_eq!(sum, total_bytes); assert_eq!(sum, total_bytes);
}); });
} }

View File

@@ -11,26 +11,31 @@ use std::time::Duration;
use futures_util::{stream, StreamExt}; use futures_util::{stream, StreamExt};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use hyper::{Body, Response, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Response, Server};
macro_rules! bench_server { macro_rules! bench_server {
($b:ident, $header:expr, $body:expr) => ({ ($b:ident, $header:expr, $body:expr) => {{
let _ = pretty_env_logger::try_init(); let _ = pretty_env_logger::try_init();
let (_until_tx, until_rx) = oneshot::channel::<()>(); let (_until_tx, until_rx) = oneshot::channel::<()>();
let addr = { let addr = {
let (addr_tx, addr_rx) = mpsc::channel(); let (addr_tx, addr_rx) = mpsc::channel();
std::thread::spawn(move || { std::thread::spawn(move || {
let addr = "127.0.0.1:0".parse().unwrap(); let addr = "127.0.0.1:0".parse().unwrap();
let make_svc = make_service_fn(|_| async { let make_svc = make_service_fn(|_| {
Ok::<_, hyper::Error>(service_fn(|_| async { async {
Ok::<_, hyper::Error>(Response::builder() Ok::<_, hyper::Error>(service_fn(|_| {
async {
Ok::<_, hyper::Error>(
Response::builder()
.header($header.0, $header.1) .header($header.0, $header.1)
.header("content-type", "text/plain") .header("content-type", "text/plain")
.body($body()) .body($body())
.unwrap() .unwrap(),
) )
}
})) }))
}
}); });
let mut rt = tokio::runtime::Builder::new() let mut rt = tokio::runtime::Builder::new()
@@ -39,15 +44,11 @@ macro_rules! bench_server {
.build() .build()
.expect("rt build"); .expect("rt build");
let srv = rt.block_on(async move { let srv = rt.block_on(async move { Server::bind(&addr).serve(make_svc) });
Server::bind(&addr)
.serve(make_svc)
});
addr_tx.send(srv.local_addr()).unwrap(); addr_tx.send(srv.local_addr()).unwrap();
let graceful = srv let graceful = srv.with_graceful_shutdown(async {
.with_graceful_shutdown(async {
until_rx.await.ok(); until_rx.await.ok();
}); });
rt.block_on(async move { rt.block_on(async move {
@@ -62,7 +63,8 @@ macro_rules! bench_server {
let total_bytes = { let total_bytes = {
let mut tcp = TcpStream::connect(addr).unwrap(); let mut tcp = TcpStream::connect(addr).unwrap();
tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n").unwrap(); tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")
.unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
tcp.read_to_end(&mut buf).unwrap() tcp.read_to_end(&mut buf).unwrap()
}; };
@@ -73,14 +75,15 @@ macro_rules! bench_server {
$b.bytes = 35 + total_bytes as u64; $b.bytes = 35 + total_bytes as u64;
$b.iter(|| { $b.iter(|| {
tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap(); tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
.unwrap();
let mut sum = 0; let mut sum = 0;
while sum < total_bytes { while sum < total_bytes {
sum += tcp.read(&mut buf).unwrap(); sum += tcp.read(&mut buf).unwrap();
} }
assert_eq!(sum, total_bytes); assert_eq!(sum, total_bytes);
}); });
}) }};
} }
fn body(b: &'static [u8]) -> hyper::Body { fn body(b: &'static [u8]) -> hyper::Body {
@@ -94,7 +97,9 @@ fn throughput_fixedsize_small_payload(b: &mut test::Bencher) {
#[bench] #[bench]
fn throughput_fixedsize_large_payload(b: &mut test::Bencher) { fn throughput_fixedsize_large_payload(b: &mut test::Bencher) {
bench_server!(b, ("content-length", "1000000"), || body(&[b'x'; 1_000_000])) bench_server!(b, ("content-length", "1000000"), || body(
&[b'x'; 1_000_000]
))
} }
#[bench] #[bench]
@@ -107,12 +112,16 @@ fn throughput_fixedsize_many_chunks(b: &mut test::Bencher) {
#[bench] #[bench]
fn throughput_chunked_small_payload(b: &mut test::Bencher) { fn throughput_chunked_small_payload(b: &mut test::Bencher) {
bench_server!(b, ("transfer-encoding", "chunked"), || body(b"Hello, World!")) bench_server!(b, ("transfer-encoding", "chunked"), || body(
b"Hello, World!"
))
} }
#[bench] #[bench]
fn throughput_chunked_large_payload(b: &mut test::Bencher) { fn throughput_chunked_large_payload(b: &mut test::Bencher) {
bench_server!(b, ("transfer-encoding", "chunked"), || body(&[b'x'; 1_000_000])) bench_server!(b, ("transfer-encoding", "chunked"), || body(
&[b'x'; 1_000_000]
))
} }
#[bench] #[bench]
@@ -134,14 +143,17 @@ fn raw_tcp_throughput_small_payload(b: &mut test::Bencher) {
let mut buf = [0u8; 8192]; let mut buf = [0u8; 8192];
while rx.try_recv().is_err() { while rx.try_recv().is_err() {
sock.read(&mut buf).unwrap(); sock.read(&mut buf).unwrap();
sock.write_all(b"\ sock.write_all(
b"\
HTTP/1.1 200 OK\r\n\ HTTP/1.1 200 OK\r\n\
Content-Length: 13\r\n\ Content-Length: 13\r\n\
Content-Type: text/plain; charset=utf-8\r\n\ Content-Type: text/plain; charset=utf-8\r\n\
Date: Fri, 12 May 2017 18:21:45 GMT\r\n\ Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
\r\n\ \r\n\
Hello, World!\ Hello, World!\
").unwrap(); ",
)
.unwrap();
} }
}); });
@@ -150,7 +162,8 @@ fn raw_tcp_throughput_small_payload(b: &mut test::Bencher) {
b.bytes = 130 + 35; b.bytes = 130 + 35;
b.iter(|| { b.iter(|| {
tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap(); tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
.unwrap();
let n = tcp.read(&mut buf).unwrap(); let n = tcp.read(&mut buf).unwrap();
assert_eq!(n, 130); assert_eq!(n, 130);
}); });
@@ -191,7 +204,8 @@ fn raw_tcp_throughput_large_payload(b: &mut test::Bencher) {
b.bytes = expect_read as u64 + 35; b.bytes = expect_read as u64 + 35;
b.iter(|| { b.iter(|| {
tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap(); tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
.unwrap();
let mut sum = 0; let mut sum = 0;
while sum < expect_read { while sum < expect_read {
sum += tcp.read(&mut buf).unwrap(); sum += tcp.read(&mut buf).unwrap();

View File

@@ -2,7 +2,7 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use std::env; use std::env;
use hyper::{Client, body::HttpBody as _}; use hyper::{body::HttpBody as _, Client};
use tokio::io::{self, AsyncWriteExt as _}; use tokio::io::{self, AsyncWriteExt as _};
// A simple type alias so as to DRY. // A simple type alias so as to DRY.

View File

@@ -4,8 +4,8 @@
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
use hyper::Client;
use futures_util::StreamExt; use futures_util::StreamExt;
use hyper::Client;
// A simple type alias so as to DRY. // A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

View File

@@ -1,22 +1,20 @@
//#![deny(warnings)] //#![deny(warnings)]
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use hyper::service::{make_service_fn, service_fn};
use futures_util::{StreamExt, TryStreamExt}; use futures_util::{StreamExt, TryStreamExt};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
/// This is our service handler. It receives a Request, routes on its /// This is our service handler. It receives a Request, routes on its
/// path, and returns a Future of a Response. /// path, and returns a Future of a Response.
async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> { async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
match (req.method(), req.uri().path()) { match (req.method(), req.uri().path()) {
// Serve some instructions at / // Serve some instructions at /
(&Method::GET, "/") => { (&Method::GET, "/") => Ok(Response::new(Body::from(
Ok(Response::new(Body::from("Try POSTing data to /echo such as: `curl localhost:3000/echo -XPOST -d 'hello world'`"))) "Try POSTing data to /echo such as: `curl localhost:3000/echo -XPOST -d 'hello world'`",
} ))),
// Simply echo the body back to the client. // Simply echo the body back to the client.
(&Method::POST, "/echo") => { (&Method::POST, "/echo") => Ok(Response::new(req.into_body())),
Ok(Response::new(req.into_body()))
}
// Convert to uppercase before sending back to client using a stream. // Convert to uppercase before sending back to client using a stream.
(&Method::POST, "/echo/uppercase") => { (&Method::POST, "/echo/uppercase") => {
@@ -41,11 +39,7 @@ async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
whole_body.extend_from_slice(&chunk?); whole_body.extend_from_slice(&chunk?);
} }
let reversed_body = whole_body let reversed_body = whole_body.iter().rev().cloned().collect::<Vec<u8>>();
.iter()
.rev()
.cloned()
.collect::<Vec<u8>>();
Ok(Response::new(Body::from(reversed_body))) Ok(Response::new(Body::from(reversed_body)))
} }
@@ -58,19 +52,13 @@ async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
} }
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = ([127, 0, 0, 1], 3000).into(); let addr = ([127, 0, 0, 1], 3000).into();
let service = make_service_fn(|_| { let service = make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(echo)) });
async {
Ok::<_, hyper::Error>(service_fn(echo))
}
});
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(service);
.serve(service);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);

View File

@@ -2,8 +2,8 @@
use std::convert::Infallible; use std::convert::Infallible;
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> { async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from("Hello World!"))) Ok(Response::new(Body::from("Hello World!")))
@@ -19,9 +19,7 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// This is the `Service` that will handle the connection. // This is the `Service` that will handle the connection.
// `service_fn` is a helper to convert a function that // `service_fn` is a helper to convert a function that
// returns a Response into a `Service`. // returns a Response into a `Service`.
async { async { Ok::<_, Infallible>(service_fn(hello)) }
Ok::<_, Infallible>(service_fn(hello))
}
}); });
let addr = ([127, 0, 0, 1], 3000).into(); let addr = ([127, 0, 0, 1], 3000).into();

View File

@@ -1,9 +1,9 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use hyper::{Body, Request, Response, Server};
use hyper::service::{service_fn, make_service_fn};
use futures_util::future::join; use futures_util::future::join;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
static INDEX1: &'static [u8] = b"The 1st service!"; static INDEX1: &'static [u8] = b"The 1st service!";
static INDEX2: &'static [u8] = b"The 2nd service!"; static INDEX2: &'static [u8] = b"The 2nd service!";
@@ -23,18 +23,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr1 = ([127, 0, 0, 1], 1337).into(); let addr1 = ([127, 0, 0, 1], 1337).into();
let addr2 = ([127, 0, 0, 1], 1338).into(); let addr2 = ([127, 0, 0, 1], 1338).into();
let srv1 = Server::bind(&addr1) let srv1 = Server::bind(&addr1).serve(make_service_fn(|_| {
.serve(make_service_fn(|_| { async { Ok::<_, hyper::Error>(service_fn(index1)) }
async {
Ok::<_, hyper::Error>(service_fn(index1))
}
})); }));
let srv2 = Server::bind(&addr2) let srv2 = Server::bind(&addr2).serve(make_service_fn(|_| {
.serve(make_service_fn(|_| { async { Ok::<_, hyper::Error>(service_fn(index2)) }
async {
Ok::<_, hyper::Error>(service_fn(index2))
}
})); }));
println!("Listening on http://{} and http://{}", addr1, addr2); println!("Listening on http://{} and http://{}", addr1, addr2);

View File

@@ -1,12 +1,12 @@
// #![deny(warnings)] // FIXME: https://github.com/rust-lang/rust/issues/62411 // #![deny(warnings)] // FIXME: https://github.com/rust-lang/rust/issues/62411
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode}; use hyper::{Body, Method, Request, Response, Server, StatusCode};
use hyper::service::{service_fn, make_service_fn};
use futures_util::StreamExt;
use std::collections::HashMap; use std::collections::HashMap;
use url::form_urlencoded; use url::form_urlencoded;
use futures_util::StreamExt;
static INDEX: &[u8] = b"<html><body><form action=\"post\" method=\"post\">Name: <input type=\"text\" name=\"name\"><br>Number: <input type=\"text\" name=\"number\"><br><input type=\"submit\"></body></html>"; static INDEX: &[u8] = b"<html><body><form action=\"post\" method=\"post\">Name: <input type=\"text\" name=\"name\"><br>Number: <input type=\"text\" name=\"number\"><br><input type=\"submit\"></body></html>";
static MISSING: &[u8] = b"Missing field"; static MISSING: &[u8] = b"Missing field";
@@ -15,9 +15,7 @@ static NOTNUMERIC: &[u8] = b"Number field is not numeric";
// Using service_fn, we can turn this function into a `Service`. // Using service_fn, we can turn this function into a `Service`.
async fn param_example(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> { async fn param_example(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
match (req.method(), req.uri().path()) { match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/post") => { (&Method::GET, "/") | (&Method::GET, "/post") => Ok(Response::new(INDEX.into())),
Ok(Response::new(INDEX.into()))
},
(&Method::POST, "/post") => { (&Method::POST, "/post") => {
// Concatenate the body... // Concatenate the body...
let mut b = Vec::new(); let mut b = Vec::new();
@@ -35,7 +33,9 @@ async fn param_example(mut req: Request<Body>) -> Result<Response<Body>, hyper::
// form, and the values should be rolled up into a // form, and the values should be rolled up into a
// HashMap<String, Vec<String>>. However in this // HashMap<String, Vec<String>>. However in this
// example the simpler approach is sufficient. // example the simpler approach is sufficient.
let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::<HashMap<String, String>>(); let params = form_urlencoded::parse(b.as_ref())
.into_owned()
.collect::<HashMap<String, String>>();
// Validate the request parameters, returning // Validate the request parameters, returning
// early if an invalid input is detected. // early if an invalid input is detected.
@@ -71,13 +71,11 @@ async fn param_example(mut req: Request<Body>) -> Result<Response<Body>, hyper::
// needed here, too. // needed here, too.
let body = format!("Hello {}, your number is {}", name, number); let body = format!("Hello {}, your number is {}", name, number);
Ok(Response::new(body.into())) Ok(Response::new(body.into()))
}, }
_ => { _ => Ok(Response::builder()
Ok(Response::builder()
.status(StatusCode::NOT_FOUND) .status(StatusCode::NOT_FOUND)
.body(Body::empty()) .body(Body::empty())
.unwrap()) .unwrap()),
}
} }
} }
@@ -87,11 +85,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = ([127, 0, 0, 1], 1337).into(); let addr = ([127, 0, 0, 1], 1337).into();
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(make_service_fn(|_| {
.serve(make_service_fn(|_| { async { Ok::<_, hyper::Error>(service_fn(param_example)) }
async {
Ok::<_, hyper::Error>(service_fn(param_example))
}
})); }));
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);

View File

@@ -1,7 +1,7 @@
#![deny(warnings)] #![deny(warnings)]
use hyper::{Client, Error, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Client, Error, Server};
use std::net::SocketAddr; use std::net::SocketAddr;
#[tokio::main] #[tokio::main]
@@ -25,9 +25,11 @@ async fn main() {
// `service_fn` is a helper to convert a function that // `service_fn` is a helper to convert a function that
// returns a Response into a `Service`. // returns a Response into a `Service`.
Ok::<_, Error>(service_fn(move |mut req| { Ok::<_, Error>(service_fn(move |mut req| {
let uri_string = format!("http://{}/{}", let uri_string = format!(
"http://{}/{}",
out_addr_clone, out_addr_clone,
req.uri().path_and_query().map(|x| x.as_str()).unwrap_or("")); req.uri().path_and_query().map(|x| x.as_str()).unwrap_or("")
);
let uri = uri_string.parse().unwrap(); let uri = uri_string.parse().unwrap();
*req.uri_mut() = uri; *req.uri_mut() = uri;
client.request(req) client.request(req)
@@ -35,8 +37,7 @@ async fn main() {
} }
}); });
let server = Server::bind(&in_addr) let server = Server::bind(&in_addr).serve(make_service);
.serve(make_service);
println!("Listening on http://{}", in_addr); println!("Listening on http://{}", in_addr);
println!("Proxying on http://{}", out_addr); println!("Proxying on http://{}", out_addr);

View File

@@ -1,10 +1,10 @@
#![deny(warnings)] #![deny(warnings)]
use tokio::io::AsyncReadExt;
use tokio::fs::File; use tokio::fs::File;
use tokio::io::AsyncReadExt;
use hyper::{Body, Method, Result, Request, Response, Server, StatusCode};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Result, Server, StatusCode};
static INDEX: &str = "examples/send_file_index.html"; static INDEX: &str = "examples/send_file_index.html";
static INTERNAL_SERVER_ERROR: &[u8] = b"Internal Server Error"; static INTERNAL_SERVER_ERROR: &[u8] = b"Internal Server Error";
@@ -16,12 +16,10 @@ async fn main() {
let addr = "127.0.0.1:1337".parse().unwrap(); let addr = "127.0.0.1:1337".parse().unwrap();
let make_service = make_service_fn(|_| async { let make_service =
Ok::<_, hyper::Error>(service_fn(response_examples)) make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(response_examples)) });
});
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(make_service);
.serve(make_service);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);
@@ -32,16 +30,14 @@ async fn main() {
async fn response_examples(req: Request<Body>) -> Result<Response<Body>> { async fn response_examples(req: Request<Body>) -> Result<Response<Body>> {
match (req.method(), req.uri().path()) { match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/") | (&Method::GET, "/index.html") | (&Method::GET, "/big_file.html") => {
(&Method::GET, "/index.html") |
(&Method::GET, "/big_file.html") => {
simple_file_send(INDEX).await simple_file_send(INDEX).await
} }
(&Method::GET, "/no_file.html") => { (&Method::GET, "/no_file.html") => {
// Test what happens when file cannot be be found // Test what happens when file cannot be be found
simple_file_send("this_file_should_not_exist.html").await simple_file_send("this_file_should_not_exist.html").await
} }
_ => Ok(not_found()) _ => Ok(not_found()),
} }
} }

View File

@@ -3,8 +3,8 @@
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use hyper::{Body, Error, Response, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Error, Response, Server};
fn main() { fn main() {
pretty_env_logger::init(); pretty_env_logger::init();
@@ -22,7 +22,6 @@ fn main() {
} }
async fn run() { async fn run() {
let addr = ([127, 0, 0, 1], 3000).into(); let addr = ([127, 0, 0, 1], 3000).into();
// Using a !Send request counter is fine on 1 thread... // Using a !Send request counter is fine on 1 thread...
@@ -37,18 +36,12 @@ async fn run() {
let prev = cnt.get(); let prev = cnt.get();
cnt.set(prev + 1); cnt.set(prev + 1);
let value = cnt.get(); let value = cnt.get();
async move { async move { Ok::<_, Error>(Response::new(Body::from(format!("Request #{}", value)))) }
Ok::<_, Error>(Response::new(Body::from(
format!("Request #{}", value)
)))
}
})) }))
} }
}); });
let server = Server::bind(&addr) let server = Server::bind(&addr).executor(LocalExec).serve(make_service);
.executor(LocalExec)
.serve(make_service);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);

View File

@@ -1,9 +1,12 @@
#![deny(warnings)] #![deny(warnings)]
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}}; use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
use hyper::{Body, Error, Response, Server};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Error, Response, Server};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@@ -34,17 +37,12 @@ async fn main() {
// Get the current count, and also increment by 1, in a single // Get the current count, and also increment by 1, in a single
// atomic operation. // atomic operation.
let count = counter.fetch_add(1, Ordering::AcqRel); let count = counter.fetch_add(1, Ordering::AcqRel);
async move { async move { Ok::<_, Error>(Response::new(Body::from(format!("Request #{}", count)))) }
Ok::<_, Error>(
Response::new(Body::from(format!("Request #{}", count)))
)
}
})) }))
} }
}); });
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(make_service);
.serve(make_service);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);
@@ -52,4 +50,3 @@ async fn main() {
eprintln!("server error: {}", e); eprintln!("server error: {}", e);
} }
} }

View File

@@ -1,8 +1,8 @@
#![deny(warnings)] #![deny(warnings)]
use hyper::client::service::Connect;
use hyper::client::conn::Builder; use hyper::client::conn::Builder;
use hyper::client::connect::HttpConnector; use hyper::client::connect::HttpConnector;
use hyper::client::service::Connect;
use hyper::service::Service; use hyper::service::Service;
use hyper::{Body, Request}; use hyper::{Body, Request};
@@ -14,7 +14,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let uri = "http://127.0.0.1:8080".parse::<http::Uri>()?; let uri = "http://127.0.0.1:8080".parse::<http::Uri>()?;
let mut svc = mk_svc.call(uri.clone()).await?; let mut svc = mk_svc.call(uri.clone()).await?;
let body = Body::empty(); let body = Body::empty();

View File

@@ -3,8 +3,8 @@
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use futures_util::future; use futures_util::future;
use hyper::{Body, Request, Response, Server};
use hyper::service::Service; use hyper::service::Service;
use hyper::{Body, Request, Response, Server};
const ROOT: &'static str = "/"; const ROOT: &'static str = "/";
@@ -58,9 +58,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "127.0.0.1:1337".parse().unwrap(); let addr = "127.0.0.1:1337".parse().unwrap();
let server = Server::bind(&addr).serve(MakeSvc);
let server = Server::bind(&addr)
.serve(MakeSvc);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);

View File

@@ -3,13 +3,13 @@
// Note: `hyper::upgrade` docs link to this upgrade. // Note: `hyper::upgrade` docs link to this upgrade.
use std::str; use std::str;
use tokio::sync::oneshot;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::sync::oneshot;
use hyper::{Body, Client, Request, Response, Server, StatusCode}; use hyper::header::{HeaderValue, UPGRADE};
use hyper::header::{UPGRADE, HeaderValue};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::upgrade::Upgraded; use hyper::upgrade::Upgraded;
use hyper::{Body, Client, Request, Response, Server, StatusCode};
use std::net::SocketAddr; use std::net::SocketAddr;
// A simple type alias so as to DRY. // A simple type alias so as to DRY.
@@ -58,14 +58,15 @@ async fn server_upgrade(req: Request<Body>) -> Result<Response<Body>> {
eprintln!("server foobar io error: {}", e) eprintln!("server foobar io error: {}", e)
}; };
} }
Err(e) => eprintln!("upgrade error: {}", e) Err(e) => eprintln!("upgrade error: {}", e),
} }
}); });
// Now return a 101 Response saying we agree to the upgrade to some // Now return a 101 Response saying we agree to the upgrade to some
// made-up 'foobar' protocol. // made-up 'foobar' protocol.
*res.status_mut() = StatusCode::SWITCHING_PROTOCOLS; *res.status_mut() = StatusCode::SWITCHING_PROTOCOLS;
res.headers_mut().insert(UPGRADE, HeaderValue::from_static("foobar")); res.headers_mut()
.insert(UPGRADE, HeaderValue::from_static("foobar"));
Ok(res) Ok(res)
} }
@@ -102,7 +103,7 @@ async fn client_upgrade_request(addr: SocketAddr) -> Result<()> {
eprintln!("client foobar io error: {}", e) eprintln!("client foobar io error: {}", e)
}; };
} }
Err(e) => eprintln!("upgrade error: {}", e) Err(e) => eprintln!("upgrade error: {}", e),
} }
Ok(()) Ok(())
@@ -115,12 +116,10 @@ async fn main() {
// unused port. // unused port.
let addr = ([127, 0, 0, 1], 0).into(); let addr = ([127, 0, 0, 1], 0).into();
let make_service = make_service_fn(|_| async { let make_service =
Ok::<_, hyper::Error>(service_fn(server_upgrade)) make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(server_upgrade)) });
});
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(make_service);
.serve(make_service);
// We need the assigned address for the client to send it messages. // We need the assigned address for the client to send it messages.
let addr = server.local_addr(); let addr = server.local_addr();
@@ -128,8 +127,7 @@ async fn main() {
// For this example, a oneshot is used to signal that after 1 request, // For this example, a oneshot is used to signal that after 1 request,
// the server should be shutdown. // the server should be shutdown.
let (tx, rx) = oneshot::channel::<()>(); let (tx, rx) = oneshot::channel::<()>();
let server = server let server = server.with_graceful_shutdown(async move {
.with_graceful_shutdown(async move {
rx.await.ok(); rx.await.ok();
}); });

View File

@@ -1,9 +1,9 @@
#![deny(warnings)] #![deny(warnings)]
use hyper::{Body, Chunk, Client, Method, Request, Response, Server, StatusCode, header}; use futures_util::{StreamExt, TryStreamExt};
use hyper::client::HttpConnector; use hyper::client::HttpConnector;
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use futures_util::{StreamExt, TryStreamExt}; use hyper::{header, Body, Chunk, Client, Method, Request, Response, Server, StatusCode};
type GenericError = Box<dyn std::error::Error + Send + Sync>; type GenericError = Box<dyn std::error::Error + Send + Sync>;
type Result<T> = std::result::Result<T, GenericError>; type Result<T> = std::result::Result<T, GenericError>;
@@ -14,9 +14,7 @@ static NOTFOUND: &[u8] = b"Not Found";
static POST_DATA: &str = r#"{"original": "data"}"#; static POST_DATA: &str = r#"{"original": "data"}"#;
static URL: &str = "http://127.0.0.1:1337/json_api"; static URL: &str = "http://127.0.0.1:1337/json_api";
async fn client_request_response( async fn client_request_response(client: &Client<HttpConnector>) -> Result<Response<Body>> {
client: &Client<HttpConnector>
) -> Result<Response<Body>> {
let req = Request::builder() let req = Request::builder()
.method(Method::POST) .method(Method::POST)
.uri(URL) .uri(URL)
@@ -27,9 +25,11 @@ async fn client_request_response(
let web_res = client.request(req).await?; let web_res = client.request(req).await?;
// Compare the JSON we sent (before) with what we received (after): // Compare the JSON we sent (before) with what we received (after):
let body = Body::wrap_stream(web_res.into_body().map_ok(|b| { let body = Body::wrap_stream(web_res.into_body().map_ok(|b| {
Chunk::from(format!("<b>POST request body</b>: {}<br><b>Response</b>: {}", Chunk::from(format!(
"<b>POST request body</b>: {}<br><b>Response</b>: {}",
POST_DATA, POST_DATA,
std::str::from_utf8(&b).unwrap())) std::str::from_utf8(&b).unwrap()
))
})); }));
Ok(Response::new(body)) Ok(Response::new(body))
@@ -57,40 +57,27 @@ async fn api_post_response(mut req: Request<Body>) -> Result<Response<Body>> {
async fn api_get_response() -> Result<Response<Body>> { async fn api_get_response() -> Result<Response<Body>> {
let data = vec!["foo", "bar"]; let data = vec!["foo", "bar"];
let res = match serde_json::to_string(&data) { let res = match serde_json::to_string(&data) {
Ok(json) => { Ok(json) => Response::builder()
Response::builder()
.header(header::CONTENT_TYPE, "application/json") .header(header::CONTENT_TYPE, "application/json")
.body(Body::from(json)) .body(Body::from(json))
.unwrap() .unwrap(),
} Err(_) => Response::builder()
Err(_) => {
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR) .status(StatusCode::INTERNAL_SERVER_ERROR)
.body(INTERNAL_SERVER_ERROR.into()) .body(INTERNAL_SERVER_ERROR.into())
.unwrap() .unwrap(),
}
}; };
Ok(res) Ok(res)
} }
async fn response_examples( async fn response_examples(
req: Request<Body>, req: Request<Body>,
client: Client<HttpConnector> client: Client<HttpConnector>,
) -> Result<Response<Body>> { ) -> Result<Response<Body>> {
match (req.method(), req.uri().path()) { match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/") | (&Method::GET, "/index.html") => Ok(Response::new(INDEX.into())),
(&Method::GET, "/index.html") => { (&Method::GET, "/test.html") => client_request_response(&client).await,
Ok(Response::new(INDEX.into())) (&Method::POST, "/json_api") => api_post_response(req).await,
}, (&Method::GET, "/json_api") => api_get_response().await,
(&Method::GET, "/test.html") => {
client_request_response(&client).await
},
(&Method::POST, "/json_api") => {
api_post_response(req).await
},
(&Method::GET, "/json_api") => {
api_get_response().await
}
_ => { _ => {
// Return 404 not found response. // Return 404 not found response.
Ok(Response::builder() Ok(Response::builder()
@@ -121,8 +108,7 @@ async fn main() -> Result<()> {
} }
}); });
let server = Server::bind(&addr) let server = Server::bind(&addr).serve(new_service);
.serve(new_service);
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);

View File

@@ -4,15 +4,15 @@ use std::error::Error as StdError;
use std::fmt; use std::fmt;
use bytes::Bytes; use bytes::Bytes;
use futures_core::Stream; // for mpsc::Receiver
use futures_channel::{mpsc, oneshot}; use futures_channel::{mpsc, oneshot};
use futures_core::Stream; // for mpsc::Receiver
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
use futures_util::TryStreamExt; use futures_util::TryStreamExt;
use http_body::{SizeHint, Body as HttpBody};
use http::HeaderMap; use http::HeaderMap;
use http_body::{Body as HttpBody, SizeHint};
use crate::common::{Future, Never, Pin, Poll, task};
use super::Chunk; use super::Chunk;
use crate::common::{task, Future, Never, Pin, Poll};
use crate::upgrade::OnUpgrade; use crate::upgrade::OnUpgrade;
type BodySender = mpsc::Sender<Result<Chunk, crate::Error>>; type BodySender = mpsc::Sender<Result<Chunk, crate::Error>>;
@@ -44,7 +44,9 @@ enum Kind {
// //
// See https://github.com/rust-lang/rust/issues/57017 // See https://github.com/rust-lang/rust/issues/57017
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
Wrapped(Pin<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>), Wrapped(
Pin<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>,
),
} }
struct Extra { struct Extra {
@@ -161,8 +163,7 @@ impl Body {
/// ///
/// See [the `upgrade` module](::upgrade) for more. /// See [the `upgrade` module](::upgrade) for more.
pub fn on_upgrade(self) -> OnUpgrade { pub fn on_upgrade(self) -> OnUpgrade {
self self.extra
.extra
.map(|ex| ex.on_upgrade) .map(|ex| ex.on_upgrade)
.unwrap_or_else(OnUpgrade::none) .unwrap_or_else(OnUpgrade::none)
} }
@@ -193,54 +194,44 @@ impl Body {
} }
fn take_delayed_eof(&mut self) -> Option<DelayEof> { fn take_delayed_eof(&mut self) -> Option<DelayEof> {
self self.extra
.extra
.as_mut() .as_mut()
.and_then(|extra| extra.delayed_eof.take()) .and_then(|extra| extra.delayed_eof.take())
} }
fn extra_mut(&mut self) -> &mut Extra { fn extra_mut(&mut self) -> &mut Extra {
self self.extra.get_or_insert_with(|| {
.extra Box::new(Extra {
.get_or_insert_with(|| Box::new(Extra {
delayed_eof: None, delayed_eof: None,
on_upgrade: OnUpgrade::none(), on_upgrade: OnUpgrade::none(),
})) })
})
} }
fn poll_eof(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Chunk>>> { fn poll_eof(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Chunk>>> {
match self.take_delayed_eof() { match self.take_delayed_eof() {
Some(DelayEof::NotEof(mut delay)) => { Some(DelayEof::NotEof(mut delay)) => match self.poll_inner(cx) {
match self.poll_inner(cx) { ok @ Poll::Ready(Some(Ok(..))) | ok @ Poll::Pending => {
ok @ Poll::Ready(Some(Ok(..))) |
ok @ Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay));
ok ok
}, }
Poll::Ready(None) => match Pin::new(&mut delay).poll(cx) { Poll::Ready(None) => match Pin::new(&mut delay).poll(cx) {
Poll::Ready(Ok(never)) => match never {}, Poll::Ready(Ok(never)) => match never {},
Poll::Pending => { Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
Poll::Pending Poll::Pending
}, }
Poll::Ready(Err(_done)) => { Poll::Ready(Err(_done)) => Poll::Ready(None),
Poll::Ready(None)
},
}, },
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
}
}, },
Some(DelayEof::Eof(mut delay)) => { Some(DelayEof::Eof(mut delay)) => match Pin::new(&mut delay).poll(cx) {
match Pin::new(&mut delay).poll(cx) {
Poll::Ready(Ok(never)) => match never {}, Poll::Ready(Ok(never)) => match never {},
Poll::Pending => { Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
Poll::Pending Poll::Pending
},
Poll::Ready(Err(_done)) => {
Poll::Ready(None)
},
} }
Poll::Ready(Err(_done)) => Poll::Ready(None),
}, },
None => self.poll_inner(cx), None => self.poll_inner(cx),
} }
@@ -268,25 +259,23 @@ impl Body {
} }
None => Poll::Ready(None), None => Poll::Ready(None),
} }
}, }
Kind::H2 { Kind::H2 {
recv: ref mut h2, .. recv: ref mut h2, ..
} => match ready!(h2.poll_data(cx)) { } => match ready!(h2.poll_data(cx)) {
Some(Ok(bytes)) => { Some(Ok(bytes)) => {
let _ = h2.flow_control().release_capacity(bytes.len()); let _ = h2.flow_control().release_capacity(bytes.len());
Poll::Ready(Some(Ok(Chunk::from(bytes)))) Poll::Ready(Some(Ok(Chunk::from(bytes))))
}, }
Some(Err(e)) => Poll::Ready(Some(Err(crate::Error::new_body(e)))), Some(Err(e)) => Poll::Ready(Some(Err(crate::Error::new_body(e)))),
None => Poll::Ready(None), None => Poll::Ready(None),
}, },
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
Kind::Wrapped(ref mut s) => { Kind::Wrapped(ref mut s) => match ready!(s.as_mut().poll_next(cx)) {
match ready!(s.as_mut().poll_next(cx)) {
Some(res) => Poll::Ready(Some(res.map_err(crate::Error::new_body))), Some(res) => Poll::Ready(Some(res.map_err(crate::Error::new_body))),
None => Poll::Ready(None), None => Poll::Ready(None),
} },
}
} }
} }
@@ -311,13 +300,21 @@ impl HttpBody for Body {
type Data = Chunk; type Data = Chunk;
type Error = crate::Error; type Error = crate::Error;
fn poll_data(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> { fn poll_data(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
self.poll_eof(cx) self.poll_eof(cx)
} }
fn poll_trailers(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { fn poll_trailers(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
match self.kind { match self.kind {
Kind::H2 { recv: ref mut h2, .. } => match ready!(h2.poll_trailers(cx)) { Kind::H2 {
recv: ref mut h2, ..
} => match ready!(h2.poll_trailers(cx)) {
Ok(t) => Poll::Ready(Ok(t)), Ok(t) => Poll::Ready(Ok(t)),
Err(e) => Poll::Ready(Err(crate::Error::new_h2(e))), Err(e) => Poll::Ready(Err(crate::Error::new_h2(e))),
}, },
@@ -341,10 +338,8 @@ impl HttpBody for Body {
let mut hint = SizeHint::default(); let mut hint = SizeHint::default();
hint.set_exact(val.len() as u64); hint.set_exact(val.len() as u64);
hint hint
}, }
Kind::Once(None) => { Kind::Once(None) => SizeHint::default(),
SizeHint::default()
},
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
Kind::Wrapped(..) => SizeHint::default(), Kind::Wrapped(..) => SizeHint::default(),
Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => { Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => {
@@ -355,7 +350,7 @@ impl HttpBody for Body {
} }
hint hint
}, }
} }
} }
} }
@@ -393,14 +388,12 @@ impl Stream for Body {
} }
} }
/// # Optional /// # Optional
/// ///
/// This function requires enabling the `stream` feature in your /// This function requires enabling the `stream` feature in your
/// `Cargo.toml`. /// `Cargo.toml`.
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
impl impl From<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>
From<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>
for Body for Body
{ {
#[inline] #[inline]
@@ -487,13 +480,17 @@ impl Sender {
Poll::Pending => (), // fallthrough Poll::Pending => (), // fallthrough
} }
self.tx.poll_ready(cx).map_err(|_| crate::Error::new_closed()) self.tx
.poll_ready(cx)
.map_err(|_| crate::Error::new_closed())
} }
/// Send data on this channel when it is ready. /// Send data on this channel when it is ready.
pub async fn send_data(&mut self, chunk: Chunk) -> crate::Result<()> { pub async fn send_data(&mut self, chunk: Chunk) -> crate::Result<()> {
futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await?; futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await?;
self.tx.try_send(Ok(chunk)).map_err(|_| crate::Error::new_closed()) self.tx
.try_send(Ok(chunk))
.map_err(|_| crate::Error::new_closed())
} }
/// Try to send data on this channel. /// Try to send data on this channel.

View File

@@ -19,7 +19,6 @@ pub struct IntoIter {
inner: <Bytes as IntoIterator>::IntoIter, inner: <Bytes as IntoIterator>::IntoIter,
} }
impl Chunk { impl Chunk {
/// Converts this `Chunk` directly into the `Bytes` type without copies. /// Converts this `Chunk` directly into the `Bytes` type without copies.
/// ///
@@ -82,9 +81,7 @@ impl From<&'static str> for Chunk {
impl From<Bytes> for Chunk { impl From<Bytes> for Chunk {
#[inline] #[inline]
fn from(bytes: Bytes) -> Chunk { fn from(bytes: Bytes) -> Chunk {
Chunk { Chunk { bytes: bytes }
bytes: bytes,
}
} }
} }
@@ -176,4 +173,3 @@ mod tests {
}) })
} }
} }

View File

@@ -59,4 +59,3 @@ fn _assert_send_sync() {
_assert_send::<Chunk>(); _assert_send::<Chunk>();
_assert_sync::<Chunk>(); _assert_sync::<Chunk>();
} }

View File

@@ -3,7 +3,7 @@ use std::error::Error as StdError;
use bytes::Buf; use bytes::Buf;
use http::HeaderMap; use http::HeaderMap;
use crate::common::{Pin, Poll, task}; use crate::common::{task, Pin, Poll};
use http_body::{Body as HttpBody, SizeHint}; use http_body::{Body as HttpBody, SizeHint};
/// This trait represents a streaming body of a `Request` or `Response`. /// This trait represents a streaming body of a `Request` or `Response`.
@@ -21,14 +21,20 @@ pub trait Payload: sealed::Sealed + Send + 'static {
/// ///
/// Similar to `Stream::poll_next`, this yields `Some(Data)` until /// Similar to `Stream::poll_next`, this yields `Some(Data)` until
/// the body ends, when it yields `None`. /// the body ends, when it yields `None`.
fn poll_data(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>>; fn poll_data(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>>;
/// Poll for an optional **single** `HeaderMap` of trailers. /// Poll for an optional **single** `HeaderMap` of trailers.
/// ///
/// This should **only** be called after `poll_data` has ended. /// This should **only** be called after `poll_data` has ended.
/// ///
/// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2.
fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
drop(cx); drop(cx);
Poll::Ready(Ok(None)) Poll::Ready(Ok(None))
} }
@@ -61,7 +67,6 @@ pub trait Payload: sealed::Sealed + Send + 'static {
} }
} }
impl<T> Payload for T impl<T> Payload for T
where where
T: HttpBody + Send + 'static, T: HttpBody + Send + 'static,
@@ -71,11 +76,17 @@ where
type Data = T::Data; type Data = T::Data;
type Error = T::Error; type Error = T::Error;
fn poll_data(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> { fn poll_data(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
HttpBody::poll_data(self, cx) HttpBody::poll_data(self, cx)
} }
fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
HttpBody::poll_trailers(self, cx) HttpBody::poll_trailers(self, cx)
} }
@@ -127,5 +138,3 @@ impl<E: Payload> Payload for Box<E> {
} }
} }
*/ */

View File

@@ -17,19 +17,14 @@ use pin_project::{pin_project, project};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use tower_service::Service; use tower_service::Service;
use crate::body::Payload;
use crate::common::{BoxSendFuture, Exec, Executor, Future, Pin, Poll, task};
use crate::upgrade::Upgraded;
use crate::proto;
use super::dispatch; use super::dispatch;
use crate::body::Payload;
use crate::common::{task, BoxSendFuture, Exec, Executor, Future, Pin, Poll};
use crate::proto;
use crate::upgrade::Upgraded;
use crate::{Body, Request, Response}; use crate::{Body, Request, Response};
type Http1Dispatcher<T, B, R> = proto::dispatch::Dispatcher< type Http1Dispatcher<T, B, R> = proto::dispatch::Dispatcher<proto::dispatch::Client<B>, B, T, R>;
proto::dispatch::Client<B>,
B,
T,
R,
>;
#[pin_project] #[pin_project]
enum ProtoClient<T, B> enum ProtoClient<T, B>
@@ -46,18 +41,16 @@ where
const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb
const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb
/// Returns a handshake future over some IO. /// Returns a handshake future over some IO.
/// ///
/// This is a shortcut for `Builder::new().handshake(io)`. /// This is a shortcut for `Builder::new().handshake(io)`.
pub async fn handshake<T>(io: T) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)> pub async fn handshake<T>(
io: T,
) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)>
where where
T: AsyncRead + AsyncWrite + Unpin + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{ {
Builder::new() Builder::new().handshake(io).await
.handshake(io)
.await
} }
/// The sender side of an established connection. /// The sender side of an established connection.
@@ -65,7 +58,6 @@ pub struct SendRequest<B> {
dispatch: dispatch::Sender<Request<B>, Response<Body>>, dispatch: dispatch::Sender<Request<B>, Response<Body>>,
} }
/// A future that processes all HTTP state for the IO object. /// A future that processes all HTTP state for the IO object.
/// ///
/// In most cases, this should just be spawned into an executor, so that it /// In most cases, this should just be spawned into an executor, so that it
@@ -79,7 +71,6 @@ where
inner: Option<ProtoClient<T, B>>, inner: Option<ProtoClient<T, B>>,
} }
/// A builder to configure an HTTP connection. /// A builder to configure an HTTP connection.
/// ///
/// After setting options, the builder is used to create a handshake future. /// After setting options, the builder is used to create a handshake future.
@@ -99,7 +90,7 @@ pub struct Builder {
/// Yields a `Response` if successful. /// Yields a `Response` if successful.
#[must_use = "futures do nothing unless polled"] #[must_use = "futures do nothing unless polled"]
pub struct ResponseFuture { pub struct ResponseFuture {
inner: ResponseFutureState inner: ResponseFutureState,
} }
enum ResponseFutureState { enum ResponseFutureState {
@@ -139,8 +130,7 @@ pub(super) struct Http2SendRequest<B> {
// ===== impl SendRequest // ===== impl SendRequest
impl<B> SendRequest<B> impl<B> SendRequest<B> {
{
/// Polls to determine whether this sender can be used yet for a request. /// Polls to determine whether this sender can be used yet for a request.
/// ///
/// If the associated connection is closed, this returns an Error. /// If the associated connection is closed, this returns an Error.
@@ -218,9 +208,7 @@ where
/// ``` /// ```
pub fn send_request(&mut self, req: Request<B>) -> ResponseFuture { pub fn send_request(&mut self, req: Request<B>) -> ResponseFuture {
let inner = match self.dispatch.send(req) { let inner = match self.dispatch.send(req) {
Ok(rx) => { Ok(rx) => ResponseFutureState::Waiting(rx),
ResponseFutureState::Waiting(rx)
},
Err(_req) => { Err(_req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
@@ -228,12 +216,13 @@ where
} }
}; };
ResponseFuture { ResponseFuture { inner }
inner,
}
} }
pub(crate) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> + Unpin pub(crate) fn send_request_retryable(
&mut self,
req: Request<B>,
) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> + Unpin
where where
B: Send, B: Send,
{ {
@@ -247,7 +236,7 @@ where
Err(_) => panic!("dispatch dropped without returning error"), Err(_) => panic!("dispatch dropped without returning error"),
} }
})) }))
}, }
Err(req) => { Err(req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
@@ -259,7 +248,8 @@ where
impl<B> Service<Request<B>> for SendRequest<B> impl<B> Service<Request<B>> for SendRequest<B>
where where
B: Payload + 'static, { B: Payload + 'static,
{
type Response = Response<Body>; type Response = Response<Body>;
type Error = crate::Error; type Error = crate::Error;
type Future = ResponseFuture; type Future = ResponseFuture;
@@ -275,8 +265,7 @@ where
impl<B> fmt::Debug for SendRequest<B> { impl<B> fmt::Debug for SendRequest<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SendRequest") f.debug_struct("SendRequest").finish()
.finish()
} }
} }
@@ -296,7 +285,10 @@ impl<B> Http2SendRequest<B>
where where
B: Payload + 'static, B: Payload + 'static,
{ {
pub(super) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output=Result<Response<Body>, (crate::Error, Option<Request<B>>)>> pub(super) fn send_request_retryable(
&mut self,
req: Request<B>,
) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>>
where where
B: Send, B: Send,
{ {
@@ -310,7 +302,7 @@ where
Err(_) => panic!("dispatch dropped without returning error"), Err(_) => panic!("dispatch dropped without returning error"),
} }
})) }))
}, }
Err(req) => { Err(req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
@@ -322,8 +314,7 @@ where
impl<B> fmt::Debug for Http2SendRequest<B> { impl<B> fmt::Debug for Http2SendRequest<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Http2SendRequest") f.debug_struct("Http2SendRequest").finish()
.finish()
} }
} }
@@ -374,12 +365,8 @@ where
/// to work with this function; or use the `without_shutdown` wrapper. /// to work with this function; or use the `without_shutdown` wrapper.
pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
match self.inner.as_mut().expect("already upgraded") { match self.inner.as_mut().expect("already upgraded") {
&mut ProtoClient::H1(ref mut h1) => { &mut ProtoClient::H1(ref mut h1) => h1.poll_without_shutdown(cx),
h1.poll_without_shutdown(cx) &mut ProtoClient::H2(ref mut h2) => Pin::new(h2).poll(cx).map_ok(|_| ()),
},
&mut ProtoClient::H2(ref mut h2) => {
Pin::new(h2).poll(cx).map_ok(|_| ())
}
} }
} }
@@ -404,9 +391,7 @@ where
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match ready!(Pin::new(self.inner.as_mut().unwrap()).poll(cx))? { match ready!(Pin::new(self.inner.as_mut().unwrap()).poll(cx))? {
proto::Dispatched::Shutdown => { proto::Dispatched::Shutdown => Poll::Ready(Ok(())),
Poll::Ready(Ok(()))
},
proto::Dispatched::Upgrade(pending) => { proto::Dispatched::Upgrade(pending) => {
let h1 = match mem::replace(&mut self.inner, None) { let h1 = match mem::replace(&mut self.inner, None) {
Some(ProtoClient::H1(h1)) => h1, Some(ProtoClient::H1(h1)) => h1,
@@ -427,8 +412,7 @@ where
B: Payload + 'static, B: Payload + 'static,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Connection") f.debug_struct("Connection").finish()
.finish()
} }
} }
@@ -519,7 +503,10 @@ impl Builder {
/// Passing `None` will do nothing. /// Passing `None` will do nothing.
/// ///
/// If not set, hyper will use a default. /// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { pub fn http2_initial_connection_window_size(
&mut self,
sz: impl Into<Option<u32>>,
) -> &mut Self {
if let Some(sz) = sz.into() { if let Some(sz) = sz.into() {
self.h2_builder.initial_connection_window_size(sz); self.h2_builder.initial_connection_window_size(sz);
} }
@@ -527,7 +514,10 @@ impl Builder {
} }
/// Constructs a connection with the configured options and IO. /// Constructs a connection with the configured options and IO.
pub fn handshake<T, B>(&self, io: T) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B>)>> pub fn handshake<T, B>(
&self,
io: T,
) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B>)>>
where where
T: AsyncRead + AsyncWrite + Unpin + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
@@ -563,12 +553,8 @@ impl Builder {
}; };
Ok(( Ok((
SendRequest { SendRequest { dispatch: tx },
dispatch: tx, Connection { inner: Some(proto) },
},
Connection {
inner: Some(proto),
},
)) ))
} }
} }
@@ -588,7 +574,7 @@ impl Future for ResponseFuture {
// this is definite bug if it happens, but it shouldn't happen! // this is definite bug if it happens, but it shouldn't happen!
Err(_canceled) => panic!("dispatch dropped without returning error"), Err(_canceled) => panic!("dispatch dropped without returning error"),
}) })
}, }
ResponseFutureState::Error(ref mut err) => { ResponseFutureState::Error(ref mut err) => {
Poll::Ready(Err(err.take().expect("polled after ready"))) Poll::Ready(Err(err.take().expect("polled after ready")))
} }
@@ -598,8 +584,7 @@ impl Future for ResponseFuture {
impl fmt::Debug for ResponseFuture { impl fmt::Debug for ResponseFuture {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ResponseFuture") f.debug_struct("ResponseFuture").finish()
.finish()
} }
} }
@@ -628,7 +613,6 @@ where
trait AssertSend: Send {} trait AssertSend: Send {}
trait AssertSendSync: Send + Sync {} trait AssertSendSync: Send + Sync {}
#[doc(hidden)] #[doc(hidden)]
impl<B: Send> AssertSendSync for SendRequest<B> {} impl<B: Send> AssertSendSync for SendRequest<B> {}
@@ -637,7 +621,8 @@ 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,
{} {
}
#[doc(hidden)] #[doc(hidden)]
impl<T: Send + Sync, B: Send + Sync> AssertSendSync for Connection<T, B> impl<T: Send + Sync, B: Send + Sync> AssertSendSync for Connection<T, B>
@@ -645,11 +630,11 @@ where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
B::Data: Send + Sync + 'static, B::Data: Send + Sync + 'static,
{} {
}
#[doc(hidden)] #[doc(hidden)]
impl AssertSendSync for Builder {} impl AssertSendSync for Builder {}
#[doc(hidden)] #[doc(hidden)]
impl AssertSend for ResponseFuture {} impl AssertSend for ResponseFuture {}

View File

@@ -22,11 +22,11 @@
//! }); //! });
//! ``` //! ```
use std::error::Error; use std::error::Error;
use std::future::Future;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::pin::Pin;
use std::str::FromStr; use std::str::FromStr;
use std::task::{self, Poll}; use std::task::{self, Poll};
use std::pin::Pin;
use std::future::Future;
use std::{fmt, io, vec}; use std::{fmt, io, vec};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
@@ -394,7 +394,8 @@ mod tests {
let dst = ::http::Uri::from_static("http://[::1]:8080/"); let dst = ::http::Uri::from_static("http://[::1]:8080/");
let mut addrs = let mut addrs =
IpAddrs::try_parse(dst.host().expect("host"), dst.port_u16().expect("port")).expect("try_parse"); IpAddrs::try_parse(dst.host().expect("host"), dst.port_u16().expect("port"))
.expect("try_parse");
let expected = "[::1]:8080".parse::<SocketAddr>().expect("expected"); let expected = "[::1]:8080".parse::<SocketAddr>().expect("expected");

View File

@@ -1,12 +1,12 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{self, Poll};
use std::fmt; use std::fmt;
use std::future::Future;
use std::io; use std::io;
use std::marker::PhantomData;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::task::{self, Poll};
use std::time::Duration; use std::time::Duration;
use futures_util::future::Either; use futures_util::future::Either;
@@ -20,7 +20,6 @@ use super::dns::{self, resolve, GaiResolver, Resolve};
use super::{Connected, Connection}; use super::{Connected, Connection};
//#[cfg(feature = "runtime")] use super::dns::TokioThreadpoolGaiResolver; //#[cfg(feature = "runtime")] use super::dns::TokioThreadpoolGaiResolver;
/// A connector for the `http` scheme. /// A connector for the `http` scheme.
/// ///
/// Performs DNS resolution in a thread pool, and then connects over TCP. /// Performs DNS resolution in a thread pool, and then connects over TCP.
@@ -256,10 +255,7 @@ impl<R> HttpConnector<R>
where where
R: Resolve, R: Resolve,
{ {
async fn call_async( async fn call_async(&mut self, dst: Uri) -> Result<TcpStream, ConnectError> {
&mut self,
dst: Uri,
) -> Result<TcpStream, ConnectError> {
trace!( trace!(
"Http::connect; scheme={:?}, host={:?}, port={:?}", "Http::connect; scheme={:?}, host={:?}, port={:?}",
dst.scheme(), dst.scheme(),
@@ -292,7 +288,13 @@ where
}; };
let port = match dst.port() { let port = match dst.port() {
Some(port) => port.as_u16(), Some(port) => port.as_u16(),
None => if dst.scheme() == Some(&Scheme::HTTPS) { 443 } else { 80 }, None => {
if dst.scheme() == Some(&Scheme::HTTPS) {
443
} else {
80
}
}
}; };
let config = &self.config; let config = &self.config;
@@ -348,9 +350,7 @@ impl Connection for TcpStream {
fn connected(&self) -> Connected { fn connected(&self) -> Connected {
let connected = Connected::new(); let connected = Connected::new();
if let Ok(remote_addr) = self.peer_addr() { if let Ok(remote_addr) = self.peer_addr() {
connected.extra(HttpInfo { connected.extra(HttpInfo { remote_addr })
remote_addr,
})
} else { } else {
connected connected
} }
@@ -389,7 +389,6 @@ impl<R: Resolve> Future for HttpConnecting<R> {
} }
} }
// Not publicly exported (so missing_docs doesn't trigger). // Not publicly exported (so missing_docs doesn't trigger).
pub struct ConnectError { pub struct ConnectError {
msg: Box<str>, msg: Box<str>,
@@ -531,14 +530,7 @@ impl ConnectingTcpRemote {
let mut err = None; let mut err = None;
for addr in &mut self.addrs { for addr in &mut self.addrs {
debug!("connecting to {}", addr); debug!("connecting to {}", addr);
match connect( match connect(&addr, local_addr, reuse_address, self.connect_timeout)?.await {
&addr,
local_addr,
reuse_address,
self.connect_timeout,
)?
.await
{
Ok(tcp) => { Ok(tcp) => {
debug!("connected to {:?}", tcp.peer_addr().ok()); debug!("connected to {:?}", tcp.peer_addr().ok());
return Ok(tcp); return Ok(tcp);
@@ -606,11 +598,7 @@ impl ConnectingTcp {
.. ..
} = self; } = self;
match self.fallback { match self.fallback {
None => { None => self.preferred.connect(local_addr, reuse_address).await,
self.preferred
.connect(local_addr, reuse_address)
.await
}
Some(mut fallback) => { Some(mut fallback) => {
let preferred_fut = self.preferred.connect(local_addr, reuse_address); let preferred_fut = self.preferred.connect(local_addr, reuse_address);
futures_util::pin_mut!(preferred_fut); futures_util::pin_mut!(preferred_fut);
@@ -652,10 +640,7 @@ mod tests {
use super::super::sealed::Connect; use super::super::sealed::Connect;
use super::HttpConnector; use super::HttpConnector;
async fn connect<C>( async fn connect<C>(connector: C, dst: Uri) -> Result<C::Transport, C::Error>
connector: C,
dst: Uri,
) -> Result<C::Transport, C::Error>
where where
C: Connect, C: Connect,
{ {
@@ -795,7 +780,6 @@ mod tests {
continue; continue;
} }
let (start, stream) = rt let (start, stream) = rt
.block_on(async move { .block_on(async move {
let addrs = hosts let addrs = hosts

View File

@@ -7,11 +7,14 @@
//! - Types to build custom connectors. //! - Types to build custom connectors.
use std::fmt; use std::fmt;
use ::http::{Response}; use ::http::Response;
#[cfg(feature = "tcp")] pub mod dns; #[cfg(feature = "tcp")]
#[cfg(feature = "tcp")] mod http; pub mod dns;
#[cfg(feature = "tcp")] pub use self::http::{HttpConnector, HttpInfo}; #[cfg(feature = "tcp")]
mod http;
#[cfg(feature = "tcp")]
pub use self::http::{HttpConnector, HttpInfo};
/// Describes a type returned by a connector. /// Describes a type returned by a connector.
pub trait Connection { pub trait Connection {
@@ -115,8 +118,7 @@ impl Clone for Extra {
impl fmt::Debug for Extra { impl fmt::Debug for Extra {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extra") f.debug_struct("Extra").finish()
.finish()
} }
} }
@@ -133,7 +135,7 @@ struct ExtraEnvelope<T>(T);
impl<T> ExtraInner for ExtraEnvelope<T> impl<T> ExtraInner for ExtraEnvelope<T>
where where
T: Clone + Send + Sync + 'static T: Clone + Send + Sync + 'static,
{ {
fn clone_box(&self) -> Box<dyn ExtraInner> { fn clone_box(&self) -> Box<dyn ExtraInner> {
Box::new(self.clone()) Box::new(self.clone())
@@ -154,7 +156,7 @@ impl<T: Clone> Clone for ExtraChain<T> {
impl<T> ExtraInner for ExtraChain<T> impl<T> ExtraInner for ExtraChain<T>
where where
T: Clone + Send + Sync + 'static T: Clone + Send + Sync + 'static,
{ {
fn clone_box(&self) -> Box<dyn ExtraInner> { fn clone_box(&self) -> Box<dyn ExtraInner> {
Box::new(self.clone()) Box::new(self.clone())
@@ -172,8 +174,8 @@ pub(super) mod sealed {
use ::http::Uri; use ::http::Uri;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use super::Connection;
use crate::common::{Future, Unpin}; use crate::common::{Future, Unpin};
use super::{Connection};
/// Connect to a destination, returning an IO transport. /// Connect to a destination, returning an IO transport.
/// ///
@@ -219,7 +221,8 @@ pub(super) mod sealed {
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
S::Future: Unpin + Send, S::Future: Unpin + Send,
T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static, T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static,
{} {
}
pub trait Sealed {} pub trait Sealed {}
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@@ -228,7 +231,7 @@ pub(super) mod sealed {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Connected}; use super::Connected;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Ex1(usize); struct Ex1(usize);
@@ -241,18 +244,13 @@ mod tests {
#[test] #[test]
fn test_connected_extra() { fn test_connected_extra() {
let c1 = Connected::new() let c1 = Connected::new().extra(Ex1(41));
.extra(Ex1(41));
let mut res1 = crate::Response::new(crate::Body::empty()); let mut res1 = crate::Response::new(crate::Body::empty());
assert_eq!(res1.extensions().get::<Ex1>(), None); assert_eq!(res1.extensions().get::<Ex1>(), None);
c1 c1.extra.as_ref().expect("c1 extra").set(&mut res1);
.extra
.as_ref()
.expect("c1 extra")
.set(&mut res1);
assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(41))); assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(41)));
} }
@@ -273,11 +271,7 @@ mod tests {
assert_eq!(res1.extensions().get::<Ex2>(), None); assert_eq!(res1.extensions().get::<Ex2>(), None);
assert_eq!(res1.extensions().get::<Ex3>(), None); assert_eq!(res1.extensions().get::<Ex3>(), None);
c1 c1.extra.as_ref().expect("c1 extra").set(&mut res1);
.extra
.as_ref()
.expect("c1 extra")
.set(&mut res1);
assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(45))); assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(45)));
assert_eq!(res1.extensions().get::<Ex2>(), Some(&Ex2("zoom"))); assert_eq!(res1.extensions().get::<Ex2>(), Some(&Ex2("zoom")));
@@ -291,11 +285,7 @@ mod tests {
let mut res2 = crate::Response::new(crate::Body::empty()); let mut res2 = crate::Response::new(crate::Body::empty());
c2 c2.extra.as_ref().expect("c2 extra").set(&mut res2);
.extra
.as_ref()
.expect("c2 extra")
.set(&mut res2);
assert_eq!(res2.extensions().get::<Ex1>(), Some(&Ex1(99))); assert_eq!(res2.extensions().get::<Ex1>(), Some(&Ex1(99)));
assert_eq!(res2.extensions().get::<Ex2>(), Some(&Ex2("hiccup"))); assert_eq!(res2.extensions().get::<Ex2>(), Some(&Ex2("hiccup")));

View File

@@ -1,8 +1,8 @@
use futures_core::Stream;
use futures_channel::{mpsc, oneshot}; use futures_channel::{mpsc, oneshot};
use futures_core::Stream;
use futures_util::future; use futures_util::future;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>; pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>;
pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>; pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;
@@ -52,7 +52,8 @@ pub struct UnboundedSender<T, U> {
impl<T, U> Sender<T, U> { impl<T, U> Sender<T, U> {
pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
self.giver.poll_want(cx) self.giver
.poll_want(cx)
.map_err(|_| crate::Error::new_closed()) .map_err(|_| crate::Error::new_closed())
} }
@@ -82,7 +83,8 @@ impl<T, U> Sender<T, U> {
return Err(val); return Err(val);
} }
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) self.inner
.unbounded_send(Envelope(Some((val, Callback::Retry(tx)))))
.map(move |_| rx) .map(move |_| rx)
.map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0)
} }
@@ -92,7 +94,8 @@ impl<T, U> Sender<T, U> {
return Err(val); return Err(val);
} }
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.inner.unbounded_send(Envelope(Some((val, Callback::NoRetry(tx))))) self.inner
.unbounded_send(Envelope(Some((val, Callback::NoRetry(tx)))))
.map(move |_| rx) .map(move |_| rx)
.map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0)
} }
@@ -116,7 +119,8 @@ impl<T, U> UnboundedSender<T, U> {
pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> { pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) self.inner
.unbounded_send(Envelope(Some((val, Callback::Retry(tx)))))
.map(move |_| rx) .map(move |_| rx)
.map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0)
} }
@@ -137,15 +141,18 @@ pub struct Receiver<T, U> {
} }
impl<T, U> Receiver<T, U> { impl<T, U> Receiver<T, U> {
pub(crate) fn poll_next(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> { pub(crate) fn poll_next(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<(T, Callback<T, U>)>> {
match Pin::new(&mut self.inner).poll_next(cx) { match Pin::new(&mut self.inner).poll_next(cx) {
Poll::Ready(item) => Poll::Ready(item.map(|mut env| { Poll::Ready(item) => {
env.0.take().expect("envelope not dropped") Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped")))
})), }
Poll::Pending => { Poll::Pending => {
self.taker.want(); self.taker.want();
Poll::Pending Poll::Pending
}, }
} }
} }
@@ -176,7 +183,10 @@ struct Envelope<T, U>(Option<(T, Callback<T, U>)>);
impl<T, U> Drop for Envelope<T, U> { impl<T, U> Drop for Envelope<T, U> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some((val, cb)) = self.0.take() { if let Some((val, cb)) = self.0.take() {
let _ = cb.send(Err((crate::Error::new_canceled().with("connection closed"), Some(val)))); let _ = cb.send(Err((
crate::Error::new_canceled().with("connection closed"),
Some(val),
)));
} }
} }
} }
@@ -205,7 +215,7 @@ impl<T, U> Callback<T, U> {
match self { match self {
Callback::Retry(tx) => { Callback::Retry(tx) => {
let _ = tx.send(val); let _ = tx.send(val);
}, }
Callback::NoRetry(tx) => { Callback::NoRetry(tx) => {
let _ = tx.send(val.map_err(|e| e.0)); let _ = tx.send(val.map_err(|e| e.0));
} }
@@ -222,21 +232,17 @@ impl<T, U> Callback<T, U> {
future::poll_fn(move |cx| { future::poll_fn(move |cx| {
match Pin::new(&mut when).poll(cx) { match Pin::new(&mut when).poll(cx) {
Poll::Ready(Ok(res)) => { Poll::Ready(Ok(res)) => {
cb.take() cb.take().expect("polled after complete").send(Ok(res));
.expect("polled after complete")
.send(Ok(res));
Poll::Ready(()) Poll::Ready(())
}, }
Poll::Pending => { Poll::Pending => {
// check if the callback is canceled // check if the callback is canceled
ready!(cb.as_mut().unwrap().poll_canceled(cx)); ready!(cb.as_mut().unwrap().poll_canceled(cx));
trace!("send_when canceled"); trace!("send_when canceled");
Poll::Ready(()) Poll::Ready(())
}, }
Poll::Ready(Err(err)) => { Poll::Ready(Err(err)) => {
cb.take() cb.take().expect("polled after complete").send(Err(err));
.expect("polled after complete")
.send(Err(err));
Poll::Ready(()) Poll::Ready(())
} }
} }
@@ -253,7 +259,7 @@ mod tests {
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use super::{Callback, channel, Receiver}; use super::{channel, Callback, Receiver};
#[derive(Debug)] #[derive(Debug)]
struct Custom(i32); struct Custom(i32);
@@ -271,14 +277,14 @@ mod tests {
impl<F, T> Future for PollOnce<'_, F> impl<F, T> Future for PollOnce<'_, F>
where where
F: Future<Output = T> + Unpin F: Future<Output = T> + Unpin,
{ {
type Output = Option<()>; type Output = Option<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.0).poll(cx) { match Pin::new(&mut self.0).poll(cx) {
Poll::Ready(_) => Poll::Ready(Some(())), Poll::Ready(_) => Poll::Ready(Some(())),
Poll::Pending => Poll::Ready(None) Poll::Pending => Poll::Ready(None),
} }
} }
} }
@@ -357,7 +363,7 @@ mod tests {
let poll_once = PollOnce(&mut rx); let poll_once = PollOnce(&mut rx);
let opt = poll_once.await; let opt = poll_once.await;
if opt.is_none() { if opt.is_none() {
break break;
} }
} }
}); });

View File

@@ -64,17 +64,18 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use futures_channel::oneshot; use futures_channel::oneshot;
use futures_util::future::{self, FutureExt as _, TryFutureExt as _, Either}; use futures_util::future::{self, Either, FutureExt as _, TryFutureExt as _};
use http::{Method, Request, Response, Uri, Version};
use http::header::{HeaderValue, HOST}; use http::header::{HeaderValue, HOST};
use http::uri::Scheme; use http::uri::Scheme;
use http::{Method, Request, Response, Uri, Version};
use crate::body::{Body, Payload}; use self::connect::{sealed::Connect, Alpn, Connected, Connection};
use crate::common::{lazy as hyper_lazy, BoxSendFuture, Executor, Lazy, Future, Pin, Poll, task};
use self::connect::{Alpn, sealed::Connect, Connected, Connection};
use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation}; use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation};
use crate::body::{Body, Payload};
use crate::common::{lazy as hyper_lazy, task, BoxSendFuture, Executor, Future, Lazy, Pin, Poll};
#[cfg(feature = "tcp")] pub use self::connect::HttpConnector; #[cfg(feature = "tcp")]
pub use self::connect::HttpConnector;
pub mod conn; pub mod conn;
pub mod connect; pub mod connect;
@@ -157,7 +158,8 @@ impl Client<(), Body> {
} }
impl<C, B> Client<C, B> impl<C, B> Client<C, B>
where C: Connect + Clone + Send + Sync + 'static, where
C: Connect + Clone + Send + Sync + 'static,
C::Transport: Unpin + Send + 'static, C::Transport: Unpin + Send + 'static,
C::Future: Unpin + Send + 'static, C::Future: Unpin + Send + 'static,
B: Payload + Unpin + Send + 'static, B: Payload + Unpin + Send + 'static,
@@ -223,13 +225,19 @@ where C: Connect + Clone + Send + Sync + 'static,
let is_http_connect = req.method() == &Method::CONNECT; let is_http_connect = req.method() == &Method::CONNECT;
match req.version() { match req.version() {
Version::HTTP_11 => (), Version::HTTP_11 => (),
Version::HTTP_10 => if is_http_connect { Version::HTTP_10 => {
if is_http_connect {
warn!("CONNECT is not allowed for HTTP/1.0"); warn!("CONNECT is not allowed for HTTP/1.0");
return ResponseFuture::new(Box::new(future::err(crate::Error::new_user_unsupported_request_method()))); return ResponseFuture::new(Box::new(future::err(
}, crate::Error::new_user_unsupported_request_method(),
other_h2 @ Version::HTTP_2 => if self.config.ver != Ver::Http2 { )));
}
}
other_h2 @ Version::HTTP_2 => {
if self.config.ver != Ver::Http2 {
return ResponseFuture::error_version(other_h2); return ResponseFuture::error_version(other_h2);
}, }
}
// completely unsupported HTTP version (like HTTP/0.9)! // completely unsupported HTTP version (like HTTP/0.9)!
other => return ResponseFuture::error_version(other), other => return ResponseFuture::error_version(other),
}; };
@@ -245,7 +253,11 @@ where C: Connect + Clone + Send + Sync + 'static,
ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key))) ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key)))
} }
fn retryably_send_request(&self, req: Request<B>, pool_key: PoolKey) -> impl Future<Output=crate::Result<Response<Body>>> { fn retryably_send_request(
&self,
req: Request<B>,
pool_key: PoolKey,
) -> impl Future<Output = crate::Result<Response<Body>>> {
let client = self.clone(); let client = self.clone();
let uri = req.uri().clone(); let uri = req.uri().clone();
@@ -265,7 +277,10 @@ where C: Connect + Clone + Send + Sync + 'static,
return Poll::Ready(Err(reason)); return Poll::Ready(Err(reason));
} }
trace!("unstarted request canceled, trying again (reason={:?})", reason); trace!(
"unstarted request canceled, trying again (reason={:?})",
reason
);
*req.uri_mut() = uri.clone(); *req.uri_mut() = uri.clone();
send_fut = client.send_request(req, pool_key.clone()); send_fut = client.send_request(req, pool_key.clone());
} }
@@ -273,7 +288,11 @@ where C: Connect + Clone + Send + Sync + 'static,
}) })
} }
fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> impl Future<Output=Result<Response<Body>, ClientError<B>>> + Unpin { fn send_request(
&self,
mut req: Request<B>,
pool_key: PoolKey,
) -> impl Future<Output = Result<Response<Body>, ClientError<B>>> + Unpin {
let conn = self.connection_for(req.uri().clone(), pool_key); let conn = self.connection_for(req.uri().clone(), pool_key);
let set_host = self.config.set_host; let set_host = self.config.set_host;
@@ -282,17 +301,15 @@ where C: Connect + Clone + Send + Sync + 'static,
if pooled.is_http1() { if pooled.is_http1() {
if set_host { if set_host {
let uri = req.uri().clone(); let uri = req.uri().clone();
req req.headers_mut().entry(HOST).or_insert_with(|| {
.headers_mut()
.entry(HOST)
.or_insert_with(|| {
let hostname = uri.host().expect("authority implies host"); let hostname = uri.host().expect("authority implies host");
if let Some(port) = uri.port() { if let Some(port) = uri.port() {
let s = format!("{}:{}", hostname, port); let s = format!("{}:{}", hostname, port);
HeaderValue::from_str(&s) HeaderValue::from_str(&s)
} else { } else {
HeaderValue::from_str(hostname) HeaderValue::from_str(hostname)
}.expect("uri host is valid header value") }
.expect("uri host is valid header value")
}); });
} }
@@ -306,10 +323,13 @@ where C: Connect + Clone + Send + Sync + 'static,
}; };
} else if req.method() == &Method::CONNECT { } else if req.method() == &Method::CONNECT {
debug!("client does not support CONNECT requests over HTTP2"); debug!("client does not support CONNECT requests over HTTP2");
return Either::Left(future::err(ClientError::Normal(crate::Error::new_user_unsupported_request_method()))); return Either::Left(future::err(ClientError::Normal(
crate::Error::new_user_unsupported_request_method(),
)));
} }
let fut = pooled.send_request_retryable(req) let fut = pooled
.send_request_retryable(req)
.map_err(ClientError::map_with_reused(pooled.is_reused())); .map_err(ClientError::map_with_reused(pooled.is_reused()));
// If the Connector included 'extra' info, add to Response... // If the Connector included 'extra' info, add to Response...
@@ -332,8 +352,7 @@ where C: Connect + Clone + Send + Sync + 'static,
return Either::Right(Either::Left(fut)); return Either::Right(Either::Left(fut));
} }
Either::Right(Either::Right(fut Either::Right(Either::Right(fut.map_ok(move |mut res| {
.map_ok(move |mut res| {
// If pooled is HTTP/2, we can toss this reference immediately. // If pooled is HTTP/2, we can toss this reference immediately.
// //
// when pooled is dropped, it will try to insert back into the // when pooled is dropped, it will try to insert back into the
@@ -349,10 +368,7 @@ where C: Connect + Clone + Send + Sync + 'static,
} else if !res.body().is_end_stream() { } else if !res.body().is_end_stream() {
let (delayed_tx, delayed_rx) = oneshot::channel(); let (delayed_tx, delayed_rx) = oneshot::channel();
res.body_mut().delayed_eof(delayed_rx); res.body_mut().delayed_eof(delayed_rx);
let on_idle = future::poll_fn(move |cx| { let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(move |_| {
pooled.poll_ready(cx)
})
.map(move |_| {
// At this point, `pooled` is dropped, and had a chance // At this point, `pooled` is dropped, and had a chance
// to insert into the pool (if conn was idle) // to insert into the pool (if conn was idle)
drop(delayed_tx); drop(delayed_tx);
@@ -362,10 +378,7 @@ where C: Connect + Clone + Send + Sync + 'static,
} else { } else {
// There's no body to delay, but the connection isn't // There's no body to delay, but the connection isn't
// ready yet. Only re-insert when it's ready // ready yet. Only re-insert when it's ready
let on_idle = future::poll_fn(move |cx| { let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(|_| ());
pooled.poll_ready(cx)
})
.map(|_| ());
executor.execute(on_idle); executor.execute(on_idle);
} }
@@ -374,9 +387,11 @@ where C: Connect + Clone + Send + Sync + 'static,
}) })
} }
fn connection_for(&self, uri: Uri, pool_key: PoolKey) fn connection_for(
-> impl Future<Output=Result<Pooled<PoolClient<B>>, ClientError<B>>> &self,
{ uri: Uri,
pool_key: PoolKey,
) -> impl Future<Output = Result<Pooled<PoolClient<B>>, ClientError<B>>> {
// This actually races 2 different futures to try to get a ready // This actually races 2 different futures to try to get a ready
// connection the fastest, and to reduce connection churn. // connection the fastest, and to reduce connection churn.
// //
@@ -395,8 +410,7 @@ where C: Connect + Clone + Send + Sync + 'static,
let executor = self.conn_builder.exec.clone(); let executor = self.conn_builder.exec.clone();
// The order of the `select` is depended on below... // The order of the `select` is depended on below...
future::select(checkout, connect) future::select(checkout, connect).then(move |either| match either {
.then(move |either| match either {
// Checkout won, connect future may have been started or not. // Checkout won, connect future may have been started or not.
// //
// If it has, let it finish and insert back into the pool, // If it has, let it finish and insert back into the pool,
@@ -423,11 +437,9 @@ where C: Connect + Clone + Send + Sync + 'static,
let _ = executor.execute(bg); let _ = executor.execute(bg);
} }
Either::Left(future::ok(checked_out)) Either::Left(future::ok(checked_out))
}, }
// Connect won, checkout can just be dropped. // Connect won, checkout can just be dropped.
Either::Right((Ok(connected), _checkout)) => { Either::Right((Ok(connected), _checkout)) => Either::Left(future::ok(connected)),
Either::Left(future::ok(connected))
},
// Either checkout or connect could get canceled: // Either checkout or connect could get canceled:
// //
// 1. Connect is canceled if this is HTTP/2 and there is // 1. Connect is canceled if this is HTTP/2 and there is
@@ -453,9 +465,11 @@ where C: Connect + Clone + Send + Sync + 'static,
}) })
} }
fn connect_to(&self, uri: Uri, pool_key: PoolKey) fn connect_to(
-> impl Lazy<Output=crate::Result<Pooled<PoolClient<B>>>> + Unpin &self,
{ uri: Uri,
pool_key: PoolKey,
) -> impl Lazy<Output = crate::Result<Pooled<PoolClient<B>>>> + Unpin {
let executor = self.conn_builder.exec.clone(); let executor = self.conn_builder.exec.clone();
let pool = self.pool.clone(); let pool = self.pool.clone();
let mut conn_builder = self.conn_builder.clone(); let mut conn_builder = self.conn_builder.clone();
@@ -472,11 +486,14 @@ where C: Connect + Clone + Send + Sync + 'static,
let connecting = match pool.connecting(&pool_key, ver) { let connecting = match pool.connecting(&pool_key, ver) {
Some(lock) => lock, Some(lock) => lock,
None => { None => {
let canceled = crate::Error::new_canceled().with("HTTP/2 connection in progress"); let canceled =
crate::Error::new_canceled().with("HTTP/2 connection in progress");
return Either::Right(future::err(canceled)); return Either::Right(future::err(canceled));
} }
}; };
Either::Left(connector.connect(connect::sealed::Internal, dst) Either::Left(
connector
.connect(connect::sealed::Internal, dst)
.map_err(crate::Error::new_connect) .map_err(crate::Error::new_connect)
.and_then(move |io| { .and_then(move |io| {
let connected = io.connected(); let connected = io.connected();
@@ -488,11 +505,12 @@ where C: Connect + Clone + Send + Sync + 'static,
Some(lock) => { Some(lock) => {
trace!("ALPN negotiated h2, updating pool"); trace!("ALPN negotiated h2, updating pool");
lock lock
}, }
None => { None => {
// Another connection has already upgraded, // Another connection has already upgraded,
// the pool checkout should finish up for us. // the pool checkout should finish up for us.
let canceled = crate::Error::new_canceled().with("ALPN upgraded to HTTP/2"); let canceled = crate::Error::new_canceled()
.with("ALPN upgraded to HTTP/2");
return Either::Right(future::err(canceled)); return Either::Right(future::err(canceled));
} }
} }
@@ -500,36 +518,46 @@ where C: Connect + Clone + Send + Sync + 'static,
connecting connecting
}; };
let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2;
Either::Left(Box::pin(conn_builder Either::Left(Box::pin(
conn_builder
.http2_only(is_h2) .http2_only(is_h2)
.handshake(io) .handshake(io)
.and_then(move |(tx, conn)| { .and_then(move |(tx, conn)| {
trace!("handshake complete, spawning background dispatcher task"); trace!(
executor.execute(conn.map_err(|e| { "handshake complete, spawning background dispatcher task"
debug!("client connection error: {}", e) );
}).map(|_| ())); executor.execute(
conn.map_err(|e| debug!("client connection error: {}", e))
.map(|_| ()),
);
// Wait for 'conn' to ready up before we // Wait for 'conn' to ready up before we
// declare this tx as usable // declare this tx as usable
tx.when_ready() tx.when_ready()
}) })
.map_ok(move |tx| { .map_ok(move |tx| {
pool.pooled(connecting, PoolClient { pool.pooled(
connecting,
PoolClient {
conn_info: connected, conn_info: connected,
tx: if is_h2 { tx: if is_h2 {
PoolTx::Http2(tx.into_http2()) PoolTx::Http2(tx.into_http2())
} else { } else {
PoolTx::Http1(tx) PoolTx::Http1(tx)
}, },
}) },
}))) )
})) }),
))
}),
)
}) })
} }
} }
impl<C, B> tower_service::Service<Request<B>> for Client<C, B> impl<C, B> tower_service::Service<Request<B>> for Client<C, B>
where C: Connect + Clone + Send + Sync + 'static, where
C: Connect + Clone + Send + Sync + 'static,
C::Transport: Unpin + Send + 'static, C::Transport: Unpin + Send + 'static,
C::Future: Unpin + Send + 'static, C::Future: Unpin + Send + 'static,
B: Payload + Unpin + Send + 'static, B: Payload + Unpin + Send + 'static,
@@ -561,8 +589,7 @@ impl<C: Clone, B> Clone for Client<C, B> {
impl<C, B> fmt::Debug for Client<C, B> { impl<C, B> fmt::Debug for Client<C, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Client") f.debug_struct("Client").finish()
.finish()
} }
} }
@@ -570,14 +597,14 @@ impl<C, B> fmt::Debug for Client<C, B> {
impl ResponseFuture { impl ResponseFuture {
fn new(fut: Box<dyn Future<Output = crate::Result<Response<Body>>> + Send>) -> Self { fn new(fut: Box<dyn Future<Output = crate::Result<Response<Body>>> + Send>) -> Self {
Self { Self { inner: fut.into() }
inner: fut.into(),
}
} }
fn error_version(ver: Version) -> Self { fn error_version(ver: Version) -> Self {
warn!("Request has unsupported version \"{:?}\"", ver); warn!("Request has unsupported version \"{:?}\"", ver);
ResponseFuture::new(Box::new(future::err(crate::Error::new_user_unsupported_version()))) ResponseFuture::new(Box::new(future::err(
crate::Error::new_user_unsupported_version(),
)))
} }
} }
@@ -644,7 +671,10 @@ impl<B> PoolClient<B> {
} }
impl<B: Payload + 'static> PoolClient<B> { impl<B: Payload + 'static> PoolClient<B> {
fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> fn send_request_retryable(
&mut self,
req: Request<B>,
) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>>
where where
B: Send, B: Send,
{ {
@@ -668,12 +698,10 @@ where
fn reserve(self) -> Reservation<Self> { fn reserve(self) -> Reservation<Self> {
match self.tx { match self.tx {
PoolTx::Http1(tx) => { PoolTx::Http1(tx) => Reservation::Unique(PoolClient {
Reservation::Unique(PoolClient {
conn_info: self.conn_info, conn_info: self.conn_info,
tx: PoolTx::Http1(tx), tx: PoolTx::Http1(tx),
}) }),
},
PoolTx::Http2(tx) => { PoolTx::Http2(tx) => {
let b = PoolClient { let b = PoolClient {
conn_info: self.conn_info.clone(), conn_info: self.conn_info.clone(),
@@ -703,13 +731,11 @@ enum ClientError<B> {
connection_reused: bool, connection_reused: bool,
req: Request<B>, req: Request<B>,
reason: crate::Error, reason: crate::Error,
} },
} }
impl<B> ClientError<B> { impl<B> ClientError<B> {
fn map_with_reused(conn_reused: bool) fn map_with_reused(conn_reused: bool) -> impl Fn((crate::Error, Option<Request<B>>)) -> Self {
-> impl Fn((crate::Error, Option<Request<B>>)) -> Self
{
move |(err, orig_req)| { move |(err, orig_req)| {
if let Some(req) = orig_req { if let Some(req) = orig_req {
ClientError::Canceled { ClientError::Canceled {
@@ -737,7 +763,7 @@ fn origin_form(uri: &mut Uri) {
let mut parts = ::http::uri::Parts::default(); let mut parts = ::http::uri::Parts::default();
parts.path_and_query = Some(path.clone()); parts.path_and_query = Some(path.clone());
Uri::from_parts(parts).expect("path is valid uri") Uri::from_parts(parts).expect("path is valid uri")
}, }
_none_or_just_slash => { _none_or_just_slash => {
debug_assert!(Uri::default() == "/"); debug_assert!(Uri::default() == "/");
Uri::default() Uri::default()
@@ -748,7 +774,10 @@ fn origin_form(uri: &mut Uri) {
fn absolute_form(uri: &mut Uri) { fn absolute_form(uri: &mut Uri) {
debug_assert!(uri.scheme().is_some(), "absolute_form needs a scheme"); debug_assert!(uri.scheme().is_some(), "absolute_form needs a scheme");
debug_assert!(uri.authority().is_some(), "absolute_form needs an authority"); debug_assert!(
uri.authority().is_some(),
"absolute_form needs an authority"
);
// If the URI is to HTTPS, and the connector claimed to be a proxy, // If the URI is to HTTPS, and the connector claimed to be a proxy,
// then it *should* have tunneled, and so we don't want to send // then it *should* have tunneled, and so we don't want to send
// absolute-form in that case. // absolute-form in that case.
@@ -763,10 +792,7 @@ fn authority_form(uri: &mut Uri) {
// `https://hyper.rs` would parse with `/` path, don't // `https://hyper.rs` would parse with `/` path, don't
// annoy people about that... // annoy people about that...
if path != "/" { if path != "/" {
warn!( warn!("HTTP/1.1 CONNECT request stripping path: {:?}", path);
"HTTP/1.1 CONNECT request stripping path: {:?}",
path
);
} }
} }
} }
@@ -775,7 +801,7 @@ fn authority_form(uri: &mut Uri) {
let mut parts = ::http::uri::Parts::default(); let mut parts = ::http::uri::Parts::default();
parts.authority = Some(auth.clone()); parts.authority = Some(auth.clone());
Uri::from_parts(parts).expect("authority is valid") Uri::from_parts(parts).expect("authority is valid")
}, }
None => { None => {
unreachable!("authority_form with relative uri"); unreachable!("authority_form with relative uri");
} }
@@ -785,9 +811,7 @@ fn authority_form(uri: &mut Uri) {
fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String> { fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String> {
let uri_clone = uri.clone(); let uri_clone = uri.clone();
match (uri_clone.scheme(), uri_clone.authority()) { match (uri_clone.scheme(), uri_clone.authority()) {
(Some(scheme), Some(auth)) => { (Some(scheme), Some(auth)) => Ok(format!("{}://{}", scheme, auth)),
Ok(format!("{}://{}", scheme, auth))
}
(None, Some(auth)) if is_http_connect => { (None, Some(auth)) if is_http_connect => {
let scheme = match auth.port_u16() { let scheme = match auth.port_u16() {
Some(443) => { Some(443) => {
@@ -797,10 +821,10 @@ fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String>
_ => { _ => {
set_scheme(uri, Scheme::HTTP); set_scheme(uri, Scheme::HTTP);
"http" "http"
}, }
}; };
Ok(format!("{}://{}", scheme, auth)) Ok(format!("{}://{}", scheme, auth))
}, }
_ => { _ => {
debug!("Client requires absolute-form URIs, received: {:?}", uri); debug!("Client requires absolute-form URIs, received: {:?}", uri);
Err(crate::Error::new_user_absolute_uri_required()) Err(crate::Error::new_user_absolute_uri_required())
@@ -809,7 +833,10 @@ fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String>
} }
fn set_scheme(uri: &mut Uri, scheme: Scheme) { fn set_scheme(uri: &mut Uri, scheme: Scheme) {
debug_assert!(uri.scheme().is_none(), "set_scheme expects no existing scheme"); debug_assert!(
uri.scheme().is_none(),
"set_scheme expects no existing scheme"
);
let old = mem::replace(uri, Uri::default()); let old = mem::replace(uri, Uri::default());
let mut parts: ::http::uri::Parts = old.into(); let mut parts: ::http::uri::Parts = old.into();
parts.scheme = Some(scheme); parts.scheme = Some(scheme);
@@ -946,11 +973,7 @@ impl Builder {
/// ///
/// Default is false. /// Default is false.
pub fn http2_only(&mut self, val: bool) -> &mut Self { pub fn http2_only(&mut self, val: bool) -> &mut Self {
self.client_config.ver = if val { self.client_config.ver = if val { Ver::Http2 } else { Ver::Auto };
Ver::Http2
} else {
Ver::Auto
};
self self
} }
@@ -963,7 +986,8 @@ impl Builder {
/// ///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
self.conn_builder.http2_initial_stream_window_size(sz.into()); self.conn_builder
.http2_initial_stream_window_size(sz.into());
self self
} }
@@ -972,8 +996,12 @@ impl Builder {
/// Passing `None` will do nothing. /// Passing `None` will do nothing.
/// ///
/// If not set, hyper will use a default. /// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { pub fn http2_initial_connection_window_size(
self.conn_builder.http2_initial_connection_window_size(sz.into()); &mut self,
sz: impl Into<Option<u32>>,
) -> &mut Self {
self.conn_builder
.http2_initial_connection_window_size(sz.into());
self self
} }

View File

@@ -10,8 +10,8 @@ use futures_channel::oneshot;
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
use tokio::time::{Duration, Instant, Interval}; use tokio::time::{Duration, Instant, Interval};
use crate::common::{Exec, Future, Pin, Poll, Unpin, task};
use super::Ver; use super::Ver;
use crate::common::{task, Exec, Future, Pin, Poll, Unpin};
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@@ -111,9 +111,7 @@ impl<T> Pool<T> {
None None
}; };
Pool { Pool { inner }
inner,
}
} }
fn is_enabled(&self) -> bool { fn is_enabled(&self) -> bool {
@@ -174,12 +172,7 @@ impl<T: Poolable> Pool<T> {
#[cfg(test)] #[cfg(test)]
fn locked(&self) -> ::std::sync::MutexGuard<'_, PoolInner<T>> { fn locked(&self) -> ::std::sync::MutexGuard<'_, PoolInner<T>> {
self self.inner.as_ref().expect("enabled").lock().expect("lock")
.inner
.as_ref()
.expect("enabled")
.lock()
.expect("lock")
} }
/* Used in client/tests.rs... /* Used in client/tests.rs...
@@ -216,13 +209,13 @@ impl<T: Poolable> Pool<T> {
// Shared reservations don't need a reference to the pool, // Shared reservations don't need a reference to the pool,
// since the pool always keeps a copy. // since the pool always keeps a copy.
(to_return, WeakOpt::none()) (to_return, WeakOpt::none())
}, }
Reservation::Unique(value) => { Reservation::Unique(value) => {
// Unique reservations must take a reference to the pool // Unique reservations must take a reference to the pool
// since they hope to reinsert once the reservation is // since they hope to reinsert once the reservation is
// completed // completed
(value, WeakOpt::downgrade(enabled)) (value, WeakOpt::downgrade(enabled))
}, }
} }
} else { } else {
// If pool is not enabled, skip all the things... // If pool is not enabled, skip all the things...
@@ -236,7 +229,7 @@ impl<T: Poolable> Pool<T> {
key: connecting.key.clone(), key: connecting.key.clone(),
is_reused: false, is_reused: false,
pool: pool_ref, pool: pool_ref,
value: Some(value) value: Some(value),
} }
} }
@@ -299,10 +292,8 @@ impl<'a, T: Poolable + 'a> IdlePopper<'a, T> {
value: to_reinsert, value: to_reinsert,
}); });
to_checkout to_checkout
},
Reservation::Unique(unique) => {
unique
} }
Reservation::Unique(unique) => unique,
}; };
return Some(Idle { return Some(Idle {
@@ -332,7 +323,7 @@ impl<T: Poolable> PoolInner<T> {
Reservation::Shared(to_keep, to_send) => { Reservation::Shared(to_keep, to_send) => {
value = Some(to_keep); value = Some(to_keep);
to_send to_send
}, }
Reservation::Unique(uniq) => uniq, Reservation::Unique(uniq) => uniq,
}; };
match tx.send(reserved) { match tx.send(reserved) {
@@ -342,7 +333,7 @@ impl<T: Poolable> PoolInner<T> {
} else { } else {
continue; continue;
} }
}, }
Err(e) => { Err(e) => {
value = Some(e); value = Some(e);
} }
@@ -361,10 +352,7 @@ impl<T: Poolable> PoolInner<T> {
Some(value) => { Some(value) => {
// borrow-check scope... // borrow-check scope...
{ {
let idle_list = self let idle_list = self.idle.entry(key.clone()).or_insert(Vec::new());
.idle
.entry(key.clone())
.or_insert(Vec::new());
if self.max_idle_per_host <= idle_list.len() { if self.max_idle_per_host <= idle_list.len() {
trace!("max idle per host for {:?}, dropping connection", key); trace!("max idle per host for {:?}, dropping connection", key);
return; return;
@@ -390,10 +378,7 @@ impl<T: Poolable> PoolInner<T> {
/// but the lock is going away, so clean up. /// but the lock is going away, so clean up.
fn connected(&mut self, key: &Key) { fn connected(&mut self, key: &Key) {
let existed = self.connecting.remove(key); let existed = self.connecting.remove(key);
debug_assert!( debug_assert!(existed, "Connecting dropped, key not in pool.connecting");
existed,
"Connecting dropped, key not in pool.connecting"
);
// cancel any waiters. if there are any, it's because // cancel any waiters. if there are any, it's because
// this Connecting task didn't complete successfully. // this Connecting task didn't complete successfully.
// those waiters would never receive a connection. // those waiters would never receive a connection.
@@ -412,7 +397,7 @@ impl<T: Poolable> PoolInner<T> {
self.idle_interval_ref = Some(tx); self.idle_interval_ref = Some(tx);
(dur, rx) (dur, rx)
} else { } else {
return return;
} }
}; };
@@ -434,9 +419,7 @@ impl<T> PoolInner<T> {
fn clean_waiters(&mut self, key: &Key) { fn clean_waiters(&mut self, key: &Key) {
let mut remove_waiters = false; let mut remove_waiters = false;
if let Some(waiters) = self.waiters.get_mut(key) { if let Some(waiters) = self.waiters.get_mut(key) {
waiters.retain(|tx| { waiters.retain(|tx| !tx.is_canceled());
!tx.is_canceled()
});
remove_waiters = waiters.is_empty(); remove_waiters = waiters.is_empty();
} }
if remove_waiters { if remove_waiters {
@@ -547,9 +530,7 @@ impl<T: Poolable> Drop for Pooled<T> {
impl<T: Poolable> fmt::Debug for Pooled<T> { impl<T: Poolable> fmt::Debug for Pooled<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pooled") f.debug_struct("Pooled").field("key", &self.key).finish()
.field("key", &self.key)
.finish()
} }
} }
@@ -567,7 +548,10 @@ pub(super) struct Checkout<T> {
} }
impl<T: Poolable> Checkout<T> { impl<T: Poolable> Checkout<T> {
fn poll_waiter(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Pooled<T>>>> { fn poll_waiter(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<crate::Result<Pooled<T>>>> {
static CANCELED: &str = "pool checkout failed"; static CANCELED: &str = "pool checkout failed";
if let Some(mut rx) = self.waiter.take() { if let Some(mut rx) = self.waiter.take() {
match Pin::new(&mut rx).poll(cx) { match Pin::new(&mut rx).poll(cx) {
@@ -577,12 +561,14 @@ impl<T: Poolable> Checkout<T> {
} else { } else {
Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))) Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED))))
} }
}, }
Poll::Pending => { Poll::Pending => {
self.waiter = Some(rx); self.waiter = Some(rx);
Poll::Pending Poll::Pending
}, }
Poll::Ready(Err(_canceled)) => Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))), Poll::Ready(Err(_canceled)) => {
Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED))))
}
} }
} else { } else {
Poll::Ready(None) Poll::Ready(None)
@@ -593,8 +579,7 @@ impl<T: Poolable> Checkout<T> {
let entry = { let entry = {
let mut inner = self.pool.inner.as_ref()?.lock().unwrap(); let mut inner = self.pool.inner.as_ref()?.lock().unwrap();
let expiration = Expiration::new(inner.timeout); let expiration = Expiration::new(inner.timeout);
let maybe_entry = inner.idle.get_mut(&self.key) let maybe_entry = inner.idle.get_mut(&self.key).and_then(|list| {
.and_then(|list| {
trace!("take? {:?}: expiration = {:?}", self.key, expiration.0); trace!("take? {:?}: expiration = {:?}", self.key, expiration.0);
// A block to end the mutable borrow on list, // A block to end the mutable borrow on list,
// so the map below can check is_empty() // so the map below can check is_empty()
@@ -764,9 +749,7 @@ impl<T> WeakOpt<T> {
} }
fn upgrade(&self) -> Option<Arc<T>> { fn upgrade(&self) -> Option<Arc<T>> {
self.0 self.0.as_ref().and_then(Weak::upgrade)
.as_ref()
.and_then(Weak::upgrade)
} }
} }
@@ -776,8 +759,8 @@ mod tests {
use std::task::Poll; use std::task::Poll;
use std::time::Duration; use std::time::Duration;
use crate::common::{Exec, Future, Pin, task}; use super::{Connecting, Key, Pool, Poolable, Reservation, WeakOpt};
use super::{Connecting, Key, Poolable, Pool, Reservation, WeakOpt}; use crate::common::{task, Exec, Future, Pin};
/// Test unique reservations. /// Test unique reservations.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@@ -809,7 +792,8 @@ mod tests {
} }
fn pool_max_idle_no_timer<T>(max_idle: usize) -> Pool<T> { fn pool_max_idle_no_timer<T>(max_idle: usize) -> Pool<T> {
let pool = Pool::new(super::Config { let pool = Pool::new(
super::Config {
enabled: true, enabled: true,
keep_alive_timeout: Some(Duration::from_millis(100)), keep_alive_timeout: Some(Duration::from_millis(100)),
max_idle_per_host: max_idle, max_idle_per_host: max_idle,
@@ -838,7 +822,8 @@ mod tests {
struct PollOnce<'a, F>(&'a mut F); struct PollOnce<'a, F>(&'a mut F);
impl<F, T, U> Future for PollOnce<'_, F> impl<F, T, U> Future for PollOnce<'_, F>
where F: Future<Output = Result<T, U>> + Unpin where
F: Future<Output = Result<T, U>> + Unpin,
{ {
type Output = Option<()>; type Output = Option<()>;
@@ -846,7 +831,7 @@ mod tests {
match Pin::new(&mut self.0).poll(cx) { match Pin::new(&mut self.0).poll(cx) {
Poll::Ready(Ok(_)) => Poll::Ready(Some(())), Poll::Ready(Ok(_)) => Poll::Ready(Some(())),
Poll::Ready(Err(_)) => Poll::Ready(Some(())), Poll::Ready(Err(_)) => Poll::Ready(Some(())),
Poll::Pending => Poll::Ready(None) Poll::Pending => Poll::Ready(None),
} }
} }
} }
@@ -875,7 +860,10 @@ mod tests {
pool.pooled(c(key.clone()), Uniq(5)); pool.pooled(c(key.clone()), Uniq(5));
pool.pooled(c(key.clone()), Uniq(99)); pool.pooled(c(key.clone()), Uniq(99));
assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); assert_eq!(
pool.locked().idle.get(&key).map(|entries| entries.len()),
Some(3)
);
tokio::time::delay_for(pool.locked().timeout.unwrap()).await; tokio::time::delay_for(pool.locked().timeout.unwrap()).await;
let mut checkout = pool.checkout(key.clone()); let mut checkout = pool.checkout(key.clone());
@@ -895,7 +883,10 @@ mod tests {
pool.pooled(c(key.clone()), Uniq(99)); pool.pooled(c(key.clone()), Uniq(99));
// pooled and dropped 3, max_idle should only allow 2 // pooled and dropped 3, max_idle should only allow 2
assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(2)); assert_eq!(
pool.locked().idle.get(&key).map(|entries| entries.len()),
Some(2)
);
} }
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
@@ -904,7 +895,8 @@ mod tests {
let _ = pretty_env_logger::try_init(); let _ = pretty_env_logger::try_init();
tokio::time::pause(); tokio::time::pause();
let pool = Pool::new(super::Config { let pool = Pool::new(
super::Config {
enabled: true, enabled: true,
keep_alive_timeout: Some(Duration::from_millis(10)), keep_alive_timeout: Some(Duration::from_millis(10)),
max_idle_per_host: ::std::usize::MAX, max_idle_per_host: ::std::usize::MAX,
@@ -918,7 +910,10 @@ mod tests {
pool.pooled(c(key.clone()), Uniq(5)); pool.pooled(c(key.clone()), Uniq(5));
pool.pooled(c(key.clone()), Uniq(99)); pool.pooled(c(key.clone()), Uniq(99));
assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); assert_eq!(
pool.locked().idle.get(&key).map(|entries| entries.len()),
Some(3)
);
// Let the timer tick passed the expiration... // Let the timer tick passed the expiration...
tokio::time::advance(Duration::from_millis(30)).await; tokio::time::advance(Duration::from_millis(30)).await;
@@ -937,17 +932,15 @@ mod tests {
let key = Arc::new("foo".to_string()); let key = Arc::new("foo".to_string());
let pooled = pool.pooled(c(key.clone()), Uniq(41)); let pooled = pool.pooled(c(key.clone()), Uniq(41));
let checkout = join( let checkout = join(pool.checkout(key), async {
pool.checkout(key),
async {
// the checkout future will park first, // the checkout future will park first,
// and then this lazy future will be polled, which will insert // and then this lazy future will be polled, which will insert
// the pooled back into the pool // the pooled back into the pool
// //
// this test makes sure that doing so will unpark the checkout // this test makes sure that doing so will unpark the checkout
drop(pooled); drop(pooled);
}, })
).map(|(entry, _)| entry); .map(|(entry, _)| entry);
assert_eq!(*checkout.await.unwrap(), Uniq(41)); assert_eq!(*checkout.await.unwrap(), Uniq(41));
} }
@@ -1001,10 +994,13 @@ mod tests {
fn pooled_drop_if_closed_doesnt_reinsert() { fn pooled_drop_if_closed_doesnt_reinsert() {
let pool = pool_no_timer(); let pool = pool_no_timer();
let key = Arc::new("localhost:12345".to_string()); let key = Arc::new("localhost:12345".to_string());
pool.pooled(c(key.clone()), CanClose { pool.pooled(
c(key.clone()),
CanClose {
val: 57, val: 57,
closed: true, closed: true,
}); },
);
assert!(!pool.locked().idle.contains_key(&key)); assert!(!pool.locked().idle.contains_key(&key));
} }

View File

@@ -2,12 +2,16 @@
//! //!
//! This module provides `Connect` which hook-ins into the Tower ecosystem. //! This module provides `Connect` which hook-ins into the Tower ecosystem.
use std::marker::PhantomData;
use std::future::Future;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::future::Future;
use std::marker::PhantomData;
use crate::{common::{Poll, task, Pin}, body::Payload, service::{MakeConnection, Service}}; use super::conn::{Builder, SendRequest};
use super::conn::{SendRequest, Builder}; use crate::{
body::Payload,
common::{task, Pin, Poll},
service::{MakeConnection, Service},
};
/// Creates a connection via `SendRequest`. /// Creates a connection via `SendRequest`.
/// ///
@@ -18,7 +22,7 @@ use super::conn::{SendRequest, Builder};
pub struct Connect<C, B, T> { pub struct Connect<C, B, T> {
inner: C, inner: C,
builder: Builder, builder: Builder,
_pd: PhantomData<fn(T, B)> _pd: PhantomData<fn(T, B)>,
} }
impl<C, B, T> Connect<C, B, T> { impl<C, B, T> Connect<C, B, T> {
@@ -28,7 +32,7 @@ impl<C, B, T> Connect<C, B, T> {
Self { Self {
inner, inner,
builder, builder,
_pd: PhantomData _pd: PhantomData,
} }
} }
} }
@@ -44,10 +48,13 @@ where
{ {
type Response = SendRequest<B>; type Response = SendRequest<B>;
type Error = crate::Error; type Error = crate::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>; type Future =
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx).map_err(|e| crate::Error::new(crate::error::Kind::Connect).with(e.into())) self.inner
.poll_ready(cx)
.map_err(|e| crate::Error::new(crate::error::Kind::Connect).with(e.into()))
} }
fn call(&mut self, req: T) -> Self::Future { fn call(&mut self, req: T) -> Self::Future {
@@ -56,8 +63,7 @@ where
let fut = async move { let fut = async move {
match io.await { match io.await {
Ok(io) => { Ok(io) => match builder.handshake(io).await {
match builder.handshake(io).await {
Ok((sr, conn)) => { Ok((sr, conn)) => {
builder.exec.execute(async move { builder.exec.execute(async move {
if let Err(e) = conn.await { if let Err(e) = conn.await {
@@ -65,9 +71,8 @@ where
} }
}); });
Ok(sr) Ok(sr)
},
Err(e) => Err(e)
} }
Err(e) => Err(e),
}, },
Err(e) => { Err(e) => {
let err = crate::Error::new(crate::error::Kind::Connect).with(e.into()); let err = crate::Error::new(crate::error::Kind::Connect).with(e.into());

View File

@@ -1,9 +1,9 @@
use std::mem; use std::mem;
use tokio::sync::{mpsc, watch};
use pin_project::pin_project; use pin_project::pin_project;
use tokio::sync::{mpsc, watch};
use super::{Future, Never, Poll, Pin, task}; use super::{task, Future, Never, Pin, Poll};
// Sentinel value signaling that the watch is still open // Sentinel value signaling that the watch is still open
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@@ -21,10 +21,7 @@ pub fn channel() -> (Signal, Watch) {
drained_rx, drained_rx,
_tx: tx, _tx: tx,
}, },
Watch { Watch { drained_tx, rx },
drained_tx,
rx,
},
) )
} }
@@ -107,17 +104,14 @@ where
Poll::Ready(None) => { Poll::Ready(None) => {
// Drain has been triggered! // Drain has been triggered!
on_drain(me.future.as_mut()); on_drain(me.future.as_mut());
}, }
Poll::Ready(Some(_/*State::Open*/)) | Poll::Ready(Some(_ /*State::Open*/)) | Poll::Pending => {
Poll::Pending => {
*me.state = State::Watch(on_drain); *me.state = State::Watch(on_drain);
return me.future.poll(cx); return me.future.poll(cx);
},
} }
}, }
State::Draining => { }
return me.future.poll(cx) State::Draining => return me.future.poll(cx),
},
} }
} }
} }
@@ -236,4 +230,3 @@ mod tests {
}); });
} }
} }

View File

@@ -3,7 +3,7 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use crate::body::{Payload, Body}; use crate::body::{Body, Payload};
use crate::proto::h2::server::H2Stream; use crate::proto::h2::server::H2Stream;
use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; use crate::server::conn::spawn_all::{NewSvcTask, Watcher};
use crate::service::HttpService; use crate::service::HttpService;
@@ -50,22 +50,20 @@ impl Exec {
// If no runtime, we need an executor! // If no runtime, we need an executor!
panic!("executor must be set") panic!("executor must be set")
} }
}, }
Exec::Executor(ref e) => { Exec::Executor(ref e) => {
e.execute(Box::pin(fut)); e.execute(Box::pin(fut));
}, }
} }
} }
} }
impl fmt::Debug for Exec { impl fmt::Debug for Exec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Exec") f.debug_struct("Exec").finish()
.finish()
} }
} }
impl<F, B> H2Exec<F, B> for Exec impl<F, B> H2Exec<F, B> for Exec
where where
H2Stream<F, B>: Future<Output = ()> + Send + 'static, H2Stream<F, B>: Future<Output = ()> + Send + 'static,
@@ -111,4 +109,3 @@ where
self.execute(fut) self.execute(fut)
} }
} }

View File

@@ -1,10 +1,10 @@
use std::{cmp, io};
use std::marker::Unpin; use std::marker::Unpin;
use std::{cmp, io};
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, task}; use crate::common::{task, Pin, Poll};
/// Combine a buffer with an IO, rewinding reads to use the buffer. /// Combine a buffer with an IO, rewinding reads to use the buffer.
#[derive(Debug)] #[derive(Debug)]
@@ -47,7 +47,11 @@ where
self.inner.prepare_uninitialized_buffer(buf) self.inner.prepare_uninitialized_buffer(buf)
} }
fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
if let Some(mut prefix) = self.pre.take() { if let Some(mut prefix) = self.pre.take() {
// If there are no remaining bytes, let the bytes get dropped. // If there are no remaining bytes, let the bytes get dropped.
if prefix.len() > 0 { if prefix.len() > 0 {
@@ -69,7 +73,11 @@ impl<T> AsyncWrite for Rewind<T>
where where
T: AsyncWrite + Unpin, T: AsyncWrite + Unpin,
{ {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write(cx, buf) Pin::new(&mut self.inner).poll_write(cx, buf)
} }
@@ -82,7 +90,11 @@ where
} }
#[inline] #[inline]
fn poll_write_buf<B: Buf>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { fn poll_write_buf<B: Buf>(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut B,
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write_buf(cx, buf) Pin::new(&mut self.inner).poll_write_buf(cx, buf)
} }
} }
@@ -91,36 +103,27 @@ where
mod tests { mod tests {
// FIXME: re-implement tests with `async/await`, this import should // FIXME: re-implement tests with `async/await`, this import should
// trigger a warning to remind us // trigger a warning to remind us
use super::Rewind;
use bytes::Bytes; use bytes::Bytes;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use super::Rewind;
#[tokio::test] #[tokio::test]
async fn partial_rewind() { async fn partial_rewind() {
let underlying = [104, 101, 108, 108, 111]; let underlying = [104, 101, 108, 108, 111];
let mock = tokio_test::io::Builder::new() let mock = tokio_test::io::Builder::new().read(&underlying).build();
.read(&underlying)
.build();
let mut stream = Rewind::new(mock); let mut stream = Rewind::new(mock);
// Read off some bytes, ensure we filled o1 // Read off some bytes, ensure we filled o1
let mut buf = [0; 2]; let mut buf = [0; 2];
stream stream.read_exact(&mut buf).await.expect("read1");
.read_exact(&mut buf)
.await
.expect("read1");
// Rewind the stream so that it is as if we never read in the first place. // Rewind the stream so that it is as if we never read in the first place.
stream.rewind(Bytes::copy_from_slice(&buf[..])); stream.rewind(Bytes::copy_from_slice(&buf[..]));
let mut buf = [0; 5]; let mut buf = [0; 5];
stream stream.read_exact(&mut buf).await.expect("read1");
.read_exact(&mut buf)
.await
.expect("read1");
// At this point we should have read everything that was in the MockStream // At this point we should have read everything that was in the MockStream
assert_eq!(&buf, &underlying); assert_eq!(&buf, &underlying);
@@ -130,26 +133,17 @@ mod tests {
async fn full_rewind() { async fn full_rewind() {
let underlying = [104, 101, 108, 108, 111]; let underlying = [104, 101, 108, 108, 111];
let mock = tokio_test::io::Builder::new() let mock = tokio_test::io::Builder::new().read(&underlying).build();
.read(&underlying)
.build();
let mut stream = Rewind::new(mock); let mut stream = Rewind::new(mock);
let mut buf = [0; 5]; let mut buf = [0; 5];
stream stream.read_exact(&mut buf).await.expect("read1");
.read_exact(&mut buf)
.await
.expect("read1");
// Rewind the stream so that it is as if we never read in the first place. // Rewind the stream so that it is as if we never read in the first place.
stream.rewind(Bytes::copy_from_slice(&buf[..])); stream.rewind(Bytes::copy_from_slice(&buf[..]));
let mut buf = [0; 5]; let mut buf = [0; 5];
stream stream.read_exact(&mut buf).await.expect("read1");
.read_exact(&mut buf)
.await
.expect("read1");
} }
} }

View File

@@ -1,6 +1,6 @@
use std::mem; use std::mem;
use super::{Future, Pin, Poll, task}; use super::{task, Future, Pin, Poll};
pub(crate) trait Started: Future { pub(crate) trait Started: Future {
fn started(&self) -> bool; fn started(&self) -> bool;
@@ -19,7 +19,7 @@ where
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub(crate) struct Lazy<F, R> { pub(crate) struct Lazy<F, R> {
inner: Inner<F, R> inner: Inner<F, R>,
} }
enum Inner<F, R> { enum Inner<F, R> {
@@ -36,8 +36,7 @@ where
fn started(&self) -> bool { fn started(&self) -> bool {
match self.inner { match self.inner {
Inner::Init(_) => false, Inner::Init(_) => false,
Inner::Fut(_) | Inner::Fut(_) | Inner::Empty => true,
Inner::Empty => true,
} }
} }
} }
@@ -61,7 +60,7 @@ where
let ret = Pin::new(&mut fut).poll(cx); let ret = Pin::new(&mut fut).poll(cx);
self.inner = Inner::Fut(fut); self.inner = Inner::Fut(fut);
ret ret
}, }
_ => unreachable!("lazy state wrong"), _ => unreachable!("lazy state wrong"),
} }
} }
@@ -69,4 +68,3 @@ where
// The closure `F` is never pinned // The closure `F` is never pinned
impl<F, R: Unpin> Unpin for Lazy<F, R> {} impl<F, R: Unpin> Unpin for Lazy<F, R> {}

View File

@@ -1,10 +1,10 @@
macro_rules! ready { macro_rules! ready {
($e:expr) => ( ($e:expr) => {
match $e { match $e {
::std::task::Poll::Ready(v) => v, ::std::task::Poll::Ready(v) => v,
::std::task::Poll::Pending => return ::std::task::Poll::Pending, ::std::task::Poll::Pending => return ::std::task::Poll::Pending,
} }
) };
} }
pub(crate) mod drain; pub(crate) mod drain;
@@ -14,16 +14,11 @@ mod lazy;
mod never; mod never;
pub(crate) mod task; pub(crate) mod task;
pub(crate) use self::exec::{BoxSendFuture, Exec};
pub use self::exec::Executor; pub use self::exec::Executor;
pub(crate) use self::exec::{BoxSendFuture, Exec};
pub(crate) use self::lazy::{lazy, Started as Lazy}; pub(crate) use self::lazy::{lazy, Started as Lazy};
pub use self::never::Never; pub use self::never::Never;
pub(crate) use self::task::Poll; pub(crate) use self::task::Poll;
// group up types normally needed for `Future` // group up types normally needed for `Future`
pub(crate) use std::{ pub(crate) use std::{future::Future, marker::Unpin, pin::Pin};
future::Future,
marker::Unpin,
pin::Pin,
};

View File

@@ -19,4 +19,3 @@ impl Error for Never {
match *self {} match *self {}
} }
} }

View File

@@ -1,5 +1,5 @@
pub(crate) use std::task::{Context, Poll};
use super::Never; use super::Never;
pub(crate) use std::task::{Context, Poll};
/// A function to help "yield" a future, such that it is re-scheduled immediately. /// A function to help "yield" a future, such that it is re-scheduled immediately.
/// ///

View File

@@ -140,10 +140,7 @@ impl Error {
pub(crate) fn new(kind: Kind) -> Error { pub(crate) fn new(kind: Kind) -> Error {
Error { Error {
inner: Box::new(ErrorImpl { inner: Box::new(ErrorImpl { kind, cause: None }),
kind,
cause: None,
}),
} }
} }
@@ -162,9 +159,7 @@ impl Error {
let mut cause = self.source(); let mut cause = self.source();
while let Some(err) = cause { while let Some(err) = cause {
if let Some(h2_err) = err.downcast_ref::<h2::Error>() { if let Some(h2_err) = err.downcast_ref::<h2::Error>() {
return h2_err return h2_err.reason().unwrap_or(h2::Reason::INTERNAL_ERROR);
.reason()
.unwrap_or(h2::Reason::INTERNAL_ERROR);
} }
cause = err.source(); cause = err.source();
} }
@@ -335,7 +330,9 @@ impl StdError for Error {
Kind::User(User::UnexpectedHeader) => "user sent unexpected header", Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version", Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version",
Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method", Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
Kind::User(User::UnsupportedStatusCode) => "response has 1xx status code, not supported by server", Kind::User(User::UnsupportedStatusCode) => {
"response has 1xx status code, not supported by server"
}
Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs", Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs",
Kind::User(User::NoUpgrade) => "no upgrade available", Kind::User(User::NoUpgrade) => "no upgrade available",
Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use", Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
@@ -343,8 +340,7 @@ impl StdError for Error {
} }
fn source(&self) -> Option<&(dyn StdError + 'static)> { fn source(&self) -> Option<&(dyn StdError + 'static)> {
self self.inner
.inner
.cause .cause
.as_ref() .as_ref()
.map(|cause| &**cause as &(dyn StdError + 'static)) .map(|cause| &**cause as &(dyn StdError + 'static))
@@ -361,10 +357,10 @@ impl From<Parse> for Error {
impl From<httparse::Error> for Parse { impl From<httparse::Error> for Parse {
fn from(err: httparse::Error) -> Parse { fn from(err: httparse::Error) -> Parse {
match err { match err {
httparse::Error::HeaderName | httparse::Error::HeaderName
httparse::Error::HeaderValue | | httparse::Error::HeaderValue
httparse::Error::NewLine | | httparse::Error::NewLine
httparse::Error::Token => Parse::Header, | httparse::Error::Token => Parse::Header,
httparse::Error::Status => Parse::Status, httparse::Error::Status => Parse::Status,
httparse::Error::TooManyHeaders => Parse::TooLarge, httparse::Error::TooManyHeaders => Parse::TooLarge,
httparse::Error::Version => Parse::Version, httparse::Error::Version => Parse::Version,
@@ -403,8 +399,8 @@ impl AssertSendSync for Error {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::mem;
use super::*; use super::*;
use std::mem;
#[test] #[test]
fn error_size_of() { fn error_size_of() {

View File

@@ -1,7 +1,7 @@
use bytes::BytesMut; use bytes::BytesMut;
use http::HeaderMap;
use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING};
use http::header::{HeaderValue, OccupiedEntry, ValueIter}; use http::header::{HeaderValue, OccupiedEntry, ValueIter};
use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING};
use http::HeaderMap;
pub fn connection_keep_alive(value: &HeaderValue) -> bool { pub fn connection_keep_alive(value: &HeaderValue) -> bool {
connection_has(value, "keep-alive") connection_has(value, "keep-alive")
@@ -23,10 +23,7 @@ fn connection_has(value: &HeaderValue, needle: &str) -> bool {
} }
pub fn content_length_parse(value: &HeaderValue) -> Option<u64> { pub fn content_length_parse(value: &HeaderValue) -> Option<u64> {
value value.to_str().ok().and_then(|s| s.parse().ok())
.to_str()
.ok()
.and_then(|s| s.parse().ok())
} }
pub fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> { pub fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> {
@@ -38,21 +35,18 @@ pub fn content_length_parse_all_values(values: ValueIter<'_, HeaderValue>) -> Op
// be alright if they all contain the same value, and all parse // be alright if they all contain the same value, and all parse
// correctly. If not, then it's an error. // correctly. If not, then it's an error.
let folded = values let folded = values.fold(None, |prev, line| match prev {
.fold(None, |prev, line| match prev { Some(Ok(prev)) => Some(
Some(Ok(prev)) => { line.to_str()
Some(line
.to_str()
.map_err(|_| ()) .map_err(|_| ())
.and_then(|s| s.parse().map_err(|_| ())) .and_then(|s| s.parse().map_err(|_| ()))
.and_then(|n| if prev == n { Ok(n) } else { Err(()) })) .and_then(|n| if prev == n { Ok(n) } else { Err(()) }),
}, ),
None => { None => Some(
Some(line line.to_str()
.to_str()
.map_err(|_| ()) .map_err(|_| ())
.and_then(|s| s.parse().map_err(|_| ()))) .and_then(|s| s.parse().map_err(|_| ())),
}, ),
Some(Err(())) => Some(Err(())), Some(Err(())) => Some(Err(())),
}); });

View File

@@ -29,38 +29,31 @@
//! TCP (using tokio). //! TCP (using tokio).
//! - `stream` (*enabled by default*): Provides `futures::Stream` capabilities. //! - `stream` (*enabled by default*): Provides `futures::Stream` capabilities.
#[doc(hidden)] pub use http; #[doc(hidden)]
#[macro_use] extern crate log; pub use http;
#[macro_use]
extern crate log;
#[cfg(all(test, feature = "nightly"))] #[cfg(all(test, feature = "nightly"))]
extern crate test; extern crate test;
pub use http::{ pub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version};
header,
HeaderMap,
Method,
Request,
Response,
StatusCode,
Uri,
Version,
};
pub use crate::client::Client;
pub use crate::error::{Result, Error};
pub use crate::body::{Body, Chunk}; pub use crate::body::{Body, Chunk};
pub use crate::client::Client;
pub use crate::error::{Error, Result};
pub use crate::server::Server; pub use crate::server::Server;
#[macro_use] #[macro_use]
mod common; mod common;
#[cfg(test)]
mod mock;
pub mod body; pub mod body;
pub mod client; pub mod client;
pub mod error; pub mod error;
mod headers; mod headers;
#[cfg(test)]
mod mock;
mod proto; mod proto;
pub mod rt;
pub mod server; pub mod server;
pub mod service; pub mod service;
pub mod rt;
pub mod upgrade; pub mod upgrade;

View File

@@ -3,16 +3,16 @@ use std::io::{self};
use std::marker::PhantomData; use std::marker::PhantomData;
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use http::{HeaderMap, Method, Version};
use http::header::{HeaderValue, CONNECTION}; use http::header::{HeaderValue, CONNECTION};
use http::{HeaderMap, Method, Version};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use crate::Chunk; use super::io::Buffered;
use crate::common::{Pin, Poll, Unpin, task}; use super::{/*Decode,*/ Decoder, Encode, EncodedBuf, Encoder, Http1Transaction, ParseContext,};
use crate::proto::{BodyLength, DecodedLength, MessageHead}; use crate::common::{task, Pin, Poll, Unpin};
use crate::headers::connection_keep_alive; use crate::headers::connection_keep_alive;
use super::io::{Buffered}; use crate::proto::{BodyLength, DecodedLength, MessageHead};
use super::{EncodedBuf, Encode, Encoder, /*Decode,*/ Decoder, Http1Transaction, ParseContext}; use crate::Chunk;
const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
@@ -26,11 +26,12 @@ const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
pub(crate) struct Conn<I, B, T> { pub(crate) struct Conn<I, B, T> {
io: Buffered<I, EncodedBuf<B>>, io: Buffered<I, EncodedBuf<B>>,
state: State, state: State,
_marker: PhantomData<fn(T)> _marker: PhantomData<fn(T)>,
} }
impl<I, B, T> Conn<I, B, T> impl<I, B, T> Conn<I, B, T>
where I: AsyncRead + AsyncWrite + Unpin, where
I: AsyncRead + AsyncWrite + Unpin,
B: Buf, B: Buf,
T: Http1Transaction, T: Http1Transaction,
{ {
@@ -107,7 +108,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
_ => true, _ => true,
} }
} }
}, }
_ => false, _ => false,
} }
} }
@@ -129,14 +130,20 @@ where I: AsyncRead + AsyncWrite + Unpin,
read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE
} }
pub fn poll_read_head(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<(MessageHead<T::Incoming>, DecodedLength, bool)>>> { pub fn poll_read_head(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<crate::Result<(MessageHead<T::Incoming>, DecodedLength, bool)>>> {
debug_assert!(self.can_read_head()); debug_assert!(self.can_read_head());
trace!("Conn::read_head"); trace!("Conn::read_head");
let msg = match ready!(self.io.parse::<T>(cx, ParseContext { let msg = match ready!(self.io.parse::<T>(
cx,
ParseContext {
cached_headers: &mut self.state.cached_headers, cached_headers: &mut self.state.cached_headers,
req_method: &mut self.state.method, req_method: &mut self.state.method,
})) { }
)) {
Ok(msg) => msg, Ok(msg) => msg,
Err(e) => return self.on_read_head_error(e), Err(e) => return self.on_read_head_error(e),
}; };
@@ -179,11 +186,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty(); let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty();
if was_mid_parse || must_error { if was_mid_parse || must_error {
// We check if the buf contains the h2 Preface // We check if the buf contains the h2 Preface
debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len()); debug!(
"parse error ({}) with {} bytes",
e,
self.io.read_buf().len()
);
match self.on_parse_error(e) { match self.on_parse_error(e) {
Ok(()) => Poll::Pending, // XXX: wat? Ok(()) => Poll::Pending, // XXX: wat?
Err(e) => Poll::Ready(Some(Err(e))), Err(e) => Poll::Ready(Some(Err(e))),
} }
} else { } else {
debug!("read eof"); debug!("read eof");
@@ -192,7 +202,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
} }
} }
pub fn poll_read_body(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<io::Result<Chunk>>> { pub fn poll_read_body(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<io::Result<Chunk>>> {
debug_assert!(self.can_read_body()); debug_assert!(self.can_read_body());
let (reading, ret) = match self.state.reading { let (reading, ret) = match self.state.reading {
@@ -201,11 +214,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
Poll::Ready(Ok(slice)) => { Poll::Ready(Ok(slice)) => {
let (reading, chunk) = if decoder.is_eof() { let (reading, chunk) = if decoder.is_eof() {
debug!("incoming body completed"); debug!("incoming body completed");
(Reading::KeepAlive, if !slice.is_empty() { (
Reading::KeepAlive,
if !slice.is_empty() {
Some(Ok(Chunk::from(slice))) Some(Ok(Chunk::from(slice)))
} else { } else {
None None
}) },
)
} else if slice.is_empty() { } else if slice.is_empty() {
error!("incoming body unexpectedly ended"); error!("incoming body unexpectedly ended");
// This should be unreachable, since all 3 decoders // This should be unreachable, since all 3 decoders
@@ -216,14 +232,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
return Poll::Ready(Some(Ok(Chunk::from(slice)))); return Poll::Ready(Some(Ok(Chunk::from(slice))));
}; };
(reading, Poll::Ready(chunk)) (reading, Poll::Ready(chunk))
}, }
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => { Poll::Ready(Err(e)) => {
debug!("incoming body decode error: {}", e); debug!("incoming body decode error: {}", e);
(Reading::Closed, Poll::Ready(Some(Err(e)))) (Reading::Closed, Poll::Ready(Some(Err(e))))
},
} }
}, }
}
_ => unreachable!("read_body invalid state: {:?}", self.state.reading), _ => unreachable!("read_body invalid state: {:?}", self.state.reading),
}; };
@@ -287,7 +303,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
return ret; return ret;
} }
debug!("received unexpected {} bytes on an idle connection", num_read); debug!(
"received unexpected {} bytes on an idle connection",
num_read
);
Poll::Ready(Err(crate::Error::new_unexpected_message())) Poll::Ready(Err(crate::Error::new_unexpected_message()))
} }
@@ -321,27 +340,20 @@ where I: AsyncRead + AsyncWrite + Unpin,
})) }))
} }
fn maybe_notify(&mut self, cx: &mut task::Context<'_>) { fn maybe_notify(&mut self, cx: &mut task::Context<'_>) {
// its possible that we returned NotReady from poll() without having // its possible that we returned NotReady from poll() without having
// exhausted the underlying Io. We would have done this when we // exhausted the underlying Io. We would have done this when we
// determined we couldn't keep reading until we knew how writing // determined we couldn't keep reading until we knew how writing
// would finish. // would finish.
match self.state.reading { match self.state.reading {
Reading::Body(..) | Reading::Body(..) | Reading::KeepAlive | Reading::Closed => return,
Reading::KeepAlive |
Reading::Closed => return,
Reading::Init => (), Reading::Init => (),
}; };
match self.state.writing { match self.state.writing {
Writing::Body(..) => return, Writing::Body(..) => return,
Writing::Init | Writing::Init | Writing::KeepAlive | Writing::Closed => (),
Writing::KeepAlive |
Writing::Closed => (),
} }
if !self.io.is_read_blocked() { if !self.io.is_read_blocked() {
@@ -357,11 +369,11 @@ where I: AsyncRead + AsyncWrite + Unpin,
} }
return; return;
} }
}, }
Poll::Pending => { Poll::Pending => {
trace!("maybe_notify; read_from_io blocked"); trace!("maybe_notify; read_from_io blocked");
return return;
}, }
Poll::Ready(Err(e)) => { Poll::Ready(Err(e)) => {
trace!("maybe_notify; read_from_io error: {}", e); trace!("maybe_notify; read_from_io error: {}", e);
self.state.close(); self.state.close();
@@ -382,21 +394,19 @@ where I: AsyncRead + AsyncWrite + Unpin,
if !T::should_read_first() { if !T::should_read_first() {
match self.state.reading { match self.state.reading {
Reading::Closed => return false, Reading::Closed => return false,
_ => {}, _ => {}
} }
} }
match self.state.writing { match self.state.writing {
Writing::Init => true, Writing::Init => true,
_ => false _ => false,
} }
} }
pub fn can_write_body(&self) -> bool { pub fn can_write_body(&self) -> bool {
match self.state.writing { match self.state.writing {
Writing::Body(..) => true, Writing::Body(..) => true,
Writing::Init | Writing::Init | Writing::KeepAlive | Writing::Closed => false,
Writing::KeepAlive |
Writing::Closed => false,
} }
} }
@@ -417,7 +427,9 @@ where I: AsyncRead + AsyncWrite + Unpin,
} }
pub fn write_full_msg(&mut self, head: MessageHead<T::Outgoing>, body: B) { pub fn write_full_msg(&mut self, head: MessageHead<T::Outgoing>, body: B) {
if let Some(encoder) = self.encode_head(head, Some(BodyLength::Known(body.remaining() as u64))) { if let Some(encoder) =
self.encode_head(head, Some(BodyLength::Known(body.remaining() as u64)))
{
let is_last = encoder.is_last(); let is_last = encoder.is_last();
// Make sure we don't write a body if we weren't actually allowed // Make sure we don't write a body if we weren't actually allowed
// to do so, like because its a HEAD request. // to do so, like because its a HEAD request.
@@ -432,7 +444,11 @@ where I: AsyncRead + AsyncWrite + Unpin,
} }
} }
fn encode_head(&mut self, mut head: MessageHead<T::Outgoing>, body: Option<BodyLength>) -> Option<Encoder> { fn encode_head(
&mut self,
mut head: MessageHead<T::Outgoing>,
body: Option<BodyLength>,
) -> Option<Encoder> {
debug_assert!(self.can_write_head()); debug_assert!(self.can_write_head());
if !T::should_read_first() { if !T::should_read_first() {
@@ -442,24 +458,27 @@ where I: AsyncRead + AsyncWrite + Unpin,
self.enforce_version(&mut head); self.enforce_version(&mut head);
let buf = self.io.headers_buf(); let buf = self.io.headers_buf();
match T::encode(Encode { match T::encode(
Encode {
head: &mut head, head: &mut head,
body, body,
keep_alive: self.state.wants_keep_alive(), keep_alive: self.state.wants_keep_alive(),
req_method: &mut self.state.method, req_method: &mut self.state.method,
title_case_headers: self.state.title_case_headers, title_case_headers: self.state.title_case_headers,
}, buf) { },
buf,
) {
Ok(encoder) => { Ok(encoder) => {
debug_assert!(self.state.cached_headers.is_none()); debug_assert!(self.state.cached_headers.is_none());
debug_assert!(head.headers.is_empty()); debug_assert!(head.headers.is_empty());
self.state.cached_headers = Some(head.headers); self.state.cached_headers = Some(head.headers);
Some(encoder) Some(encoder)
}, }
Err(err) => { Err(err) => {
self.state.error = Some(err); self.state.error = Some(err);
self.state.writing = Writing::Closed; self.state.writing = Writing::Closed;
None None
}, }
} }
} }
@@ -478,10 +497,12 @@ where I: AsyncRead + AsyncWrite + Unpin,
Version::HTTP_10 => self.state.disable_keep_alive(), Version::HTTP_10 => self.state.disable_keep_alive(),
// If response is version 1.1 and keep-alive is wanted, add // If response is version 1.1 and keep-alive is wanted, add
// Connection: keep-alive header when not present // Connection: keep-alive header when not present
Version::HTTP_11 => if self.state.wants_keep_alive() { Version::HTTP_11 => {
if self.state.wants_keep_alive() {
head.headers head.headers
.insert(CONNECTION, HeaderValue::from_static("keep-alive")); .insert(CONNECTION, HeaderValue::from_static("keep-alive"));
}, }
}
_ => (), _ => (),
} }
} }
@@ -490,7 +511,6 @@ where I: AsyncRead + AsyncWrite + Unpin,
// If we know the remote speaks an older version, we try to fix up any messages // If we know the remote speaks an older version, we try to fix up any messages
// to work with our older peer. // to work with our older peer.
fn enforce_version(&mut self, head: &mut MessageHead<T::Outgoing>) { fn enforce_version(&mut self, head: &mut MessageHead<T::Outgoing>) {
match self.state.version { match self.state.version {
Version::HTTP_10 => { Version::HTTP_10 => {
// Fixes response or connection when keep-alive header is not present // Fixes response or connection when keep-alive header is not present
@@ -498,7 +518,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
// If the remote only knows HTTP/1.0, we should force ourselves // If the remote only knows HTTP/1.0, we should force ourselves
// to do only speak HTTP/1.0 as well. // to do only speak HTTP/1.0 as well.
head.version = Version::HTTP_10; head.version = Version::HTTP_10;
}, }
_ => { _ => {
// If the remote speaks HTTP/1.1, then it *should* be fine with // If the remote speaks HTTP/1.1, then it *should* be fine with
// both HTTP/1.0 and HTTP/1.1 from us. So again, we just let // both HTTP/1.0 and HTTP/1.1 from us. So again, we just let
@@ -525,7 +545,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else { } else {
return; return;
} }
}, }
_ => unreachable!("write_body invalid state: {:?}", self.state.writing), _ => unreachable!("write_body invalid state: {:?}", self.state.writing),
}; };
@@ -545,7 +565,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else { } else {
Writing::Closed Writing::Closed
} }
}, }
_ => unreachable!("write_body invalid state: {:?}", self.state.writing), _ => unreachable!("write_body invalid state: {:?}", self.state.writing),
}; };
@@ -568,15 +588,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else { } else {
Writing::KeepAlive Writing::KeepAlive
} }
}, }
Err(_not_eof) => Writing::Closed, Err(_not_eof) => Writing::Closed,
} }
}, }
_ => return, _ => return,
}; };
self.state.writing = state; self.state.writing = state;
} }
// When we get a parse error, depending on what side we are, we might be able // When we get a parse error, depending on what side we are, we might be able
@@ -585,11 +604,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
// - Client: there is nothing we can do // - Client: there is nothing we can do
// - Server: if Response hasn't been written yet, we can send a 4xx response // - Server: if Response hasn't been written yet, we can send a 4xx response
fn on_parse_error(&mut self, err: crate::Error) -> crate::Result<()> { fn on_parse_error(&mut self, err: crate::Error) -> crate::Result<()> {
match self.state.writing { match self.state.writing {
Writing::Init => { Writing::Init => {
if self.has_h2_prefix() { if self.has_h2_prefix() {
return Err(crate::Error::new_version_h2()) return Err(crate::Error::new_version_h2());
} }
if let Some(msg) = T::on_error(&err) { if let Some(msg) = T::on_error(&err) {
// Drop the cached headers so as to not trigger a debug // Drop the cached headers so as to not trigger a debug
@@ -619,7 +637,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
Ok(()) => { Ok(()) => {
trace!("shut down IO complete"); trace!("shut down IO complete");
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
}, }
Err(e) => { Err(e) => {
debug!("error shutting down IO: {}", e); debug!("error shutting down IO: {}", e);
Poll::Ready(Err(e)) Poll::Ready(Err(e))
@@ -741,9 +759,7 @@ impl fmt::Debug for Writing {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
Writing::Init => f.write_str("Init"), Writing::Init => f.write_str("Init"),
Writing::Body(ref enc) => f.debug_tuple("Body") Writing::Body(ref enc) => f.debug_tuple("Body").field(enc).finish(),
.field(enc)
.finish(),
Writing::KeepAlive => f.write_str("KeepAlive"), Writing::KeepAlive => f.write_str("KeepAlive"),
Writing::Closed => f.write_str("Closed"), Writing::Closed => f.write_str("Closed"),
} }
@@ -824,15 +840,18 @@ impl State {
if let KA::Busy = self.keep_alive.status() { if let KA::Busy = self.keep_alive.status() {
self.idle::<T>(); self.idle::<T>();
} else { } else {
trace!("try_keep_alive({}): could keep-alive, but status = {:?}", T::LOG, self.keep_alive); trace!(
"try_keep_alive({}): could keep-alive, but status = {:?}",
T::LOG,
self.keep_alive
);
self.close(); self.close();
} }
}, }
(&Reading::Closed, &Writing::KeepAlive) | (&Reading::Closed, &Writing::KeepAlive) | (&Reading::KeepAlive, &Writing::Closed) => {
(&Reading::KeepAlive, &Writing::Closed) => {
self.close() self.close()
} }
_ => () _ => (),
} }
} }
@@ -880,14 +899,14 @@ impl State {
fn is_read_closed(&self) -> bool { fn is_read_closed(&self) -> bool {
match self.reading { match self.reading {
Reading::Closed => true, Reading::Closed => true,
_ => false _ => false,
} }
} }
fn is_write_closed(&self) -> bool { fn is_write_closed(&self) -> bool {
match self.writing { match self.writing {
Writing::Closed => true, Writing::Closed => true,
_ => false _ => false,
} }
} }
@@ -929,10 +948,9 @@ mod tests {
let mut headers = x.0.headers; let mut headers = x.0.headers;
headers.clear(); headers.clear();
conn.state.cached_headers = Some(headers); conn.state.cached_headers = Some(headers);
},
f => panic!("expected Ready(Some(Ok(..))): {:?}", f)
} }
f => panic!("expected Ready(Some(Ok(..))): {:?}", f),
}
conn.io.read_buf_mut().reserve(1); conn.io.read_buf_mut().reserve(1);
unsafe { unsafe {

View File

@@ -24,8 +24,7 @@ pub(crate) fn update_and_header_value() -> HeaderValue {
CACHED.with(|cache| { CACHED.with(|cache| {
let mut cache = cache.borrow_mut(); let mut cache = cache.borrow_mut();
cache.check(); cache.check();
HeaderValue::from_bytes(cache.buffer()) HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
.expect("Date format should be valid HeaderValue")
}) })
} }

View File

@@ -1,16 +1,16 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
use std::usize;
use std::io; use std::io;
use std::usize;
use bytes::Bytes; use bytes::Bytes;
use crate::common::{Poll, task}; use crate::common::{task, Poll};
use super::io::MemRead; use super::io::MemRead;
use super::{DecodedLength}; use super::DecodedLength;
use self::Kind::{Length, Chunked, Eof}; use self::Kind::{Chunked, Eof, Length};
/// Decoders to handle different Transfer-Encodings. /// Decoders to handle different Transfer-Encodings.
/// ///
@@ -64,15 +64,21 @@ impl Decoder {
// constructors // constructors
pub fn length(x: u64) -> Decoder { pub fn length(x: u64) -> Decoder {
Decoder { kind: Kind::Length(x) } Decoder {
kind: Kind::Length(x),
}
} }
pub fn chunked() -> Decoder { pub fn chunked() -> Decoder {
Decoder { kind: Kind::Chunked(ChunkedState::Size, 0) } Decoder {
kind: Kind::Chunked(ChunkedState::Size, 0),
}
} }
pub fn eof() -> Decoder { pub fn eof() -> Decoder {
Decoder { kind: Kind::Eof(false) } Decoder {
kind: Kind::Eof(false),
}
} }
pub(super) fn new(len: DecodedLength) -> Self { pub(super) fn new(len: DecodedLength) -> Self {
@@ -87,14 +93,16 @@ impl Decoder {
pub fn is_eof(&self) -> bool { pub fn is_eof(&self) -> bool {
match self.kind { match self.kind {
Length(0) | Length(0) | Chunked(ChunkedState::End, _) | Eof(true) => true,
Chunked(ChunkedState::End, _) |
Eof(true) => true,
_ => false, _ => false,
} }
} }
pub fn decode<R: MemRead>(&mut self, cx: &mut task::Context<'_>, body: &mut R) -> Poll<Result<Bytes, io::Error>> { pub fn decode<R: MemRead>(
&mut self,
cx: &mut task::Context<'_>,
body: &mut R,
) -> Poll<Result<Bytes, io::Error>> {
trace!("decode; state={:?}", self.kind); trace!("decode; state={:?}", self.kind);
match self.kind { match self.kind {
Length(ref mut remaining) => { Length(ref mut remaining) => {
@@ -107,7 +115,10 @@ impl Decoder {
if num > *remaining { if num > *remaining {
*remaining = 0; *remaining = 0;
} else if num == 0 { } else if num == 0 {
return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody))); return Poll::Ready(Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
IncompleteBody,
)));
} else { } else {
*remaining -= num; *remaining -= num;
} }
@@ -146,13 +157,10 @@ impl Decoder {
#[cfg(test)] #[cfg(test)]
async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Bytes, io::Error> { async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Bytes, io::Error> {
futures_util::future::poll_fn(move |cx| { futures_util::future::poll_fn(move |cx| self.decode(cx, body)).await
self.decode(cx, body)
}).await
} }
} }
impl fmt::Debug for Decoder { impl fmt::Debug for Decoder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.kind, f) fmt::Debug::fmt(&self.kind, f)
@@ -172,12 +180,13 @@ macro_rules! byte (
); );
impl ChunkedState { impl ChunkedState {
fn step<R: MemRead>(&self, fn step<R: MemRead>(
&self,
cx: &mut task::Context<'_>, cx: &mut task::Context<'_>,
body: &mut R, body: &mut R,
size: &mut u64, size: &mut u64,
buf: &mut Option<Bytes>) buf: &mut Option<Bytes>,
-> Poll<Result<ChunkedState, io::Error>> { ) -> Poll<Result<ChunkedState, io::Error>> {
use self::ChunkedState::*; use self::ChunkedState::*;
match *self { match *self {
Size => ChunkedState::read_size(cx, body, size), Size => ChunkedState::read_size(cx, body, size),
@@ -192,7 +201,11 @@ impl ChunkedState {
End => Poll::Ready(Ok(ChunkedState::End)), End => Poll::Ready(Ok(ChunkedState::End)),
} }
} }
fn read_size<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: &mut u64) -> Poll<Result<ChunkedState, io::Error>> { fn read_size<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
size: &mut u64,
) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Read chunk hex size"); trace!("Read chunk hex size");
let radix = 16; let radix = 16;
match byte!(rdr, cx) { match byte!(rdr, cx) {
@@ -212,33 +225,45 @@ impl ChunkedState {
b';' => return Poll::Ready(Ok(ChunkedState::Extension)), b';' => return Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)), b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => { _ => {
return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, return Poll::Ready(Err(io::Error::new(
"Invalid chunk size line: Invalid Size"))); io::ErrorKind::InvalidInput,
"Invalid chunk size line: Invalid Size",
)));
} }
} }
Poll::Ready(Ok(ChunkedState::Size)) Poll::Ready(Ok(ChunkedState::Size))
} }
fn read_size_lws<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { fn read_size_lws<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
trace!("read_size_lws"); trace!("read_size_lws");
match byte!(rdr, cx) { match byte!(rdr, cx) {
// LWS can follow the chunk size, but no more digits can come // LWS can follow the chunk size, but no more digits can come
b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)), b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => Poll::Ready(Ok(ChunkedState::Extension)), b';' => Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)), b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => { _ => Poll::Ready(Err(io::Error::new(
Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, io::ErrorKind::InvalidInput,
"Invalid chunk size linear white space"))) "Invalid chunk size linear white space",
))),
} }
} }
} fn read_extension<R: MemRead>(
fn read_extension<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
trace!("read_extension"); trace!("read_extension");
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)), b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions _ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
} }
} }
fn read_size_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: u64) -> Poll<Result<ChunkedState, io::Error>> { fn read_size_lf<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
size: u64,
) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Chunk size is {:?}", size); trace!("Chunk size is {:?}", size);
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\n' => { b'\n' => {
@@ -248,15 +273,20 @@ impl ChunkedState {
debug!("incoming chunked header: {0:#X} ({0} bytes)", size); debug!("incoming chunked header: {0:#X} ({0} bytes)", size);
Poll::Ready(Ok(ChunkedState::Body)) Poll::Ready(Ok(ChunkedState::Body))
} }
}, }
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF"))), _ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk size LF",
))),
} }
} }
fn read_body<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, fn read_body<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
rem: &mut u64, rem: &mut u64,
buf: &mut Option<Bytes>) buf: &mut Option<Bytes>,
-> Poll<Result<ChunkedState, io::Error>> { ) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Chunked read, remaining={:?}", rem); trace!("Chunked read, remaining={:?}", rem);
// cap remaining bytes at the max capacity of usize // cap remaining bytes at the max capacity of usize
@@ -271,7 +301,10 @@ impl ChunkedState {
if count == 0 { if count == 0 {
*rem = 0; *rem = 0;
return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody))); return Poll::Ready(Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
IncompleteBody,
)));
} }
*buf = Some(slice); *buf = Some(slice);
*rem -= count as u64; *rem -= count as u64;
@@ -282,29 +315,53 @@ impl ChunkedState {
Poll::Ready(Ok(ChunkedState::BodyCr)) Poll::Ready(Ok(ChunkedState::BodyCr))
} }
} }
fn read_body_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { fn read_body_cr<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\r' => Poll::Ready(Ok(ChunkedState::BodyLf)), b'\r' => Poll::Ready(Ok(ChunkedState::BodyLf)),
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR"))), _ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk body CR",
))),
} }
} }
fn read_body_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { fn read_body_lf<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\n' => Poll::Ready(Ok(ChunkedState::Size)), b'\n' => Poll::Ready(Ok(ChunkedState::Size)),
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF"))), _ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk body LF",
))),
} }
} }
fn read_end_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { fn read_end_cr<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)), b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)),
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR"))), _ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk end CR",
))),
} }
} }
fn read_end_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> { fn read_end_lf<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr, cx) { match byte!(rdr, cx) {
b'\n' => Poll::Ready(Ok(ChunkedState::End)), b'\n' => Poll::Ready(Ok(ChunkedState::End)),
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF"))), _ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk end LF",
))),
} }
} }
} }
@@ -326,10 +383,10 @@ impl StdError for IncompleteBody {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::time::Duration;
use std::pin::Pin;
use tokio::io::AsyncRead;
use super::*; use super::*;
use std::pin::Pin;
use std::time::Duration;
use tokio::io::AsyncRead;
impl<'a> MemRead for &'a [u8] { impl<'a> MemRead for &'a [u8] {
fn read_mem(&mut self, _: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> { fn read_mem(&mut self, _: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
@@ -363,19 +420,18 @@ mod tests {
use crate::mock::AsyncIo; use crate::mock::AsyncIo;
*/ */
#[tokio::test] #[tokio::test]
async fn test_read_chunk_size() { async fn test_read_chunk_size() {
use std::io::ErrorKind::{UnexpectedEof, InvalidInput}; use std::io::ErrorKind::{InvalidInput, UnexpectedEof};
async fn read(s: &str) -> u64 { async fn read(s: &str) -> u64 {
let mut state = ChunkedState::Size; let mut state = ChunkedState::Size;
let rdr = &mut s.as_bytes(); let rdr = &mut s.as_bytes();
let mut size = 0; let mut size = 0;
loop { loop {
let result = futures_util::future::poll_fn(|cx| { let result =
state.step(cx, rdr, &mut size, &mut None) futures_util::future::poll_fn(|cx| state.step(cx, rdr, &mut size, &mut None))
}).await; .await;
let desc = format!("read_size failed for {:?}", s); let desc = format!("read_size failed for {:?}", s);
state = result.expect(desc.as_str()); state = result.expect(desc.as_str());
if state == ChunkedState::Body || state == ChunkedState::EndCr { if state == ChunkedState::Body || state == ChunkedState::EndCr {
@@ -390,14 +446,19 @@ mod tests {
let rdr = &mut s.as_bytes(); let rdr = &mut s.as_bytes();
let mut size = 0; let mut size = 0;
loop { loop {
let result = futures_util::future::poll_fn(|cx| { let result =
state.step(cx, rdr, &mut size, &mut None) futures_util::future::poll_fn(|cx| state.step(cx, rdr, &mut size, &mut None))
}).await; .await;
state = match result { state = match result {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
assert!(expected_err == e.kind(), "Reading {:?}, expected {:?}, but got {:?}", assert!(
s, expected_err, e.kind()); expected_err == e.kind(),
"Reading {:?}, expected {:?}, but got {:?}",
s,
expected_err,
e.kind()
);
return; return;
} }
}; };
@@ -462,7 +523,10 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_read_chunked_single_read() { async fn test_read_chunked_single_read() {
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..]; let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
let buf = Decoder::chunked().decode_fut(&mut mock_buf).await.expect("decode"); let buf = Decoder::chunked()
.decode_fut(&mut mock_buf)
.await
.expect("decode");
assert_eq!(16, buf.len()); assert_eq!(16, buf.len());
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String"); let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
assert_eq!("1234567890abcdef", &result); assert_eq!("1234567890abcdef", &result);
@@ -490,10 +554,7 @@ mod tests {
// perform an async read using a custom buffer size and causing a blocking // perform an async read using a custom buffer size and causing a blocking
// read at the specified byte // read at the specified byte
async fn read_async(mut decoder: Decoder, async fn read_async(mut decoder: Decoder, content: &[u8], block_at: usize) -> String {
content: &[u8],
block_at: usize)
-> String {
let mut outs = Vec::new(); let mut outs = Vec::new();
let mut ins = if block_at == 0 { let mut ins = if block_at == 0 {

View File

@@ -4,10 +4,13 @@ use bytes::{Buf, Bytes};
use http::{Request, Response, StatusCode}; 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};
use crate::proto::{BodyLength, DecodedLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, ResponseHead};
use super::Http1Transaction; use super::Http1Transaction;
use crate::body::{Body, Payload};
use crate::common::{task, Future, Never, Pin, Poll, Unpin};
use crate::proto::{
BodyLength, Conn, DecodedLength, Dispatched, MessageHead, RequestHead, RequestLine,
ResponseHead,
};
use crate::service::HttpService; use crate::service::HttpService;
pub(crate) struct Dispatcher<D, Bs: Payload, I, T> { pub(crate) struct Dispatcher<D, Bs: Payload, I, T> {
@@ -23,7 +26,10 @@ pub(crate) trait Dispatch {
type PollBody; type PollBody;
type PollError; type PollError;
type RecvItem; type RecvItem;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>>; fn poll_msg(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>>;
fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()>; fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()>;
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>>; fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>>;
fn should_poll(&self) -> bool; fn should_poll(&self) -> bool;
@@ -44,7 +50,11 @@ type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>
impl<D, Bs, I, T> Dispatcher<D, Bs, I, T> impl<D, Bs, I, T> Dispatcher<D, Bs, I, T>
where where
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>> + Unpin, D: Dispatch<
PollItem = MessageHead<T::Outgoing>,
PollBody = Bs,
RecvItem = MessageHead<T::Incoming>,
> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>, D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + Unpin, I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction + Unpin, T: Http1Transaction + Unpin,
@@ -77,7 +87,10 @@ where
/// ///
/// This is useful for old-style HTTP upgrades, but ignores /// This is useful for old-style HTTP upgrades, but ignores
/// newer-style upgrade API. /// newer-style upgrade API.
pub(crate) fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> pub(crate) fn poll_without_shutdown(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<crate::Result<()>>
where where
Self: Unpin, Self: Unpin,
{ {
@@ -88,7 +101,11 @@ where
}) })
} }
fn poll_catch(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> { fn poll_catch(
&mut self,
cx: &mut task::Context<'_>,
should_shutdown: bool,
) -> Poll<crate::Result<Dispatched>> {
Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| { Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| {
// An error means we're shutting down either way. // An error means we're shutting down either way.
// We just try to give the error to the user, // We just try to give the error to the user,
@@ -99,7 +116,11 @@ where
})) }))
} }
fn poll_inner(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> { fn poll_inner(
&mut self,
cx: &mut task::Context<'_>,
should_shutdown: bool,
) -> Poll<crate::Result<Dispatched>> {
T::update_date(); T::update_date();
ready!(self.poll_loop(cx))?; ready!(self.poll_loop(cx))?;
@@ -161,7 +182,7 @@ where
Poll::Pending => { Poll::Pending => {
self.body_tx = Some(body); self.body_tx = Some(body);
return Poll::Pending; return Poll::Pending;
}, }
Poll::Ready(Err(_canceled)) => { Poll::Ready(Err(_canceled)) => {
// user doesn't care about the body // user doesn't care about the body
// so we should stop reading // so we should stop reading
@@ -171,22 +192,20 @@ where
} }
} }
match self.conn.poll_read_body(cx) { match self.conn.poll_read_body(cx) {
Poll::Ready(Some(Ok(chunk))) => { Poll::Ready(Some(Ok(chunk))) => match body.try_send_data(chunk) {
match body.try_send_data(chunk) {
Ok(()) => { Ok(()) => {
self.body_tx = Some(body); self.body_tx = Some(body);
}, }
Err(_canceled) => { Err(_canceled) => {
if self.conn.can_read_body() { if self.conn.can_read_body() {
trace!("body receiver dropped before eof, closing"); trace!("body receiver dropped before eof, closing");
self.conn.close_read(); self.conn.close_read();
} }
} }
}
}, },
Poll::Ready(None) => { Poll::Ready(None) => {
// just drop, the body will close automatically // just drop, the body will close automatically
}, }
Poll::Pending => { Poll::Pending => {
self.body_tx = Some(body); self.body_tx = Some(body);
return Poll::Pending; return Poll::Pending;
@@ -223,14 +242,14 @@ where
let (tx, rx) = Body::new_channel(other.into_opt()); let (tx, rx) = Body::new_channel(other.into_opt());
self.body_tx = Some(tx); self.body_tx = Some(tx);
rx rx
}, }
}; };
if wants_upgrade { if wants_upgrade {
body.set_on_upgrade(self.conn.on_upgrade()); body.set_on_upgrade(self.conn.on_upgrade());
} }
self.dispatch.recv_msg(Ok((head, body)))?; self.dispatch.recv_msg(Ok((head, body)))?;
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
}, }
Some(Err(err)) => { Some(Err(err)) => {
debug!("read_head error: {}", err); debug!("read_head error: {}", err);
self.dispatch.recv_msg(Err(err))?; self.dispatch.recv_msg(Err(err))?;
@@ -239,7 +258,7 @@ where
// not as a second error. // not as a second error.
self.close(); self.close();
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
}, }
None => { None => {
// read eof, the write side will have been closed too unless // read eof, the write side will have been closed too unless
// allow_read_close was set to true, in which case just do // allow_read_close was set to true, in which case just do
@@ -257,7 +276,10 @@ where
loop { loop {
if self.is_closing { if self.is_closing {
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() { } else if self.body_rx.is_none()
&& self.conn.can_write_head()
&& self.dispatch.should_poll()
{
if let Some(msg) = ready!(self.dispatch.poll_msg(cx)) { if let Some(msg) = ready!(self.dispatch.poll_msg(cx)) {
let (head, mut body) = msg.map_err(crate::Error::new_user_service)?; let (head, mut body) = msg.map_err(crate::Error::new_user_service)?;
@@ -274,7 +296,9 @@ where
self.body_rx.set(None); self.body_rx.set(None);
None None
} else { } else {
let btype = body.size_hint().exact() let btype = body
.size_hint()
.exact()
.map(BodyLength::Known) .map(BodyLength::Known)
.or_else(|| Some(BodyLength::Unknown)); .or_else(|| Some(BodyLength::Unknown));
self.body_rx.set(Some(body)); self.body_rx.set(Some(body));
@@ -289,7 +313,9 @@ where
ready!(self.poll_flush(cx))?; ready!(self.poll_flush(cx))?;
} else { } else {
// A new scope is needed :( // A new scope is needed :(
if let (Some(mut body), clear_body) = OptGuard::new(self.body_rx.as_mut()).guard_mut() { if let (Some(mut body), clear_body) =
OptGuard::new(self.body_rx.as_mut()).guard_mut()
{
debug_assert!(!*clear_body, "opt guard defaults to keeping body"); debug_assert!(!*clear_body, "opt guard defaults to keeping body");
if !self.conn.can_write_body() { if !self.conn.can_write_body() {
trace!( trace!(
@@ -357,8 +383,8 @@ where
// a client that cannot read may was well be done. // a client that cannot read may was well be done.
true true
} else { } else {
let write_done = self.conn.is_write_closed() || let write_done = self.conn.is_write_closed()
(!self.dispatch.should_poll() && self.body_rx.is_none()); || (!self.dispatch.should_poll() && self.body_rx.is_none());
read_done && write_done read_done && write_done
} }
} }
@@ -366,7 +392,11 @@ where
impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T> impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>
where where
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>> + Unpin, D: Dispatch<
PollItem = MessageHead<T::Outgoing>,
PollBody = Bs,
RecvItem = MessageHead<T::Incoming>,
> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>, D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + Unpin, I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction + Unpin, T: Http1Transaction + Unpin,
@@ -436,7 +466,10 @@ where
type PollError = S::Error; type PollError = S::Error;
type RecvItem = RequestHead; type RecvItem = RequestHead;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> { fn poll_msg(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {
let ret = if let Some(ref mut fut) = self.in_flight.as_mut().as_pin_mut() { let ret = if let Some(ref mut fut) = self.in_flight.as_mut().as_pin_mut() {
let resp = ready!(fut.as_mut().poll(cx)?); let resp = ready!(fut.as_mut().poll(cx)?);
let (parts, body) = resp.into_parts(); let (parts, body) = resp.into_parts();
@@ -471,8 +504,7 @@ where
if self.in_flight.is_some() { if self.in_flight.is_some() {
Poll::Pending Poll::Pending
} else { } else {
self.service.poll_ready(cx) self.service.poll_ready(cx).map_err(|_e| {
.map_err(|_e| {
// FIXME: return error value. // FIXME: return error value.
trace!("service closed"); trace!("service closed");
}) })
@@ -486,7 +518,6 @@ where
// ===== impl Client ===== // ===== impl Client =====
impl<B> Client<B> { impl<B> Client<B> {
pub fn new(rx: ClientRx<B>) -> Client<B> { pub fn new(rx: ClientRx<B>) -> Client<B> {
Client { Client {
@@ -506,7 +537,10 @@ where
type PollError = Never; type PollError = Never;
type RecvItem = ResponseHead; type RecvItem = ResponseHead;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> { fn poll_msg(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> {
debug_assert!(!self.rx_closed); debug_assert!(!self.rx_closed);
match self.rx.poll_next(cx) { match self.rx.poll_next(cx) {
Poll::Ready(Some((req, mut cb))) => { Poll::Ready(Some((req, mut cb))) => {
@@ -515,7 +549,7 @@ where
Poll::Ready(()) => { Poll::Ready(()) => {
trace!("request canceled"); trace!("request canceled");
Poll::Ready(None) Poll::Ready(None)
}, }
Poll::Pending => { Poll::Pending => {
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
let head = RequestHead { let head = RequestHead {
@@ -527,13 +561,13 @@ where
Poll::Ready(Some(Ok((head, body)))) Poll::Ready(Some(Ok((head, body))))
} }
} }
}, }
Poll::Ready(None) => { Poll::Ready(None) => {
// user has dropped sender handle // user has dropped sender handle
trace!("client tx closed"); trace!("client tx closed");
self.rx_closed = true; self.rx_closed = true;
Poll::Ready(None) Poll::Ready(None)
}, }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }
@@ -554,7 +588,7 @@ where
// full message! // full message!
Err(crate::Error::new_unexpected_message()) Err(crate::Error::new_unexpected_message())
} }
}, }
Err(err) => { Err(err) => {
if let Some(cb) = self.callback.take() { if let Some(cb) = self.callback.take() {
let _ = cb.send(Err((err, None))); let _ = cb.send(Err((err, None)));
@@ -583,7 +617,7 @@ where
Poll::Ready(()) => { Poll::Ready(()) => {
trace!("callback receiver has dropped"); trace!("callback receiver has dropped");
Poll::Ready(Err(())) Poll::Ready(Err(()))
}, }
Poll::Pending => Poll::Ready(Ok(())), Poll::Pending => Poll::Ready(Ok(())),
}, },
None => Poll::Ready(Err(())), None => Poll::Ready(Err(())),
@@ -597,18 +631,16 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::time::Duration;
use super::*; use super::*;
use crate::proto::h1::ClientTransaction; use crate::proto::h1::ClientTransaction;
use std::time::Duration;
#[test] #[test]
fn client_read_bytes_before_writing_request() { fn client_read_bytes_before_writing_request() {
let _ = pretty_env_logger::try_init(); let _ = pretty_env_logger::try_init();
tokio_test::task::spawn(()).enter(|cx, _| { tokio_test::task::spawn(()).enter(|cx, _| {
let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
let (io, mut handle) = tokio_test::io::Builder::new()
.build_with_handle();
// Block at 0 for now, but we will release this response before // Block at 0 for now, but we will release this response before
// the request is ready to write later... // the request is ready to write later...
@@ -624,7 +656,9 @@ mod tests {
// //
handle.read(b"HTTP/1.1 200 OK\r\n\r\n"); handle.read(b"HTTP/1.1 200 OK\r\n\r\n");
let mut res_rx = tx.try_send(crate::Request::new(crate::Body::empty())).unwrap(); let mut res_rx = tx
.try_send(crate::Request::new(crate::Body::empty()))
.unwrap();
tokio_test::assert_ready_ok!(Pin::new(&mut dispatcher).poll(cx)); tokio_test::assert_ready_ok!(Pin::new(&mut dispatcher).poll(cx));
let err = tokio_test::assert_ready_ok!(Pin::new(&mut res_rx).poll(cx)) let err = tokio_test::assert_ready_ok!(Pin::new(&mut res_rx).poll(cx))

View File

@@ -1,8 +1,8 @@
use std::fmt; use std::fmt;
use std::io::IoSlice; use std::io::IoSlice;
use bytes::Buf;
use bytes::buf::ext::{BufExt, Chain, Take}; use bytes::buf::ext::{BufExt, Chain, Take};
use bytes::Buf;
use super::io::WriteBuf; use super::io::WriteBuf;
@@ -68,7 +68,7 @@ impl Encoder {
pub fn is_eof(&self) -> bool { pub fn is_eof(&self) -> bool {
match self.kind { match self.kind {
Kind::Length(0) => true, Kind::Length(0) => true,
_ => false _ => false,
} }
} }
@@ -105,7 +105,7 @@ impl Encoder {
.chain(msg) .chain(msg)
.chain(b"\r\n" as &'static [u8]); .chain(b"\r\n" as &'static [u8]);
BufKind::Chunked(buf) BufKind::Chunked(buf)
}, }
Kind::Length(ref mut remaining) => { Kind::Length(ref mut remaining) => {
trace!("sized write, len = {}", len); trace!("sized write, len = {}", len);
if len as u64 > *remaining { if len as u64 > *remaining {
@@ -116,15 +116,13 @@ impl Encoder {
*remaining -= len as u64; *remaining -= len as u64;
BufKind::Exact(msg) BufKind::Exact(msg)
} }
}, }
Kind::CloseDelimited => { Kind::CloseDelimited => {
trace!("close delimited write {}B", len); trace!("close delimited write {}B", len);
BufKind::Exact(msg) BufKind::Exact(msg)
} }
}; };
EncodedBuf { EncodedBuf { kind }
kind,
}
} }
pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>) -> bool pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>) -> bool
@@ -142,7 +140,7 @@ impl Encoder {
.chain(b"\r\n0\r\n\r\n" as &'static [u8]); .chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf); dst.buffer(buf);
!self.is_last !self.is_last
}, }
Kind::Length(remaining) => { Kind::Length(remaining) => {
use std::cmp::Ordering; use std::cmp::Ordering;
@@ -151,17 +149,17 @@ impl Encoder {
Ordering::Equal => { Ordering::Equal => {
dst.buffer(msg); dst.buffer(msg);
!self.is_last !self.is_last
}, }
Ordering::Greater => { Ordering::Greater => {
dst.buffer(msg.take(remaining as usize)); dst.buffer(msg.take(remaining as usize));
!self.is_last !self.is_last
}, }
Ordering::Less => { Ordering::Less => {
dst.buffer(msg); dst.buffer(msg);
false false
} }
} }
}, }
Kind::CloseDelimited => { Kind::CloseDelimited => {
trace!("close delimited write {}B", len); trace!("close delimited write {}B", len);
dst.buffer(msg); dst.buffer(msg);
@@ -180,10 +178,13 @@ impl Encoder {
B: Buf, B: Buf,
{ {
debug_assert!(msg.remaining() > 0, "encode() called with empty buf"); debug_assert!(msg.remaining() > 0, "encode() called with empty buf");
debug_assert!(match self.kind { debug_assert!(
match self.kind {
Kind::Length(len) => len == msg.remaining() as u64, Kind::Length(len) => len == msg.remaining() as u64,
_ => true, _ => true,
}, "danger_full_buf length mismatches"); },
"danger_full_buf length mismatches"
);
match self.kind { match self.kind {
Kind::Chunked => { Kind::Chunked => {
@@ -193,10 +194,10 @@ impl Encoder {
.chain(msg) .chain(msg)
.chain(b"\r\n0\r\n\r\n" as &'static [u8]); .chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf); dst.buffer(buf);
}, }
_ => { _ => {
dst.buffer(msg); dst.buffer(msg);
}, }
} }
} }
} }
@@ -246,7 +247,6 @@ where
} }
} }
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
const USIZE_BYTES: usize = 4; const USIZE_BYTES: usize = 4;
@@ -271,8 +271,7 @@ impl ChunkSize {
pos: 0, pos: 0,
len: 0, len: 0,
}; };
write!(&mut size, "{:X}\r\n", len) write!(&mut size, "{:X}\r\n", len).expect("CHUNK_SIZE_MAX_BYTES should fit any usize");
.expect("CHUNK_SIZE_MAX_BYTES should fit any usize");
size size
} }
} }
@@ -307,7 +306,8 @@ impl fmt::Debug for ChunkSize {
impl fmt::Write for ChunkSize { impl fmt::Write for ChunkSize {
fn write_str(&mut self, num: &str) -> fmt::Result { fn write_str(&mut self, num: &str) -> fmt::Result {
use std::io::Write; use std::io::Write;
(&mut self.bytes[self.len.into()..]).write(num.as_bytes()) (&mut self.bytes[self.len.into()..])
.write(num.as_bytes())
.expect("&mut [u8].write() cannot error"); .expect("&mut [u8].write() cannot error");
self.len += num.len() as u8; // safe because bytes is never bigger than 256 self.len += num.len() as u8; // safe because bytes is never bigger than 256
Ok(()) Ok(())
@@ -340,7 +340,7 @@ impl<B: Buf> From<Chain<Chain<ChunkSize, B>, StaticBuf>> for EncodedBuf<B> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use bytes::{BufMut}; use bytes::BufMut;
use super::super::io::Cursor; use super::super::io::Cursor;
use super::Encoder; use super::Encoder;
@@ -364,7 +364,10 @@ mod tests {
let end = encoder.end::<Cursor<Vec<u8>>>().unwrap().unwrap(); let end = encoder.end::<Cursor<Vec<u8>>>().unwrap().unwrap();
dst.put(end); dst.put(end);
assert_eq!(dst, b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n".as_ref()); assert_eq!(
dst,
b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n".as_ref()
);
} }
#[test] #[test]
@@ -373,12 +376,10 @@ mod tests {
let mut encoder = Encoder::length(max_len as u64); let mut encoder = Encoder::length(max_len as u64);
let mut dst = Vec::new(); let mut dst = Vec::new();
let msg1 = b"foo bar".as_ref(); let msg1 = b"foo bar".as_ref();
let buf1 = encoder.encode(msg1); let buf1 = encoder.encode(msg1);
dst.put(buf1); dst.put(buf1);
assert_eq!(dst, b"foo bar"); assert_eq!(dst, b"foo bar");
assert!(!encoder.is_eof()); assert!(!encoder.is_eof());
encoder.end::<()>().unwrap_err(); encoder.end::<()>().unwrap_err();
@@ -398,12 +399,10 @@ mod tests {
let mut encoder = Encoder::close_delimited(); let mut encoder = Encoder::close_delimited();
let mut dst = Vec::new(); let mut dst = Vec::new();
let msg1 = b"foo bar".as_ref(); let msg1 = b"foo bar".as_ref();
let buf1 = encoder.encode(msg1); let buf1 = encoder.encode(msg1);
dst.put(buf1); dst.put(buf1);
assert_eq!(dst, b"foo bar"); assert_eq!(dst, b"foo bar");
assert!(!encoder.is_eof()); assert!(!encoder.is_eof());
encoder.end::<()>().unwrap_err(); encoder.end::<()>().unwrap_err();

View File

@@ -7,8 +7,8 @@ use std::io::{self, IoSlice};
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, Unpin, task};
use super::{Http1Transaction, ParseContext, ParsedMessage}; use super::{Http1Transaction, ParseContext, ParsedMessage};
use crate::common::{task, Pin, Poll, Unpin};
/// The initial buffer size allocated before trying to read from IO. /// The initial buffer size allocated before trying to read from IO.
pub(crate) const INIT_BUFFER_SIZE: usize = 8192; pub(crate) const INIT_BUFFER_SIZE: usize = 8192;
@@ -140,34 +140,40 @@ where
} }
} }
pub(super) fn parse<S>(&mut self, cx: &mut task::Context<'_>, parse_ctx: ParseContext<'_>) pub(super) fn parse<S>(
-> Poll<crate::Result<ParsedMessage<S::Incoming>>> &mut self,
cx: &mut task::Context<'_>,
parse_ctx: ParseContext<'_>,
) -> Poll<crate::Result<ParsedMessage<S::Incoming>>>
where where
S: Http1Transaction, S: Http1Transaction,
{ {
loop { loop {
match S::parse(&mut self.read_buf, ParseContext { match S::parse(
&mut self.read_buf,
ParseContext {
cached_headers: parse_ctx.cached_headers, cached_headers: parse_ctx.cached_headers,
req_method: parse_ctx.req_method, req_method: parse_ctx.req_method,
})? { },
)? {
Some(msg) => { Some(msg) => {
debug!("parsed {} headers", msg.head.headers.len()); debug!("parsed {} headers", msg.head.headers.len());
return Poll::Ready(Ok(msg)); return Poll::Ready(Ok(msg));
}, }
None => { None => {
let max = self.read_buf_strategy.max(); let max = self.read_buf_strategy.max();
if self.read_buf.len() >= max { if self.read_buf.len() >= max {
debug!("max_buf_size ({}) reached, closing", max); debug!("max_buf_size ({}) reached, closing", max);
return Poll::Ready(Err(crate::Error::new_too_large())); return Poll::Ready(Err(crate::Error::new_too_large()));
} }
}, }
} }
match ready!(self.poll_read_from_io(cx)).map_err(crate::Error::new_io)? { match ready!(self.poll_read_from_io(cx)).map_err(crate::Error::new_io)? {
0 => { 0 => {
trace!("parse eof"); trace!("parse eof");
return Poll::Ready(Err(crate::Error::new_incomplete())); return Poll::Ready(Err(crate::Error::new_incomplete()));
} }
_ => {}, _ => {}
} }
} }
} }
@@ -183,7 +189,7 @@ where
debug!("read {} bytes", n); debug!("read {} bytes", n);
self.read_buf_strategy.record(n); self.read_buf_strategy.record(n);
Poll::Ready(Ok(n)) Poll::Ready(Ok(n))
}, }
Poll::Pending => { Poll::Pending => {
self.read_blocked = true; self.read_blocked = true;
Poll::Pending Poll::Pending
@@ -215,12 +221,16 @@ where
_ => (), _ => (),
} }
loop { loop {
let n = ready!(Pin::new(&mut self.io).poll_write_buf(cx, &mut self.write_buf.auto()))?; let n =
ready!(Pin::new(&mut self.io).poll_write_buf(cx, &mut self.write_buf.auto()))?;
debug!("flushed {} bytes", n); debug!("flushed {} bytes", n);
if self.write_buf.remaining() == 0 { if self.write_buf.remaining() == 0 {
break; break;
} else if n == 0 { } else if n == 0 {
trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); trace!(
"write returned zero, but {} bytes remaining",
self.write_buf.remaining()
);
return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
} }
} }
@@ -241,7 +251,10 @@ where
self.write_buf.headers.reset(); self.write_buf.headers.reset();
break; break;
} else if n == 0 { } else if n == 0 {
trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); trace!(
"write returned zero, but {} bytes remaining",
self.write_buf.remaining()
);
return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
} }
} }
@@ -283,7 +296,7 @@ enum ReadStrategy {
Adaptive { Adaptive {
decrease_now: bool, decrease_now: bool,
next: usize, next: usize,
max: usize max: usize,
}, },
Exact(usize), Exact(usize),
} }
@@ -313,7 +326,12 @@ impl ReadStrategy {
fn record(&mut self, bytes_read: usize) { fn record(&mut self, bytes_read: usize) {
match *self { match *self {
ReadStrategy::Adaptive { ref mut decrease_now, ref mut next, max, .. } => { ReadStrategy::Adaptive {
ref mut decrease_now,
ref mut next,
max,
..
} => {
if bytes_read >= *next { if bytes_read >= *next {
*next = cmp::min(incr_power_of_two(*next), max); *next = cmp::min(incr_power_of_two(*next), max);
*decrease_now = false; *decrease_now = false;
@@ -334,7 +352,7 @@ impl ReadStrategy {
*decrease_now = false; *decrease_now = false;
} }
} }
}, }
_ => (), _ => (),
} }
} }
@@ -428,7 +446,6 @@ impl<B> WriteBuf<B> {
} }
} }
impl<B> WriteBuf<B> impl<B> WriteBuf<B>
where where
B: Buf, B: Buf,
@@ -460,22 +477,19 @@ where
}; };
buf.advance(adv); buf.advance(adv);
} }
}, }
WriteStrategy::Auto | WriteStrategy::Queue => { WriteStrategy::Auto | WriteStrategy::Queue => {
self.queue.bufs.push_back(buf.into()); self.queue.bufs.push_back(buf.into());
}, }
} }
} }
fn can_buffer(&self) -> bool { fn can_buffer(&self) -> bool {
match self.strategy { match self.strategy {
WriteStrategy::Flatten => { WriteStrategy::Flatten => self.remaining() < self.max_buf_size,
self.remaining() < self.max_buf_size
},
WriteStrategy::Auto | WriteStrategy::Queue => { WriteStrategy::Auto | WriteStrategy::Queue => {
self.queue.bufs.len() < MAX_BUF_LIST_BUFFERS self.queue.bufs.len() < MAX_BUF_LIST_BUFFERS && self.remaining() < self.max_buf_size
&& self.remaining() < self.max_buf_size }
},
} }
} }
@@ -587,7 +601,6 @@ impl<'a, B: Buf + 'a> Drop for WriteBufAuto<'a, B> {
} }
} }
#[derive(Debug)] #[derive(Debug)]
enum WriteStrategy { enum WriteStrategy {
Auto, Auto,
@@ -599,7 +612,6 @@ struct BufDeque<T> {
bufs: VecDeque<T>, bufs: VecDeque<T>,
} }
impl<T> BufDeque<T> { impl<T> BufDeque<T> {
fn new() -> BufDeque<T> { fn new() -> BufDeque<T> {
BufDeque { BufDeque {
@@ -611,9 +623,7 @@ impl<T> BufDeque<T> {
impl<T: Buf> Buf for BufDeque<T> { impl<T: Buf> Buf for BufDeque<T> {
#[inline] #[inline]
fn remaining(&self) -> usize { fn remaining(&self) -> usize {
self.bufs.iter() self.bufs.iter().map(|buf| buf.remaining()).sum()
.map(|buf| buf.remaining())
.sum()
} }
#[inline] #[inline]
@@ -683,7 +693,9 @@ mod tests {
// First, let's just check that the Mock would normally return an // First, let's just check that the Mock would normally return an
// error on an unexpected write, even if the buffer is empty... // error on an unexpected write, even if the buffer is empty...
let mut mock = Mock::new().build(); let mut mock = Mock::new().build();
futures_util::future::poll_fn(|cx| Pin::new(&mut mock).poll_write_buf(cx, &mut Cursor::new(&[]))) futures_util::future::poll_fn(|cx| {
Pin::new(&mut mock).poll_write_buf(cx, &mut Cursor::new(&[]))
})
.await .await
.expect_err("should be a broken pipe"); .expect_err("should be a broken pipe");
@@ -716,11 +728,17 @@ mod tests {
cached_headers: &mut None, cached_headers: &mut None,
req_method: &mut None, req_method: &mut None,
}; };
assert!(buffered.parse::<ClientTransaction>(cx, parse_ctx).is_pending()); assert!(buffered
.parse::<ClientTransaction>(cx, parse_ctx)
.is_pending());
Poll::Ready(()) Poll::Ready(())
}).await; })
.await;
assert_eq!(buffered.read_buf, b"HTTP/1.1 200 OK\r\nServer: hyper\r\n"[..]); assert_eq!(
buffered.read_buf,
b"HTTP/1.1 200 OK\r\nServer: hyper\r\n"[..]
);
} }
#[test] #[test]
@@ -756,12 +774,20 @@ mod tests {
assert_eq!(strategy.next(), 16384); assert_eq!(strategy.next(), 16384);
strategy.record(1); strategy.record(1);
assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet"); assert_eq!(
strategy.next(),
16384,
"first smaller record doesn't decrement yet"
);
strategy.record(8192); strategy.record(8192);
assert_eq!(strategy.next(), 16384, "record was with range"); assert_eq!(strategy.next(), 16384, "record was with range");
strategy.record(1); strategy.record(1);
assert_eq!(strategy.next(), 16384, "in-range record should make this the 'first' again"); assert_eq!(
strategy.next(),
16384,
"in-range record should make this the 'first' again"
);
strategy.record(1); strategy.record(1);
assert_eq!(strategy.next(), 8192, "second smaller record decrements"); assert_eq!(strategy.next(), 8192, "second smaller record decrements");
@@ -779,10 +805,18 @@ mod tests {
assert_eq!(strategy.next(), 16384); assert_eq!(strategy.next(), 16384);
strategy.record(8193); strategy.record(8193);
assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet"); assert_eq!(
strategy.next(),
16384,
"first smaller record doesn't decrement yet"
);
strategy.record(8193); strategy.record(8193);
assert_eq!(strategy.next(), 16384, "with current step does not decrement"); assert_eq!(
strategy.next(),
16384,
"with current step does not decrement"
);
} }
#[test] #[test]

View File

@@ -1,11 +1,11 @@
use bytes::BytesMut; use bytes::BytesMut;
use http::{HeaderMap, Method}; use http::{HeaderMap, Method};
use crate::proto::{MessageHead, BodyLength, DecodedLength}; use crate::proto::{BodyLength, DecodedLength, MessageHead};
pub(crate) use self::conn::Conn; pub(crate) use self::conn::Conn;
pub(crate) use self::dispatch::Dispatcher;
pub use self::decode::Decoder; pub use self::decode::Decoder;
pub(crate) use self::dispatch::Dispatcher;
pub use self::encode::{EncodedBuf, Encoder}; pub use self::encode::{EncodedBuf, Encoder};
pub use self::io::Cursor; //TODO: move out of h1::io pub use self::io::Cursor; //TODO: move out of h1::io
pub use self::io::MINIMUM_MAX_BUFFER_SIZE; pub use self::io::MINIMUM_MAX_BUFFER_SIZE;
@@ -18,7 +18,6 @@ mod encode;
mod io; mod io;
mod role; mod role;
pub(crate) type ServerTransaction = role::Server; pub(crate) type ServerTransaction = role::Server;
pub(crate) type ClientTransaction = role::Client; pub(crate) type ClientTransaction = role::Client;
@@ -75,4 +74,3 @@ pub(crate) struct Encode<'a, T> {
req_method: &'a mut Option<Method>, req_method: &'a mut Option<Method>,
title_case_headers: bool, title_case_headers: bool,
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
use futures_channel::{mpsc, oneshot}; use futures_channel::{mpsc, oneshot};
use futures_util::future::{self, FutureExt as _, TryFutureExt as _, Either}; use futures_util::future::{self, Either, FutureExt as _, TryFutureExt as _};
use futures_util::stream::StreamExt as _; use futures_util::stream::StreamExt as _;
use h2::client::{Builder, SendRequest}; 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;
use crate::common::{Exec, Future, Never, Pin, Poll, task};
use crate::headers;
use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf}; use super::{PipeToSendStream, SendBuf};
use crate::body::Payload;
use crate::common::{task, Exec, Future, Never, Pin, Poll};
use crate::headers;
use crate::headers::content_length_parse_all;
use crate::proto::Dispatched;
use crate::{Body, Request, Response}; use crate::{Body, Request, Response};
type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>; type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>;
@@ -45,12 +45,9 @@ where
let (conn_drop_ref, rx) = mpsc::channel(1); let (conn_drop_ref, rx) = mpsc::channel(1);
let (cancel_tx, conn_eof) = oneshot::channel(); let (cancel_tx, conn_eof) = oneshot::channel();
let conn_drop_rx = rx.into_future() let conn_drop_rx = rx.into_future().map(|(item, _rx)| match item {
.map(|(item, _rx)| {
match item {
Some(never) => match never {}, Some(never) => match never {},
None => (), None => (),
}
}); });
let conn = conn.map_err(|e| debug!("connection error: {}", e)); let conn = conn.map_err(|e| debug!("connection error: {}", e));
@@ -138,8 +135,7 @@ where
}; };
if !eos { if !eos {
let mut pipe = PipeToSendStream::new(body, body_tx) let mut pipe = PipeToSendStream::new(body, body_tx).map(|res| {
.map(|res| {
if let Err(e) = res { if let Err(e) = res {
debug!("client request body error: {}", e); debug!("client request body error: {}", e);
} }
@@ -160,38 +156,32 @@ where
} }
} }
let fut = fut let fut = fut.map(move |result| match result {
.map(move |result| {
match result {
Ok(res) => { Ok(res) => {
let content_length = content_length_parse_all(res.headers()); let content_length = content_length_parse_all(res.headers());
let res = res.map(|stream| let res = res.map(|stream| crate::Body::h2(stream, content_length));
crate::Body::h2(stream, content_length));
Ok(res) Ok(res)
}, }
Err(err) => { Err(err) => {
debug!("client response error: {}", err); debug!("client response error: {}", err);
Err((crate::Error::new_h2(err), None)) Err((crate::Error::new_h2(err), None))
} }
}
}); });
self.executor.execute(cb.send_when(fut)); self.executor.execute(cb.send_when(fut));
continue; continue;
}, }
Poll::Ready(None) => { Poll::Ready(None) => {
trace!("client::dispatch::Sender dropped"); trace!("client::dispatch::Sender dropped");
return Poll::Ready(Ok(Dispatched::Shutdown)); return Poll::Ready(Ok(Dispatched::Shutdown));
} }
Poll::Pending => { Poll::Pending => match ready!(Pin::new(&mut self.conn_eof).poll(cx)) {
match ready!(Pin::new(&mut self.conn_eof).poll(cx)) {
Ok(never) => match never {}, Ok(never) => match never {},
Err(_conn_is_eof) => { Err(_conn_is_eof) => {
trace!("connection task is closed, closing dispatch task"); trace!("connection task is closed, closing dispatch task");
return Poll::Ready(Ok(Dispatched::Shutdown)); return Poll::Ready(Ok(Dispatched::Shutdown));
} }
}
}, },
} }
} }

View File

@@ -1,5 +1,5 @@
use bytes::Buf; use bytes::Buf;
use h2::{SendStream}; use h2::SendStream;
use http::header::{ use http::header::{
HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER, HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER,
TRANSFER_ENCODING, UPGRADE, TRANSFER_ENCODING, UPGRADE,
@@ -7,7 +7,7 @@ use http::header::{
use http::HeaderMap; use http::HeaderMap;
use crate::body::Payload; use crate::body::Payload;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
pub(crate) mod client; pub(crate) mod client;
pub(crate) mod server; pub(crate) mod server;
@@ -38,7 +38,11 @@ fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
} }
if is_request { if is_request {
if headers.get(TE).map(|te_header| te_header != "trailers").unwrap_or(false) { if headers
.get(TE)
.map(|te_header| te_header != "trailers")
.unwrap_or(false)
{
warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests"); warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
headers.remove(TE); headers.remove(TE);
} }
@@ -123,19 +127,24 @@ where
if self.body_tx.capacity() == 0 { if self.body_tx.capacity() == 0 {
loop { loop {
match ready!(self.body_tx.poll_capacity(cx)) { match ready!(self.body_tx.poll_capacity(cx)) {
Some(Ok(0)) => {}
Some(Ok(0)) => {},
Some(Ok(_)) => break, Some(Ok(_)) => break,
Some(Err(e)) => return Poll::Ready(Err(crate::Error::new_body_write(e))) , Some(Err(e)) => {
return Poll::Ready(Err(crate::Error::new_body_write(e)))
}
None => return Poll::Ready(Err(crate::Error::new_canceled())), None => return Poll::Ready(Err(crate::Error::new_canceled())),
} }
} }
} else { } else {
if let Poll::Ready(reason) = if let Poll::Ready(reason) = self
self.body_tx.poll_reset(cx).map_err(crate::Error::new_body_write)? .body_tx
.poll_reset(cx)
.map_err(crate::Error::new_body_write)?
{ {
debug!("stream received RST_STREAM: {:?}", reason); debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason)))); return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
} }
} }
@@ -170,11 +179,15 @@ where
} }
} }
} else { } else {
if let Poll::Ready(reason) = if let Poll::Ready(reason) = self
self.body_tx.poll_reset(cx).map_err(|e| crate::Error::new_body_write(e))? .body_tx
.poll_reset(cx)
.map_err(|e| crate::Error::new_body_write(e))?
{ {
debug!("stream received RST_STREAM: {:?}", reason); debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason)))); return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
} }
match ready!(Pin::new(&mut self.stream).poll_trailers(cx)) { match ready!(Pin::new(&mut self.stream).poll_trailers(cx)) {

View File

@@ -1,19 +1,19 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use std::marker::Unpin; use std::marker::Unpin;
use pin_project::{pin_project, project};
use h2::Reason;
use h2::server::{Builder, Connection, Handshake, SendResponse}; use h2::server::{Builder, Connection, Handshake, SendResponse};
use h2::Reason;
use pin_project::{pin_project, project};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use super::{PipeToSendStream, SendBuf};
use crate::body::Payload; use crate::body::Payload;
use crate::common::exec::H2Exec; use crate::common::exec::H2Exec;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
use crate::headers; use crate::headers;
use crate::headers::content_length_parse_all; use crate::headers::content_length_parse_all;
use crate::service::HttpService;
use crate::proto::Dispatched; use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf}; use crate::service::HttpService;
use crate::{Body, Response}; use crate::{Body, Response};
@@ -45,7 +45,6 @@ where
closing: Option<crate::Error>, closing: Option<crate::Error>,
} }
impl<T, S, B, E> Server<T, S, B, E> impl<T, S, B, E> Server<T, S, B, E>
where where
T: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite + Unpin,
@@ -69,13 +68,13 @@ where
match self.state { match self.state {
State::Handshaking(..) => { State::Handshaking(..) => {
// fall-through, to replace state with Closed // fall-through, to replace state with Closed
}, }
State::Serving(ref mut srv) => { State::Serving(ref mut srv) => {
if srv.closing.is_none() { if srv.closing.is_none() {
srv.conn.graceful_shutdown(); srv.conn.graceful_shutdown();
} }
return; return;
}, }
State::Closed => { State::Closed => {
return; return;
} }
@@ -105,7 +104,7 @@ where
conn, conn,
closing: None, closing: None,
}) })
}, }
State::Serving(ref mut srv) => { State::Serving(ref mut srv) => {
ready!(srv.poll_server(cx, &mut me.service, &mut me.exec))?; ready!(srv.poll_server(cx, &mut me.service, &mut me.exec))?;
return Poll::Ready(Ok(Dispatched::Shutdown)); return Poll::Ready(Ok(Dispatched::Shutdown));
@@ -127,12 +126,14 @@ where
B: Payload, B: Payload,
B::Data: Unpin, B::Data: Unpin,
{ {
fn poll_server<S, E>(&mut self, cx: &mut task::Context<'_>, service: &mut S, exec: &mut E) -> Poll<crate::Result<()>> fn poll_server<S, E>(
&mut self,
cx: &mut task::Context<'_>,
service: &mut S,
exec: &mut E,
) -> Poll<crate::Result<()>>
where where
S: HttpService< S: HttpService<Body, ResBody = B>,
Body,
ResBody=B,
>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
@@ -171,25 +172,26 @@ where
Some(Ok((req, respond))) => { Some(Ok((req, respond))) => {
trace!("incoming request"); trace!("incoming request");
let content_length = content_length_parse_all(req.headers()); let content_length = content_length_parse_all(req.headers());
let req = req.map(|stream| { let req = req.map(|stream| crate::Body::h2(stream, content_length));
crate::Body::h2(stream, content_length)
});
let fut = H2Stream::new(service.call(req), respond); let fut = H2Stream::new(service.call(req), respond);
exec.execute_h2stream(fut); exec.execute_h2stream(fut);
}, }
Some(Err(e)) => { Some(Err(e)) => {
return Poll::Ready(Err(crate::Error::new_h2(e))); return Poll::Ready(Err(crate::Error::new_h2(e)));
}, }
None => { None => {
// no more incoming streams... // no more incoming streams...
trace!("incoming connection complete"); trace!("incoming connection complete");
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
}, }
} }
} }
} }
debug_assert!(self.closing.is_some(), "poll_server broke loop without closing"); debug_assert!(
self.closing.is_some(),
"poll_server broke loop without closing"
);
ready!(self.conn.poll_closed(cx).map_err(crate::Error::new_h2))?; ready!(self.conn.poll_closed(cx).map_err(crate::Error::new_h2))?;
@@ -230,7 +232,7 @@ where
} }
macro_rules! reply { macro_rules! reply {
($me:expr, $res:expr, $eos:expr) => ({ ($me:expr, $res:expr, $eos:expr) => {{
match $me.reply.send_response($res, $eos) { match $me.reply.send_response($res, $eos) {
Ok(tx) => tx, Ok(tx) => tx,
Err(e) => { Err(e) => {
@@ -239,7 +241,7 @@ macro_rules! reply {
return Poll::Ready(Err(crate::Error::new_h2(e))); return Poll::Ready(Err(crate::Error::new_h2(e)));
} }
} }
}) }};
} }
impl<F, B, E> H2Stream<F, B> impl<F, B, E> H2Stream<F, B>
@@ -261,8 +263,10 @@ where
Poll::Pending => { Poll::Pending => {
// Response is not yet ready, so we want to check if the client has sent a // Response is not yet ready, so we want to check if the client has sent a
// RST_STREAM frame which would cancel the current request. // RST_STREAM frame which would cancel the current request.
if let Poll::Ready(reason) = if let Poll::Ready(reason) = me
me.reply.poll_reset(cx).map_err(|e| crate::Error::new_h2(e))? .reply
.poll_reset(cx)
.map_err(|e| crate::Error::new_h2(e))?
{ {
debug!("stream received RST_STREAM: {:?}", reason); debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_h2(reason.into()))); return Poll::Ready(Err(crate::Error::new_h2(reason.into())));
@@ -274,7 +278,7 @@ where
warn!("http2 service errored: {}", err); warn!("http2 service errored: {}", err);
me.reply.send_reset(err.h2_reason()); me.reply.send_reset(err.h2_reason());
return Poll::Ready(Err(err)); return Poll::Ready(Err(err));
}, }
}; };
let (head, body) = res.into_parts(); let (head, body) = res.into_parts();
@@ -282,13 +286,10 @@ where
super::strip_connection_headers(res.headers_mut(), false); super::strip_connection_headers(res.headers_mut(), false);
// set Date header if it isn't already set... // set Date header if it isn't already set...
res res.headers_mut()
.headers_mut()
.entry(::http::header::DATE) .entry(::http::header::DATE)
.or_insert_with(crate::proto::h1::date::update_and_header_value); .or_insert_with(crate::proto::h1::date::update_and_header_value);
// automatically set Content-Length from body... // automatically set Content-Length from body...
if let Some(len) = body.size_hint().exact() { if let Some(len) = body.size_hint().exact() {
headers::set_content_length_if_missing(res.headers_mut(), len); headers::set_content_length_if_missing(res.headers_mut(), len);
@@ -301,7 +302,7 @@ where
reply!(me, res, true); reply!(me, res, true);
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} }
}, }
H2StreamState::Body(ref mut pipe) => { H2StreamState::Body(ref mut pipe) => {
return Pin::new(pipe).poll(cx); return Pin::new(pipe).poll(cx);
} }

View File

@@ -1,8 +1,8 @@
//! Pieces pertaining to the HTTP message protocol. //! Pieces pertaining to the HTTP message protocol.
use http::{HeaderMap, Method, StatusCode, Uri, Version}; use http::{HeaderMap, Method, StatusCode, Uri, Version};
pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
use self::body_length::DecodedLength; use self::body_length::DecodedLength;
pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
pub(crate) mod h1; pub(crate) mod h1;
pub(crate) mod h2; pub(crate) mod h2;
@@ -76,9 +76,8 @@ mod body_length {
/// Converts to an Option<u64> representing a Known or Unknown length. /// Converts to an Option<u64> representing a Known or Unknown length.
pub(crate) fn into_opt(self) -> Option<u64> { pub(crate) fn into_opt(self) -> Option<u64> {
match self { match self {
DecodedLength::CHUNKED | DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None,
DecodedLength::CLOSE_DELIMITED => None, DecodedLength(known) => Some(known),
DecodedLength(known) => Some(known)
} }
} }

View File

@@ -9,7 +9,10 @@
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
use futures_core::Stream; use futures_core::Stream;
use crate::common::{Pin, task::{self, Poll}}; use crate::common::{
task::{self, Poll},
Pin,
};
/// Asynchronously accept incoming connections. /// Asynchronously accept incoming connections.
pub trait Accept { pub trait Accept {
@@ -19,8 +22,10 @@ pub trait Accept {
type Error; type Error;
/// Poll to accept the next connection. /// Poll to accept the next connection.
fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) fn poll_accept(
-> Poll<Option<Result<Self::Conn, Self::Error>>>; self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<Self::Conn, Self::Error>>>;
} }
/// Create an `Accept` with a polling function. /// Create an `Accept` with a polling function.
@@ -54,12 +59,11 @@ where
{ {
type Conn = IO; type Conn = IO;
type Error = E; type Error = E;
fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) fn poll_accept(
-> Poll<Option<Result<Self::Conn, Self::Error>>> self: Pin<&mut Self>,
{ cx: &mut task::Context<'_>,
unsafe { ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
(self.get_unchecked_mut().0)(cx) unsafe { (self.get_unchecked_mut().0)(cx) }
}
} }
} }
@@ -85,13 +89,11 @@ where
{ {
type Conn = IO; type Conn = IO;
type Error = E; type Error = E;
fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) fn poll_accept(
-> Poll<Option<Result<Self::Conn, Self::Error>>> self: Pin<&mut Self>,
{ cx: &mut task::Context<'_>,
unsafe { ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
Pin::new_unchecked(&mut self.get_unchecked_mut().0) unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0).poll_next(cx) }
.poll_next(cx)
}
} }
} }

View File

@@ -11,29 +11,31 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
use std::mem; use std::mem;
#[cfg(feature = "tcp")] use std::net::SocketAddr; #[cfg(feature = "tcp")]
use std::net::SocketAddr;
use bytes::Bytes; use bytes::Bytes;
use futures_core::Stream; use futures_core::Stream;
use tokio::io::{AsyncRead, AsyncWrite};
use pin_project::{pin_project, project}; use pin_project::{pin_project, project};
use tokio::io::{AsyncRead, AsyncWrite};
use super::Accept;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::{Exec, H2Exec, NewSvcExec}; use crate::common::exec::{Exec, H2Exec, NewSvcExec};
use crate::common::io::Rewind; use crate::common::io::Rewind;
use crate::common::{Future, Pin, Poll, Unpin, task}; use crate::common::{task, Future, Pin, Poll, Unpin};
use crate::error::{Kind, Parse}; use crate::error::{Kind, Parse};
use crate::proto; use crate::proto;
use crate::service::{MakeServiceRef, HttpService}; use crate::service::{HttpService, MakeServiceRef};
use crate::upgrade::Upgraded; use crate::upgrade::Upgraded;
use super::Accept;
pub(super) use self::spawn_all::NoopWatcher;
use self::spawn_all::NewSvcTask; use self::spawn_all::NewSvcTask;
pub(super) use self::spawn_all::NoopWatcher;
pub(super) use self::spawn_all::Watcher; pub(super) use self::spawn_all::Watcher;
pub(super) use self::upgrades::UpgradeableConnection; pub(super) use self::upgrades::UpgradeableConnection;
#[cfg(feature = "tcp")] pub use super::tcp::{AddrIncoming, AddrStream}; #[cfg(feature = "tcp")]
pub use super::tcp::{AddrIncoming, AddrStream};
// Our defaults are chosen for the "majority" case, which usually are not // Our defaults are chosen for the "majority" case, which usually are not
// resource contrained, and so the spec default of 64kb can be too limiting // resource contrained, and so the spec default of 64kb can be too limiting
@@ -274,7 +276,10 @@ impl<E> Http<E> {
/// Passing `None` will do nothing. /// Passing `None` will do nothing.
/// ///
/// If not set, hyper will use a default. /// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { pub fn http2_initial_connection_window_size(
&mut self,
sz: impl Into<Option<u32>>,
) -> &mut Self {
if let Some(sz) = sz.into() { if let Some(sz) = sz.into() {
self.h2_builder.initial_connection_window_size(sz); self.h2_builder.initial_connection_window_size(sz);
} }
@@ -402,7 +407,8 @@ impl<E> Http<E> {
} }
ConnectionMode::H2Only => { ConnectionMode::H2Only => {
let rewind_io = Rewind::new(io); let rewind_io = Rewind::new(io);
let h2 = proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone()); let h2 =
proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone());
ProtoServer::H2(h2) ProtoServer::H2(h2)
} }
}; };
@@ -422,11 +428,7 @@ impl<E> Http<E> {
I: Accept<Conn = IO, Error = IE>, I: Accept<Conn = IO, Error = IE>,
IE: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
IO: AsyncRead + AsyncWrite + Unpin, IO: AsyncRead + AsyncWrite + Unpin,
S: MakeServiceRef< S: MakeServiceRef<IO, Body, ResBody = Bd>,
IO,
Body,
ResBody=Bd,
>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
Bd: Payload, Bd: Payload,
E: H2Exec<<S::Service as HttpService<Body>>::Future, Bd>, E: H2Exec<<S::Service as HttpService<Body>>::Future, Bd>,
@@ -439,7 +441,6 @@ impl<E> Http<E> {
} }
} }
// ===== impl Connection ===== // ===== impl Connection =====
impl<I, B, S, E> Connection<I, S, E> impl<I, B, S, E> Connection<I, S, E>
@@ -459,7 +460,7 @@ where
match self.project().conn.as_mut().unwrap() { match self.project().conn.as_mut().unwrap() {
ProtoServer::H1(ref mut h1) => { ProtoServer::H1(ref mut h1) => {
h1.disable_keep_alive(); h1.disable_keep_alive();
}, }
ProtoServer::H2(ref mut h2) => { ProtoServer::H2(ref mut h2) => {
h2.graceful_shutdown(); h2.graceful_shutdown();
} }
@@ -476,7 +477,8 @@ where
/// # Panics /// # Panics
/// This method will panic if this connection is using an h2 protocol. /// This method will panic if this connection is using an h2 protocol.
pub fn into_parts(self) -> Parts<I, S> { pub fn into_parts(self) -> Parts<I, S> {
self.try_into_parts().unwrap_or_else(|| panic!("h2 cannot into_inner")) self.try_into_parts()
.unwrap_or_else(|| panic!("h2 cannot into_inner"))
} }
/// Return the inner IO object, and additional information, if available. /// Return the inner IO object, and additional information, if available.
@@ -492,7 +494,7 @@ where
service: dispatch.into_service(), service: dispatch.into_service(),
_inner: (), _inner: (),
}) })
}, }
ProtoServer::H2(_h2) => None, ProtoServer::H2(_h2) => None,
} }
} }
@@ -521,15 +523,13 @@ where
}; };
match ready!(polled) { match ready!(polled) {
Ok(x) => return Poll::Ready(Ok(x)), Ok(x) => return Poll::Ready(Ok(x)),
Err(e) => { Err(e) => match *e.kind() {
match *e.kind() {
Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => {
self.upgrade_h2(); self.upgrade_h2();
continue; continue;
} }
_ => return Poll::Ready(Err(e)), _ => return Poll::Ready(Err(e)),
} },
}
} }
} }
} }
@@ -554,9 +554,7 @@ where
let conn = self.conn.take(); let conn = self.conn.take();
let (io, read_buf, dispatch) = match conn.unwrap() { let (io, read_buf, dispatch) = match conn.unwrap() {
ProtoServer::H1(h1) => { ProtoServer::H1(h1) => h1.into_inner(),
h1.into_inner()
},
ProtoServer::H2(_h2) => { ProtoServer::H2(_h2) => {
panic!("h2 cannot into_inner"); panic!("h2 cannot into_inner");
} }
@@ -567,12 +565,7 @@ where
Fallback::ToHttp2(ref builder, ref exec) => (builder, exec), Fallback::ToHttp2(ref builder, ref exec) => (builder, exec),
Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"), Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"),
}; };
let h2 = proto::h2::Server::new( let h2 = proto::h2::Server::new(rewind_io, dispatch.into_service(), builder, exec.clone());
rewind_io,
dispatch.into_service(),
builder,
exec.clone(),
);
debug_assert!(self.conn.is_none()); debug_assert!(self.conn.is_none());
self.conn = Some(ProtoServer::H2(h2)); self.conn = Some(ProtoServer::H2(h2));
@@ -585,9 +578,7 @@ where
where where
I: Send, I: Send,
{ {
UpgradeableConnection { UpgradeableConnection { inner: self }
inner: self,
}
} }
} }
@@ -614,16 +605,14 @@ where
pending.manual(); pending.manual();
} }
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
}, }
Err(e) => { Err(e) => match *e.kind() {
match *e.kind() {
Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => {
self.upgrade_h2(); self.upgrade_h2();
continue; continue;
} }
_ => return Poll::Ready(Err(e)), _ => return Poll::Ready(Err(e)),
} },
}
} }
} }
} }
@@ -634,8 +623,7 @@ where
S: HttpService<Body>, S: HttpService<Body>,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Connection") f.debug_struct("Connection").finish()
.finish()
} }
} }
// ===== impl Serve ===== // ===== impl Serve =====
@@ -655,14 +643,9 @@ impl<I, S, E> Serve<I, S, E> {
/// Spawn all incoming connections onto the executor in `Http`. /// Spawn all incoming connections onto the executor in `Http`.
pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> { pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> {
SpawnAll { SpawnAll { serve: self }
serve: self,
} }
} }
}
impl<I, IO, IE, S, B, E> Serve<I, S, E> impl<I, IO, IE, S, B, E> Serve<I, S, E>
where where
@@ -673,7 +656,10 @@ where
B: Payload, B: Payload,
E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, E: H2Exec<<S::Service as HttpService<Body>>::Future, B>,
{ {
fn poll_next_(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Connecting<IO, S::Future, E>>>> { fn poll_next_(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<crate::Result<Connecting<IO, S::Future, E>>>> {
let me = self.project(); let me = self.project();
match ready!(me.make_service.poll_ready_ref(cx)) { match ready!(me.make_service.poll_ready_ref(cx)) {
Ok(()) => (), Ok(()) => (),
@@ -716,7 +702,6 @@ where
// ===== impl Connecting ===== // ===== impl Connecting =====
impl<I, F, S, FE, E, B> Future for Connecting<I, F, E> impl<I, F, S, FE, E, B> Future for Connecting<I, F, E>
where where
I: AsyncRead + AsyncWrite + Unpin, I: AsyncRead + AsyncWrite + Unpin,
@@ -756,15 +741,15 @@ where
I: Accept<Conn = IO, Error = IE>, I: Accept<Conn = IO, Error = IE>,
IE: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef< S: MakeServiceRef<IO, Body, ResBody = B>,
IO,
Body,
ResBody=B,
>,
B: Payload, B: Payload,
E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, E: H2Exec<<S::Service as HttpService<Body>>::Future, B>,
{ {
pub(super) fn poll_watch<W>(self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll<crate::Result<()>> pub(super) fn poll_watch<W>(
self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
watcher: &W,
) -> Poll<crate::Result<()>>
where where
E: NewSvcExec<IO, S::Future, S::Service, E, W>, E: NewSvcExec<IO, S::Future, S::Service, E, W>,
W: Watcher<IO, S::Service, E>, W: Watcher<IO, S::Service, E>,
@@ -773,7 +758,12 @@ where
loop { loop {
if let Some(connecting) = ready!(me.serve.as_mut().poll_next_(cx)?) { if let Some(connecting) = ready!(me.serve.as_mut().poll_next_(cx)?) {
let fut = NewSvcTask::new(connecting, watcher.clone()); let fut = NewSvcTask::new(connecting, watcher.clone());
me.serve.as_mut().project().protocol.exec.execute_new_svc(fut); me.serve
.as_mut()
.project()
.protocol
.exec
.execute_new_svc(fut);
} else { } else {
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} }
@@ -808,11 +798,11 @@ pub(crate) mod spawn_all {
use std::error::Error as StdError; use std::error::Error as StdError;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use super::{Connecting, UpgradeableConnection};
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::H2Exec; use crate::common::exec::H2Exec;
use crate::common::{Future, Pin, Poll, Unpin, task}; use crate::common::{task, Future, Pin, Poll, Unpin};
use crate::service::HttpService; use crate::service::HttpService;
use super::{Connecting, UpgradeableConnection};
use pin_project::{pin_project, project}; use pin_project::{pin_project, project};
// Used by `SpawnAll` to optionally watch a `Connection` future. // Used by `SpawnAll` to optionally watch a `Connection` future.
@@ -914,11 +904,9 @@ pub(crate) mod spawn_all {
}; };
let connected = watcher.watch(conn.with_upgrades()); let connected = watcher.watch(conn.with_upgrades());
State::Connected(connected) State::Connected(connected)
}, }
State::Connected(future) => { State::Connected(future) => {
return future return future.poll(cx).map(|res| {
.poll(cx)
.map(|res| {
if let Err(err) = res { if let Err(err) = res {
debug!("connection error: {}", err); debug!("connection error: {}", err);
} }
@@ -991,19 +979,16 @@ mod upgrades {
let (io, buf, _) = h1.into_inner(); let (io, buf, _) = h1.into_inner();
pending.fulfill(Upgraded::new(Box::new(io), buf)); pending.fulfill(Upgraded::new(Box::new(io), buf));
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
}, }
Err(e) => { Err(e) => match *e.kind() {
match *e.kind() {
Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => { Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => {
self.inner.upgrade_h2(); self.inner.upgrade_h2();
continue; continue;
} }
_ => return Poll::Ready(Err(e)), _ => return Poll::Ready(Err(e)),
},
} }
} }
} }
} }
} }
}
}

View File

@@ -51,27 +51,31 @@
pub mod accept; pub mod accept;
pub mod conn; pub mod conn;
mod shutdown; mod shutdown;
#[cfg(feature = "tcp")] mod tcp; #[cfg(feature = "tcp")]
mod tcp;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
#[cfg(feature = "tcp")] use std::net::{SocketAddr, TcpListener as StdTcpListener}; #[cfg(feature = "tcp")]
use std::net::{SocketAddr, TcpListener as StdTcpListener};
#[cfg(feature = "tcp")] use std::time::Duration; #[cfg(feature = "tcp")]
use std::time::Duration;
use tokio::io::{AsyncRead, AsyncWrite};
use pin_project::pin_project; use pin_project::pin_project;
use tokio::io::{AsyncRead, AsyncWrite};
use self::accept::Accept;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::{Exec, H2Exec, NewSvcExec}; use crate::common::exec::{Exec, H2Exec, NewSvcExec};
use crate::common::{Future, Pin, Poll, Unpin, task}; use crate::common::{task, Future, Pin, Poll, Unpin};
use crate::service::{MakeServiceRef, HttpService}; use crate::service::{HttpService, MakeServiceRef};
use self::accept::Accept;
// Renamed `Http` as `Http_` for now so that people upgrading don't see an // Renamed `Http` as `Http_` for now so that people upgrading don't see an
// error that `hyper::server::Http` is private... // error that `hyper::server::Http` is private...
use self::conn::{Http as Http_, NoopWatcher, SpawnAll}; use self::conn::{Http as Http_, NoopWatcher, SpawnAll};
use self::shutdown::{Graceful, GracefulWatcher}; use self::shutdown::{Graceful, GracefulWatcher};
#[cfg(feature = "tcp")] use self::tcp::AddrIncoming; #[cfg(feature = "tcp")]
use self::tcp::AddrIncoming;
/// A listening HTTP server that accepts connections in both HTTP1 and HTTP2 by default. /// A listening HTTP server that accepts connections in both HTTP1 and HTTP2 by default.
/// ///
@@ -113,8 +117,7 @@ impl Server<AddrIncoming, ()> {
/// This method will panic if binding to the address fails. For a method /// This method will panic if binding to the address fails. For a method
/// to bind to an address and return a `Result`, see `Server::try_bind`. /// to bind to an address and return a `Result`, see `Server::try_bind`.
pub fn bind(addr: &SocketAddr) -> Builder<AddrIncoming> { pub fn bind(addr: &SocketAddr) -> Builder<AddrIncoming> {
let incoming = AddrIncoming::new(addr) let incoming = AddrIncoming::new(addr).unwrap_or_else(|e| {
.unwrap_or_else(|e| {
panic!("error binding to {}: {}", addr, e); panic!("error binding to {}: {}", addr, e);
}); });
Server::builder(incoming) Server::builder(incoming)
@@ -122,14 +125,12 @@ impl Server<AddrIncoming, ()> {
/// Tries to bind to the provided address, and returns a [`Builder`](Builder). /// Tries to bind to the provided address, and returns a [`Builder`](Builder).
pub fn try_bind(addr: &SocketAddr) -> crate::Result<Builder<AddrIncoming>> { pub fn try_bind(addr: &SocketAddr) -> crate::Result<Builder<AddrIncoming>> {
AddrIncoming::new(addr) AddrIncoming::new(addr).map(Server::builder)
.map(Server::builder)
} }
/// Create a new instance from a `std::net::TcpListener` instance. /// Create a new instance from a `std::net::TcpListener` instance.
pub fn from_tcp(listener: StdTcpListener) -> Result<Builder<AddrIncoming>, crate::Error> { pub fn from_tcp(listener: StdTcpListener) -> Result<Builder<AddrIncoming>, crate::Error> {
AddrIncoming::from_std(listener) AddrIncoming::from_std(listener).map(Server::builder)
.map(Server::builder)
} }
} }
@@ -191,7 +192,7 @@ where
/// ``` /// ```
pub fn with_graceful_shutdown<F>(self, signal: F) -> Graceful<I, S, F, E> pub fn with_graceful_shutdown<F>(self, signal: F) -> Graceful<I, S, F, E>
where where
F: Future<Output=()> F: Future<Output = ()>,
{ {
Graceful::new(self.spawn_all, signal) Graceful::new(self.spawn_all, signal)
} }
@@ -231,10 +232,7 @@ impl<I, E> Builder<I, E> {
/// ///
/// For a more convenient constructor, see [`Server::bind`](Server::bind). /// For a more convenient constructor, see [`Server::bind`](Server::bind).
pub fn new(incoming: I, protocol: Http_<E>) -> Self { pub fn new(incoming: I, protocol: Http_<E>) -> Self {
Builder { Builder { incoming, protocol }
incoming,
protocol,
}
} }
/// Sets whether to use keep-alive for HTTP/1 connections. /// Sets whether to use keep-alive for HTTP/1 connections.
@@ -245,7 +243,6 @@ impl<I, E> Builder<I, E> {
self self
} }
/// Set whether HTTP/1 connections should support half-closures. /// Set whether HTTP/1 connections should support half-closures.
/// ///
/// Clients can chose to shutdown their write-side while waiting /// Clients can chose to shutdown their write-side while waiting
@@ -319,7 +316,8 @@ impl<I, E> Builder<I, E> {
/// ///
/// If not set, hyper will use a default. /// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(mut self, sz: impl Into<Option<u32>>) -> Self { pub fn http2_initial_connection_window_size(mut self, sz: impl Into<Option<u32>>) -> Self {
self.protocol.http2_initial_connection_window_size(sz.into()); self.protocol
.http2_initial_connection_window_size(sz.into());
self self
} }
@@ -396,9 +394,7 @@ impl<I, E> Builder<I, E> {
{ {
let serve = self.protocol.serve(self.incoming, new_service); let serve = self.protocol.serve(self.incoming, new_service);
let spawn_all = serve.spawn_all(); let spawn_all = serve.spawn_all();
Server { Server { spawn_all }
spawn_all,
}
} }
} }
@@ -440,4 +436,3 @@ impl<E> Builder<AddrIncoming, E> {
self self
} }
} }

View File

@@ -1,15 +1,15 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use tokio::io::{AsyncRead, AsyncWrite};
use pin_project::{pin_project, project}; use pin_project::{pin_project, project};
use tokio::io::{AsyncRead, AsyncWrite};
use super::conn::{SpawnAll, UpgradeableConnection, Watcher};
use super::Accept;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::drain::{self, Draining, Signal, Watch, Watching}; use crate::common::drain::{self, Draining, Signal, Watch, Watching};
use crate::common::exec::{H2Exec, NewSvcExec}; use crate::common::exec::{H2Exec, NewSvcExec};
use crate::common::{Future, Pin, Poll, Unpin, task}; use crate::common::{task, Future, Pin, Poll, Unpin};
use crate::service::{MakeServiceRef, HttpService}; use crate::service::{HttpService, MakeServiceRef};
use super::Accept;
use super::conn::{SpawnAll, UpgradeableConnection, Watcher};
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
#[pin_project] #[pin_project]
@@ -43,7 +43,6 @@ impl<I, S, F, E> Graceful<I, S, F, E> {
} }
} }
impl<I, IO, IE, S, B, F, E> Future for Graceful<I, S, F, E> impl<I, IO, IE, S, B, F, E> Future for Graceful<I, S, F, E>
where where
I: Accept<Conn = IO, Error = IE>, I: Accept<Conn = IO, Error = IE>,
@@ -73,20 +72,13 @@ where
} => match signal.poll(cx) { } => match signal.poll(cx) {
Poll::Ready(()) => { Poll::Ready(()) => {
debug!("signal received, starting graceful shutdown"); debug!("signal received, starting graceful shutdown");
let sig = drain let sig = drain.take().expect("drain channel").0;
.take()
.expect("drain channel")
.0;
State::Draining(sig.drain()) State::Draining(sig.drain())
}, }
Poll::Pending => { Poll::Pending => {
let watch = drain let watch = drain.as_ref().expect("drain channel").1.clone();
.as_ref()
.expect("drain channel")
.1
.clone();
return spawn_all.poll_watch(cx, &GracefulWatcher(watch)); return spawn_all.poll_watch(cx, &GracefulWatcher(watch));
}, }
}, },
State::Draining(ref mut draining) => { State::Draining(ref mut draining) => {
return Pin::new(draining).poll(cx).map(Ok); return Pin::new(draining).poll(cx).map(Ok);
@@ -109,13 +101,11 @@ where
<S::ResBody as Payload>::Data: Unpin, <S::ResBody as Payload>::Data: Unpin,
E: H2Exec<S::Future, S::ResBody>, E: H2Exec<S::Future, S::ResBody>,
{ {
type Future = Watching<UpgradeableConnection<I, S, E>, fn(Pin<&mut UpgradeableConnection<I, S, E>>)>; type Future =
Watching<UpgradeableConnection<I, S, E>, fn(Pin<&mut UpgradeableConnection<I, S, E>>)>;
fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future { fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future {
self self.0.clone().watch(conn, on_drain)
.0
.clone()
.watch(conn, on_drain)
} }
} }
@@ -130,4 +120,3 @@ where
{ {
conn.graceful_shutdown() conn.graceful_shutdown()
} }

View File

@@ -7,10 +7,10 @@ use futures_util::FutureExt as _;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::time::Delay; use tokio::time::Delay;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
use super::Accept;
pub use self::addr_stream::AddrStream; pub use self::addr_stream::AddrStream;
use super::Accept;
/// A stream of connections from binding to an address. /// A stream of connections from binding to an address.
#[must_use = "streams do nothing unless polled"] #[must_use = "streams do nothing unless polled"]
@@ -25,15 +25,13 @@ pub struct AddrIncoming {
impl AddrIncoming { impl AddrIncoming {
pub(super) fn new(addr: &SocketAddr) -> crate::Result<Self> { pub(super) fn new(addr: &SocketAddr) -> crate::Result<Self> {
let std_listener = StdTcpListener::bind(addr) let std_listener = StdTcpListener::bind(addr).map_err(crate::Error::new_listen)?;
.map_err(crate::Error::new_listen)?;
AddrIncoming::from_std(std_listener) AddrIncoming::from_std(std_listener)
} }
pub(super) fn from_std(std_listener: StdTcpListener) -> crate::Result<Self> { pub(super) fn from_std(std_listener: StdTcpListener) -> crate::Result<Self> {
let listener = TcpListener::from_std(std_listener) let listener = TcpListener::from_std(std_listener).map_err(crate::Error::new_listen)?;
.map_err(crate::Error::new_listen)?;
let addr = listener.local_addr().map_err(crate::Error::new_listen)?; let addr = listener.local_addr().map_err(crate::Error::new_listen)?;
Ok(AddrIncoming { Ok(AddrIncoming {
listener, listener,
@@ -115,7 +113,7 @@ impl AddrIncoming {
trace!("error trying to set TCP nodelay: {}", e); trace!("error trying to set TCP nodelay: {}", e);
} }
return Poll::Ready(Ok(AddrStream::new(socket, addr))); return Poll::Ready(Ok(AddrStream::new(socket, addr)));
}, }
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => { Poll::Ready(Err(e)) => {
// Connection errors can be ignored directly, continue by // Connection errors can be ignored directly, continue by
@@ -134,17 +132,17 @@ impl AddrIncoming {
match Pin::new(&mut timeout).poll(cx) { match Pin::new(&mut timeout).poll(cx) {
Poll::Ready(()) => { Poll::Ready(()) => {
// Wow, it's been a second already? Ok then... // Wow, it's been a second already? Ok then...
continue continue;
}, }
Poll::Pending => { Poll::Pending => {
self.timeout = Some(timeout); self.timeout = Some(timeout);
return Poll::Pending; return Poll::Pending;
}, }
} }
} else { } else {
return Poll::Ready(Err(e)); return Poll::Ready(Err(e));
} }
}, }
} }
} }
} }
@@ -154,7 +152,10 @@ impl Accept for AddrIncoming {
type Conn = AddrStream; type Conn = AddrStream;
type Error = io::Error; type Error = io::Error;
fn poll_accept(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Conn, Self::Error>>> { fn poll_accept(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
let result = ready!(self.poll_next_(cx)); let result = ready!(self.poll_next_(cx));
Poll::Ready(Some(result)) Poll::Ready(Some(result))
} }
@@ -169,9 +170,9 @@ impl Accept for AddrIncoming {
/// and EMFILE. Otherwise, could enter into tight loop. /// and EMFILE. Otherwise, could enter into tight loop.
fn is_connection_error(e: &io::Error) -> bool { fn is_connection_error(e: &io::Error) -> bool {
match e.kind() { match e.kind() {
io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionRefused
io::ErrorKind::ConnectionAborted | | io::ErrorKind::ConnectionAborted
io::ErrorKind::ConnectionReset => true, | io::ErrorKind::ConnectionReset => true,
_ => false, _ => false,
} }
} }
@@ -188,14 +189,13 @@ impl fmt::Debug for AddrIncoming {
} }
mod addr_stream { mod addr_stream {
use bytes::{Buf, BufMut};
use std::io; use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use bytes::{Buf, BufMut};
use tokio::net::TcpStream;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use crate::common::{Pin, Poll, task}; use crate::common::{task, Pin, Poll};
/// A transport returned yieled by `AddrIncoming`. /// A transport returned yieled by `AddrIncoming`.
#[derive(Debug)] #[derive(Debug)]
@@ -226,29 +226,48 @@ mod addr_stream {
} }
impl AsyncRead for AddrStream { impl AsyncRead for AddrStream {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [std::mem::MaybeUninit<u8>]) -> bool { unsafe fn prepare_uninitialized_buffer(
&self,
buf: &mut [std::mem::MaybeUninit<u8>],
) -> bool {
self.inner.prepare_uninitialized_buffer(buf) self.inner.prepare_uninitialized_buffer(buf)
} }
#[inline] #[inline]
fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_read(cx, buf) Pin::new(&mut self.inner).poll_read(cx, buf)
} }
#[inline] #[inline]
fn poll_read_buf<B: BufMut>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { fn poll_read_buf<B: BufMut>(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut B,
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_read_buf(cx, buf) Pin::new(&mut self.inner).poll_read_buf(cx, buf)
} }
} }
impl AsyncWrite for AddrStream { impl AsyncWrite for AddrStream {
#[inline] #[inline]
fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write(cx, buf) Pin::new(&mut self.inner).poll_write(cx, buf)
} }
#[inline] #[inline]
fn poll_write_buf<B: Buf>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { fn poll_write_buf<B: Buf>(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut B,
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write_buf(cx, buf) Pin::new(&mut self.inner).poll_write_buf(cx, buf)
} }
@@ -259,7 +278,10 @@ mod addr_stream {
} }
#[inline] #[inline]
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_shutdown(cx) Pin::new(&mut self.inner).poll_shutdown(cx)
} }
} }

View File

@@ -1,7 +1,7 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use crate::body::Payload; use crate::body::Payload;
use crate::common::{Future, Poll, task}; use crate::common::{task, Future, Poll};
use crate::{Request, Response}; use crate::{Request, Response};
/// An asynchronous function from `Request` to `Response`. /// An asynchronous function from `Request` to `Response`.
@@ -50,9 +50,9 @@ impl<T, B1, B2> sealed::Sealed<B1> for T
where where
T: tower_service::Service<Request<B1>, Response = Response<B2>>, T: tower_service::Service<Request<B1>, Response = Response<B2>>,
B2: Payload, B2: Payload,
{} {
}
mod sealed { mod sealed {
pub trait Sealed<T> {} pub trait Sealed<T> {}
} }

View File

@@ -3,9 +3,9 @@ use std::fmt;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use crate::body::Payload;
use crate::common::{Future, Poll, task};
use super::{HttpService, Service}; use super::{HttpService, Service};
use crate::body::Payload;
use crate::common::{task, Future, Poll};
// The same "trait alias" as tower::MakeConnection, but inlined to reduce // The same "trait alias" as tower::MakeConnection, but inlined to reduce
// dependencies. // dependencies.
@@ -44,11 +44,7 @@ where
pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody)> { pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody)> {
type ResBody: Payload; type ResBody: Payload;
type Error: Into<Box<dyn StdError + Send + Sync>>; type Error: Into<Box<dyn StdError + Send + Sync>>;
type Service: HttpService< type Service: HttpService<ReqBody, ResBody = Self::ResBody, Error = Self::Error>;
ReqBody,
ResBody=Self::ResBody,
Error=Self::Error,
>;
type MakeError: Into<Box<dyn StdError + Send + Sync>>; type MakeError: Into<Box<dyn StdError + Send + Sync>>;
type Future: Future<Output = Result<Self::Service, Self::MakeError>>; type Future: Future<Output = Result<Self::Service, Self::MakeError>>;
@@ -145,9 +141,7 @@ where
F: FnMut(&Target) -> Ret, F: FnMut(&Target) -> Ret,
Ret: Future, Ret: Future,
{ {
MakeServiceFn { MakeServiceFn { f }
f,
}
} }
// Not exported from crate as this will likely be replaced with `impl Service`. // Not exported from crate as this will likely be replaced with `impl Service`.
@@ -176,8 +170,7 @@ where
impl<F> fmt::Debug for MakeServiceFn<F> { impl<F> fmt::Debug for MakeServiceFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MakeServiceFn") f.debug_struct("MakeServiceFn").finish()
.finish()
} }
} }

View File

@@ -41,10 +41,9 @@ mod make;
mod oneshot; mod oneshot;
mod util; mod util;
pub(crate) use self::make::{MakeConnection, MakeServiceRef};
pub(crate) use self::http::HttpService; pub(crate) use self::http::HttpService;
pub(crate) use self::make::{MakeConnection, MakeServiceRef};
pub(crate) use self::oneshot::{oneshot, Oneshot}; pub(crate) use self::oneshot::{oneshot, Oneshot};
pub use self::make::make_service_fn; pub use self::make::make_service_fn;
pub use self::util::service_fn; pub use self::util::service_fn;

View File

@@ -1,11 +1,11 @@
// TODO: Eventually to be replaced with tower_util::Oneshot. // TODO: Eventually to be replaced with tower_util::Oneshot.
use std::mem;
use std::marker::Unpin; use std::marker::Unpin;
use std::mem;
use tower_service::Service; use tower_service::Service;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
pub(crate) fn oneshot<S, Req>(svc: S, req: Req) -> Oneshot<S, Req> pub(crate) fn oneshot<S, Req>(svc: S, req: Req) -> Oneshot<S, Req>
where where
@@ -35,7 +35,8 @@ impl<S, Req> Unpin for Oneshot<S, Req>
where where
S: Service<Req>, S: Service<Req>,
S::Future: Unpin, S::Future: Unpin,
{} {
}
impl<S, Req> Future for Oneshot<S, Req> impl<S, Req> Future for Oneshot<S, Req>
where where
@@ -52,17 +53,17 @@ where
State::NotReady(ref mut svc, _) => { State::NotReady(ref mut svc, _) => {
ready!(svc.poll_ready(cx))?; ready!(svc.poll_ready(cx))?;
// fallthrough out of the match's borrow // fallthrough out of the match's borrow
}, }
State::Called(ref mut fut) => { State::Called(ref mut fut) => {
return unsafe { Pin::new_unchecked(fut) }.poll(cx); return unsafe { Pin::new_unchecked(fut) }.poll(cx);
}, }
State::Tmp => unreachable!(), State::Tmp => unreachable!(),
} }
match mem::replace(&mut me.state, State::Tmp) { match mem::replace(&mut me.state, State::Tmp) {
State::NotReady(mut svc, req) => { State::NotReady(mut svc, req) => {
me.state = State::Called(svc.call(req)); me.state = State::Called(svc.call(req));
}, }
_ => unreachable!(), _ => unreachable!(),
} }
} }

View File

@@ -3,7 +3,7 @@ use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::body::Payload; use crate::body::Payload;
use crate::common::{Future, Poll, task}; use crate::common::{task, Future, Poll};
use crate::{Request, Response}; use crate::{Request, Response};
/// Create a `Service` from a function. /// Create a `Service` from a function.
@@ -41,7 +41,8 @@ pub struct ServiceFn<F, R> {
_req: PhantomData<fn(R)>, _req: PhantomData<fn(R)>,
} }
impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>> for ServiceFn<F, ReqBody> impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>>
for ServiceFn<F, ReqBody>
where where
F: FnMut(Request<ReqBody>) -> Ret, F: FnMut(Request<ReqBody>) -> Ret,
ReqBody: Payload, ReqBody: Payload,
@@ -64,7 +65,6 @@ where
impl<F, R> fmt::Debug for ServiceFn<F, R> { impl<F, R> fmt::Debug for ServiceFn<F, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("impl Service") f.debug_struct("impl Service").finish()
.finish()
} }
} }

View File

@@ -11,12 +11,12 @@ use std::fmt;
use std::io; use std::io;
use std::marker::Unpin; use std::marker::Unpin;
use bytes::{/*Buf, BufMut, */Bytes}; use bytes::Bytes;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use crate::common::io::Rewind; use crate::common::io::Rewind;
use crate::common::{Future, Pin, Poll, task}; use crate::common::{task, Future, Pin, Poll};
/// An upgraded HTTP connection. /// An upgraded HTTP connection.
/// ///
@@ -58,7 +58,7 @@ pub struct Parts<T> {
} }
pub(crate) struct Pending { pub(crate) struct Pending {
tx: oneshot::Sender<crate::Result<Upgraded>> tx: oneshot::Sender<crate::Result<Upgraded>>,
} }
/// Error cause returned when an upgrade was expected but canceled /// Error cause returned when an upgrade was expected but canceled
@@ -70,14 +70,7 @@ struct UpgradeExpected(());
pub(crate) fn pending() -> (Pending, OnUpgrade) { pub(crate) fn pending() -> (Pending, OnUpgrade) {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
( (Pending { tx }, OnUpgrade { rx: Some(rx) })
Pending {
tx,
},
OnUpgrade {
rx: Some(rx),
},
)
} }
pub(crate) trait Io: AsyncRead + AsyncWrite + Unpin + 'static { pub(crate) trait Io: AsyncRead + AsyncWrite + Unpin + 'static {
@@ -130,7 +123,7 @@ impl Upgraded {
}), }),
Err(io) => Err(Upgraded { Err(io) => Err(Upgraded {
io: Rewind::new_buffered(io, buf), io: Rewind::new_buffered(io, buf),
}) }),
} }
} }
} }
@@ -140,13 +133,21 @@ impl AsyncRead for Upgraded {
self.io.prepare_uninitialized_buffer(buf) self.io.prepare_uninitialized_buffer(buf)
} }
fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.io).poll_read(cx, buf) Pin::new(&mut self.io).poll_read(cx, buf)
} }
} }
impl AsyncWrite for Upgraded { impl AsyncWrite for Upgraded {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.io).poll_write(cx, buf) Pin::new(&mut self.io).poll_write(cx, buf)
} }
@@ -161,8 +162,7 @@ impl AsyncWrite for Upgraded {
impl fmt::Debug for Upgraded { impl fmt::Debug for Upgraded {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Upgraded") f.debug_struct("Upgraded").finish()
.finish()
} }
} }
@@ -170,9 +170,7 @@ impl fmt::Debug for Upgraded {
impl OnUpgrade { impl OnUpgrade {
pub(crate) fn none() -> Self { pub(crate) fn none() -> Self {
OnUpgrade { OnUpgrade { rx: None }
rx: None,
}
} }
pub(crate) fn is_none(&self) -> bool { pub(crate) fn is_none(&self) -> bool {
@@ -188,9 +186,9 @@ impl Future for OnUpgrade {
Some(ref mut rx) => Pin::new(rx).poll(cx).map(|res| match res { Some(ref mut rx) => Pin::new(rx).poll(cx).map(|res| match res {
Ok(Ok(upgraded)) => Ok(upgraded), Ok(Ok(upgraded)) => Ok(upgraded),
Ok(Err(err)) => Err(err), Ok(Err(err)) => Err(err),
Err(_oneshot_canceled) => Err( Err(_oneshot_canceled) => {
crate::Error::new_canceled().with(UpgradeExpected(())) Err(crate::Error::new_canceled().with(UpgradeExpected(())))
), }
}), }),
None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())), None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())),
} }
@@ -199,8 +197,7 @@ impl Future for OnUpgrade {
impl fmt::Debug for OnUpgrade { impl fmt::Debug for OnUpgrade {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OnUpgrade") f.debug_struct("OnUpgrade").finish()
.finish()
} }
} }
@@ -233,4 +230,3 @@ impl StdError for UpgradeExpected {
"upgrade expected but not completed" "upgrade expected but not completed"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -337,4 +337,3 @@ t! {
http2_parallel_10, http2_parallel_10,
parallel: 0..10 parallel: 0..10
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,20 @@
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::{Arc, Mutex, atomic::{AtomicUsize, Ordering}}; use std::sync::{
use std::time::{Duration/*, Instant*/}; atomic::{AtomicUsize, Ordering},
Arc, Mutex,
};
use std::time::Duration;
use hyper::{Body, Client, Request, Response, Server, Version};
use hyper::client::HttpConnector; use hyper::client::HttpConnector;
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Client, Request, Response, Server, Version};
pub use std::net::SocketAddr; pub use futures_util::{
pub use futures_util::{future, FutureExt as _, StreamExt as _, TryFutureExt as _, TryStreamExt as _}; future, FutureExt as _, StreamExt as _, TryFutureExt as _, TryStreamExt as _,
};
pub use hyper::{HeaderMap, StatusCode}; pub use hyper::{HeaderMap, StatusCode};
pub use std::net::SocketAddr;
macro_rules! t { macro_rules! t {
( (
@@ -154,43 +159,43 @@ macro_rules! t {
} }
macro_rules! __internal_map_prop { macro_rules! __internal_map_prop {
(headers: $map:tt) => ({ (headers: $map:tt) => {{
#[allow(unused_mut)] #[allow(unused_mut)]
{ {
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
__internal_headers_map!(headers, $map); __internal_headers_map!(headers, $map);
headers headers
} }
}); }};
($name:tt: $val:tt) => ({ ($name:tt: $val:tt) => {{
__internal_req_res_prop!($name: $val) __internal_req_res_prop!($name: $val)
}); }};
} }
macro_rules! __internal_eq_prop { macro_rules! __internal_eq_prop {
(headers: $map:tt) => ({ (headers: $map:tt) => {{
#[allow(unused_mut)] #[allow(unused_mut)]
{ {
let mut headers = Vec::new(); let mut headers = Vec::new();
__internal_headers_eq!(headers, $map); __internal_headers_eq!(headers, $map);
headers headers
} }
}); }};
($name:tt: $val:tt) => ({ ($name:tt: $val:tt) => {{
__internal_req_res_prop!($name: $val) __internal_req_res_prop!($name: $val)
}); }};
} }
macro_rules! __internal_req_res_prop { macro_rules! __internal_req_res_prop {
(method: $prop_val:expr) => ( (method: $prop_val:expr) => {
$prop_val $prop_val
); };
(status: $prop_val:expr) => ( (status: $prop_val:expr) => {
StatusCode::from_u16($prop_val).expect("status code") StatusCode::from_u16($prop_val).expect("status code")
); };
($prop_name:ident: $prop_val:expr) => ( ($prop_name:ident: $prop_val:expr) => {
From::from($prop_val) From::from($prop_val)
) };
} }
macro_rules! __internal_headers_map { macro_rules! __internal_headers_map {
@@ -325,9 +330,7 @@ async fn async_test(cfg: __TestConfig) {
.http2_only(cfg.client_version == 2) .http2_only(cfg.client_version == 2)
.build::<_, Body>(connector); .build::<_, Body>(connector);
let serve_handles = Arc::new(Mutex::new( let serve_handles = Arc::new(Mutex::new(cfg.server_msgs));
cfg.server_msgs
));
let expected_connections = cfg.connections; let expected_connections = cfg.connections;
let mut cnt = 0; let mut cnt = 0;
@@ -343,9 +346,7 @@ async fn async_test(cfg: __TestConfig) {
// Move a clone into the service_fn // Move a clone into the service_fn
let serve_handles = serve_handles.clone(); let serve_handles = serve_handles.clone();
future::ok::<_, hyper::Error>(service_fn(move |req: Request<Body>| { future::ok::<_, hyper::Error>(service_fn(move |req: Request<Body>| {
let (sreq, sres) = serve_handles.lock() let (sreq, sres) = serve_handles.lock().unwrap().remove(0);
.unwrap()
.remove(0);
assert_eq!(req.uri().path(), sreq.uri, "client path"); assert_eq!(req.uri().path(), sreq.uri, "client path");
assert_eq!(req.method(), &sreq.method, "client method"); assert_eq!(req.method(), &sreq.method, "client method");
@@ -354,8 +355,7 @@ async fn async_test(cfg: __TestConfig) {
func(&req.headers()); func(&req.headers());
} }
let sbody = sreq.body; let sbody = sreq.body;
concat(req.into_body()) concat(req.into_body()).map_ok(move |body| {
.map_ok(move |body| {
assert_eq!(body.as_ref(), sbody.as_slice(), "client body"); assert_eq!(body.as_ref(), sbody.as_slice(), "client body");
let mut res = Response::builder() let mut res = Response::builder()
@@ -388,7 +388,8 @@ async fn async_test(cfg: __TestConfig) {
addr = proxy_addr; addr = proxy_addr;
} }
let make_request = Arc::new(move |client: &Client<HttpConnector>, creq: __CReq, cres: __CRes| { let make_request = Arc::new(
move |client: &Client<HttpConnector>, creq: __CReq, cres: __CRes| {
let uri = format!("http://{}{}", addr, creq.uri); let uri = format!("http://{}{}", addr, creq.uri);
let mut req = Request::builder() let mut req = Request::builder()
.method(creq.method) .method(creq.method)
@@ -401,7 +402,8 @@ async fn async_test(cfg: __TestConfig) {
let cheaders = cres.headers; let cheaders = cres.headers;
let cbody = cres.body; let cbody = cres.body;
client.request(req) client
.request(req)
.and_then(move |res| { .and_then(move |res| {
assert_eq!(res.status(), cstatus, "server status"); assert_eq!(res.status(), cstatus, "server status");
assert_eq!(res.version(), version, "server version"); assert_eq!(res.version(), version, "server version");
@@ -414,8 +416,8 @@ async fn async_test(cfg: __TestConfig) {
assert_eq!(body.as_ref(), cbody.as_slice(), "server body"); assert_eq!(body.as_ref(), cbody.as_slice(), "server body");
}) })
.map(|res| res.expect("client error")) .map(|res| res.expect("client error"))
}); },
);
let client_futures: Pin<Box<dyn Future<Output = ()> + Send>> = if cfg.parallel { let client_futures: Pin<Box<dyn Future<Output = ()> + Send>> = if cfg.parallel {
let mut client_futures = vec![]; let mut client_futures = vec![];
@@ -429,13 +431,10 @@ async fn async_test(cfg: __TestConfig) {
Box::pin(future::ready(client)); Box::pin(future::ready(client));
for (creq, cres) in cfg.client_msgs { for (creq, cres) in cfg.client_msgs {
let mk_request = make_request.clone(); let mk_request = make_request.clone();
client_futures = Box::pin( client_futures = Box::pin(client_futures.then(move |client| {
client_futures
.then(move |client| {
let fut = mk_request(&client, creq, cres); let fut = mk_request(&client, creq, cres);
fut.map(move |()| client) fut.map(move |()| client)
}) }));
);
} }
Box::pin(client_futures.map(|_| ())) Box::pin(client_futures.map(|_| ()))
}; };
@@ -459,8 +458,7 @@ fn naive_proxy(cfg: ProxyConfig) -> (SocketAddr, impl Future<Output = ()>) {
let max_connections = cfg.connections; let max_connections = cfg.connections;
let counter = AtomicUsize::new(0); let counter = AtomicUsize::new(0);
let srv = Server::bind(&([127, 0, 0, 1], 0).into()) let srv = Server::bind(&([127, 0, 0, 1], 0).into()).serve(make_service_fn(move |_| {
.serve(make_service_fn(move |_| {
let prev = counter.fetch_add(1, Ordering::Relaxed); let prev = counter.fetch_add(1, Ordering::Relaxed);
assert!(max_connections >= prev + 1, "proxy max connections"); assert!(max_connections >= prev + 1, "proxy max connections");
let client = client.clone(); let client = client.clone();