split Client into (Client, Connection) (#107)
The Connection type is a `Future` that drives all of the IO of the client connection. The Client type is separate, and is used to send requests into the connection.
This commit is contained in:
@@ -67,7 +67,7 @@ pub fn main() {
|
|||||||
Client::handshake(tls)
|
Client::handshake(tls)
|
||||||
})
|
})
|
||||||
.then(|res| {
|
.then(|res| {
|
||||||
let mut h2 = res.unwrap();
|
let (mut client, h2) = res.unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
@@ -75,7 +75,7 @@ pub fn main() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stream = h2.send_request(request, true).unwrap();
|
let stream = client.send_request(request, true).unwrap();
|
||||||
|
|
||||||
let stream = stream.and_then(|response| {
|
let stream = stream.and_then(|response| {
|
||||||
let (_, body) = response.into_parts();
|
let (_, body) = response.into_parts();
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ pub fn main() {
|
|||||||
let tcp = io_dump::Dump::to_stdout(res.unwrap());
|
let tcp = io_dump::Dump::to_stdout(res.unwrap());
|
||||||
Client::handshake(tcp)
|
Client::handshake(tcp)
|
||||||
}).then(|res| {
|
}).then(|res| {
|
||||||
let mut client = res.unwrap();
|
let (mut client, h2) = res.unwrap();
|
||||||
|
|
||||||
println!("sending request");
|
println!("sending request");
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ pub fn main() {
|
|||||||
// send trailers
|
// send trailers
|
||||||
stream.send_trailers(trailers).unwrap();
|
stream.send_trailers(trailers).unwrap();
|
||||||
|
|
||||||
// Spawn a task to run the client...
|
// Spawn a task to run the conn...
|
||||||
handle.spawn(client.map_err(|e| println!("GOT ERR={:?}", e)));
|
handle.spawn(h2.map_err(|e| println!("GOT ERR={:?}", e)));
|
||||||
|
|
||||||
stream
|
stream
|
||||||
.and_then(|response| {
|
.and_then(|response| {
|
||||||
|
|||||||
120
src/client.rs
120
src/client.rs
@@ -1,7 +1,7 @@
|
|||||||
use codec::{Codec, RecvError};
|
use codec::{Codec, RecvError};
|
||||||
use frame::{Headers, Pseudo, Settings, StreamId};
|
use frame::{Headers, Pseudo, Settings, StreamId};
|
||||||
use frame::Reason::*;
|
use frame::Reason::*;
|
||||||
use proto::{self, Connection, WindowSize};
|
use proto::{self, WindowSize};
|
||||||
|
|
||||||
use bytes::{Bytes, IntoBuf};
|
use bytes::{Bytes, IntoBuf};
|
||||||
use futures::{Async, Future, MapErr, Poll};
|
use futures::{Async, Future, MapErr, Poll};
|
||||||
@@ -21,8 +21,13 @@ pub struct Handshake<T: AsyncRead + AsyncWrite, B: IntoBuf = Bytes> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Marker type indicating a client peer
|
/// Marker type indicating a client peer
|
||||||
pub struct Client<T, B: IntoBuf> {
|
pub struct Client<B: IntoBuf> {
|
||||||
connection: Connection<T, Peer, B>,
|
inner: proto::Streams<B::Buf, Peer>,
|
||||||
|
pending: Option<proto::StreamKey>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Connection<T, B: IntoBuf> {
|
||||||
|
inner: proto::Connection<T, Peer, B>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -45,10 +50,9 @@ pub struct Builder {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Peer;
|
pub(crate) struct Peer;
|
||||||
|
|
||||||
impl<T> Client<T, Bytes>
|
// ===== impl Client =====
|
||||||
where
|
|
||||||
T: AsyncRead + AsyncWrite,
|
impl Client<Bytes> {
|
||||||
{
|
|
||||||
/// Bind an H2 client connection.
|
/// Bind an H2 client connection.
|
||||||
///
|
///
|
||||||
/// Returns a future which resolves to the connection value once the H2
|
/// Returns a future which resolves to the connection value once the H2
|
||||||
@@ -56,24 +60,29 @@ where
|
|||||||
///
|
///
|
||||||
/// It's important to note that this does not **flush** the outbound
|
/// It's important to note that this does not **flush** the outbound
|
||||||
/// settings to the wire.
|
/// settings to the wire.
|
||||||
pub fn handshake(io: T) -> Handshake<T, Bytes> {
|
pub fn handshake<T>(io: T) -> Handshake<T, Bytes>
|
||||||
|
where
|
||||||
|
T: AsyncRead + AsyncWrite,
|
||||||
|
{
|
||||||
Builder::default().handshake(io)
|
Builder::default().handshake(io)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<(), Bytes> {
|
impl Client<Bytes> {
|
||||||
/// Creates a Client Builder to customize a Client before binding.
|
/// Creates a Client Builder to customize a Client before binding.
|
||||||
pub fn builder() -> Builder {
|
pub fn builder() -> Builder {
|
||||||
Builder::default()
|
Builder::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B> Client<T, B>
|
impl<B> Client<B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
fn handshake2(io: T, builder: Builder) -> Handshake<T, B> {
|
fn handshake2<T>(io: T, builder: Builder) -> Handshake<T, B>
|
||||||
|
where
|
||||||
|
T: AsyncRead + AsyncWrite,
|
||||||
|
{
|
||||||
use tokio_io::io;
|
use tokio_io::io;
|
||||||
|
|
||||||
debug!("binding client connection");
|
debug!("binding client connection");
|
||||||
@@ -91,7 +100,9 @@ where
|
|||||||
/// Returns `Ready` when the connection can initialize a new HTTP 2.0
|
/// Returns `Ready` when the connection can initialize a new HTTP 2.0
|
||||||
/// stream.
|
/// stream.
|
||||||
pub fn poll_ready(&mut self) -> Poll<(), ::Error> {
|
pub fn poll_ready(&mut self) -> Poll<(), ::Error> {
|
||||||
self.connection.poll_send_request_ready()
|
try_ready!(self.inner.poll_pending_open(self.pending.as_ref()));
|
||||||
|
self.pending = None;
|
||||||
|
Ok(().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a request on a new HTTP 2.0 stream
|
/// Send a request on a new HTTP 2.0 stream
|
||||||
@@ -100,10 +111,13 @@ where
|
|||||||
request: Request<()>,
|
request: Request<()>,
|
||||||
end_of_stream: bool,
|
end_of_stream: bool,
|
||||||
) -> Result<Stream<B>, ::Error> {
|
) -> Result<Stream<B>, ::Error> {
|
||||||
self.connection
|
self.inner
|
||||||
.send_request(request, end_of_stream)
|
.send_request(request, end_of_stream, self.pending.as_ref())
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.map(|stream| {
|
.map(|stream| {
|
||||||
|
if stream.is_pending_open() {
|
||||||
|
self.pending = Some(stream.key());
|
||||||
|
}
|
||||||
Stream {
|
Stream {
|
||||||
inner: stream,
|
inner: stream,
|
||||||
}
|
}
|
||||||
@@ -111,37 +125,30 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B> Future for Client<T, B>
|
impl<B> fmt::Debug for Client<B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
type Item = ();
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
type Error = ::Error;
|
fmt.debug_struct("Client").finish()
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<(), ::Error> {
|
|
||||||
self.connection.poll().map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B> fmt::Debug for Client<T, B>
|
impl<B> Clone for Client<B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
B: IntoBuf,
|
||||||
T: fmt::Debug,
|
|
||||||
B: fmt::Debug + IntoBuf,
|
|
||||||
B::Buf: fmt::Debug,
|
|
||||||
{
|
{
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn clone(&self) -> Self {
|
||||||
fmt.debug_struct("Client")
|
Client {
|
||||||
.field("connection", &self.connection)
|
inner: self.inner.clone(),
|
||||||
.finish()
|
pending: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
impl<T, B> Client<T, B>
|
impl<B> Client<B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
/// Returns the number of active streams.
|
/// Returns the number of active streams.
|
||||||
@@ -149,7 +156,7 @@ where
|
|||||||
/// An active stream is a stream that has not yet transitioned to a closed
|
/// An active stream is a stream that has not yet transitioned to a closed
|
||||||
/// state.
|
/// state.
|
||||||
pub fn num_active_streams(&self) -> usize {
|
pub fn num_active_streams(&self) -> usize {
|
||||||
self.connection.num_active_streams()
|
self.inner.num_active_streams()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of streams that are held in memory.
|
/// Returns the number of streams that are held in memory.
|
||||||
@@ -158,7 +165,7 @@ where
|
|||||||
/// stay in memory for some reason. For example, there are still outstanding
|
/// stay in memory for some reason. For example, there are still outstanding
|
||||||
/// userspace handles pointing to the slot.
|
/// userspace handles pointing to the slot.
|
||||||
pub fn num_wired_streams(&self) -> usize {
|
pub fn num_wired_streams(&self) -> usize {
|
||||||
self.connection.num_wired_streams()
|
self.inner.num_wired_streams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,13 +226,40 @@ impl Default for Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== impl Connection =====
|
||||||
|
|
||||||
|
impl<T, B> Future for Connection<T, B>
|
||||||
|
where
|
||||||
|
T: AsyncRead + AsyncWrite,
|
||||||
|
B: IntoBuf,
|
||||||
|
{
|
||||||
|
type Item = ();
|
||||||
|
type Error = ::Error;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<(), ::Error> {
|
||||||
|
self.inner.poll().map_err(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, B> fmt::Debug for Connection<T, B>
|
||||||
|
where
|
||||||
|
T: AsyncRead + AsyncWrite,
|
||||||
|
T: fmt::Debug,
|
||||||
|
B: fmt::Debug + IntoBuf,
|
||||||
|
B::Buf: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&self.inner, fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===== impl Handshake =====
|
// ===== impl Handshake =====
|
||||||
|
|
||||||
impl<T, B: IntoBuf> Future for Handshake<T, B>
|
impl<T, B: IntoBuf> Future for Handshake<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
{
|
{
|
||||||
type Item = Client<T, B>;
|
type Item = (Client<B>, Connection<T, B>);
|
||||||
type Error = ::Error;
|
type Error = ::Error;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
@@ -245,10 +279,16 @@ where
|
|||||||
.buffer(self.builder.settings.clone().into())
|
.buffer(self.builder.settings.clone().into())
|
||||||
.expect("invalid SETTINGS frame");
|
.expect("invalid SETTINGS frame");
|
||||||
|
|
||||||
let connection = Connection::new(codec, &self.builder.settings, self.builder.stream_id);
|
let connection =
|
||||||
Ok(Async::Ready(Client {
|
proto::Connection::new(codec, &self.builder.settings, self.builder.stream_id);
|
||||||
connection,
|
let client = Client {
|
||||||
}))
|
inner: connection.streams().clone(),
|
||||||
|
pending: None,
|
||||||
|
};
|
||||||
|
let conn = Connection {
|
||||||
|
inner: connection,
|
||||||
|
};
|
||||||
|
Ok(Async::Ready((client, conn)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use {client, frame, proto, server};
|
use {client, frame, proto, server};
|
||||||
use codec::{RecvError, SendError};
|
use codec::RecvError;
|
||||||
use frame::Reason;
|
use frame::Reason;
|
||||||
|
|
||||||
use frame::DEFAULT_INITIAL_WINDOW_SIZE;
|
use frame::DEFAULT_INITIAL_WINDOW_SIZE;
|
||||||
@@ -7,7 +7,6 @@ use proto::*;
|
|||||||
|
|
||||||
use bytes::{Bytes, IntoBuf};
|
use bytes::{Bytes, IntoBuf};
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use http::Request;
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -249,18 +248,8 @@ where
|
|||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
/// Returns `Ready` when new the connection is able to support a new request stream.
|
pub(crate) fn streams(&self) -> &Streams<B::Buf, client::Peer> {
|
||||||
pub fn poll_send_request_ready(&mut self) -> Poll<(), ::Error> {
|
&self.streams
|
||||||
self.streams.poll_send_request_ready()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a new HTTP/2.0 stream and send the message.
|
|
||||||
pub fn send_request(
|
|
||||||
&mut self,
|
|
||||||
request: Request<()>,
|
|
||||||
end_of_stream: bool,
|
|
||||||
) -> Result<StreamRef<B::Buf, client::Peer>, SendError> {
|
|
||||||
self.streams.send_request(request, end_of_stream)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,19 +262,3 @@ where
|
|||||||
self.streams.next_incoming()
|
self.streams.next_incoming()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
|
||||||
impl<T, P, B> Connection<T, P, B>
|
|
||||||
where
|
|
||||||
T: AsyncRead + AsyncWrite,
|
|
||||||
P: Peer,
|
|
||||||
B: IntoBuf,
|
|
||||||
{
|
|
||||||
pub fn num_active_streams(&self) -> usize {
|
|
||||||
self.streams.num_active_streams()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_wired_streams(&self) -> usize {
|
|
||||||
self.streams.num_wired_streams()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ mod streams;
|
|||||||
pub(crate) use self::connection::Connection;
|
pub(crate) use self::connection::Connection;
|
||||||
pub(crate) use self::error::Error;
|
pub(crate) use self::error::Error;
|
||||||
pub(crate) use self::peer::Peer;
|
pub(crate) use self::peer::Peer;
|
||||||
pub(crate) use self::streams::{StreamRef, Streams};
|
pub(crate) use self::streams::{Key as StreamKey, StreamRef, Streams};
|
||||||
|
|
||||||
use codec::Codec;
|
use codec::Codec;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use client;
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
@@ -10,20 +9,17 @@ where
|
|||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
/// Maximum number of locally initiated streams
|
/// Maximum number of locally initiated streams
|
||||||
max_send_streams: Option<usize>,
|
max_send_streams: usize,
|
||||||
|
|
||||||
/// Current number of remote initiated streams
|
/// Current number of remote initiated streams
|
||||||
num_send_streams: usize,
|
num_send_streams: usize,
|
||||||
|
|
||||||
/// Maximum number of remote initiated streams
|
/// Maximum number of remote initiated streams
|
||||||
max_recv_streams: Option<usize>,
|
max_recv_streams: usize,
|
||||||
|
|
||||||
/// Current number of locally initiated streams
|
/// Current number of locally initiated streams
|
||||||
num_recv_streams: usize,
|
num_recv_streams: usize,
|
||||||
|
|
||||||
/// Task awaiting notification to open a new stream.
|
|
||||||
blocked_open: Option<task::Task>,
|
|
||||||
|
|
||||||
_p: PhantomData<P>,
|
_p: PhantomData<P>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,22 +30,17 @@ where
|
|||||||
/// Create a new `Counts` using the provided configuration values.
|
/// Create a new `Counts` using the provided configuration values.
|
||||||
pub fn new(config: &Config) -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
Counts {
|
Counts {
|
||||||
max_send_streams: config.local_max_initiated,
|
max_send_streams: config.local_max_initiated.unwrap_or(usize::MAX),
|
||||||
num_send_streams: 0,
|
num_send_streams: 0,
|
||||||
max_recv_streams: config.remote_max_initiated,
|
max_recv_streams: config.remote_max_initiated.unwrap_or(usize::MAX),
|
||||||
num_recv_streams: 0,
|
num_recv_streams: 0,
|
||||||
blocked_open: None,
|
|
||||||
_p: PhantomData,
|
_p: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the receive stream concurrency can be incremented
|
/// Returns true if the receive stream concurrency can be incremented
|
||||||
pub fn can_inc_num_recv_streams(&self) -> bool {
|
pub fn can_inc_num_recv_streams(&self) -> bool {
|
||||||
if let Some(max) = self.max_recv_streams {
|
self.max_recv_streams > self.num_recv_streams
|
||||||
max > self.num_recv_streams
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increments the number of concurrent receive streams.
|
/// Increments the number of concurrent receive streams.
|
||||||
@@ -66,11 +57,7 @@ where
|
|||||||
|
|
||||||
/// Returns true if the send stream concurrency can be incremented
|
/// Returns true if the send stream concurrency can be incremented
|
||||||
pub fn can_inc_num_send_streams(&self) -> bool {
|
pub fn can_inc_num_send_streams(&self) -> bool {
|
||||||
if let Some(max) = self.max_send_streams {
|
self.max_send_streams > self.num_send_streams
|
||||||
max > self.num_send_streams
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increments the number of concurrent send streams.
|
/// Increments the number of concurrent send streams.
|
||||||
@@ -87,7 +74,7 @@ where
|
|||||||
|
|
||||||
pub fn apply_remote_settings(&mut self, settings: &frame::Settings) {
|
pub fn apply_remote_settings(&mut self, settings: &frame::Settings) {
|
||||||
if let Some(val) = settings.max_concurrent_streams() {
|
if let Some(val) = settings.max_concurrent_streams() {
|
||||||
self.max_send_streams = Some(val as usize);
|
self.max_send_streams = val as usize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +86,7 @@ where
|
|||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &mut store::Ptr<B, P>) -> U,
|
F: FnOnce(&mut Self, &mut store::Ptr<B, P>) -> U,
|
||||||
{
|
{
|
||||||
let is_counted = stream.state.is_counted();
|
let is_counted = stream.is_counted();
|
||||||
|
|
||||||
// Run the action
|
// Run the action
|
||||||
let ret = f(self, &mut stream);
|
let ret = f(self, &mut stream);
|
||||||
@@ -127,29 +114,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dec_num_streams(&mut self, id: StreamId) {
|
fn dec_num_streams(&mut self, id: StreamId) {
|
||||||
use std::usize;
|
|
||||||
|
|
||||||
if P::is_local_init(id) {
|
if P::is_local_init(id) {
|
||||||
self.num_send_streams -= 1;
|
self.num_send_streams -= 1;
|
||||||
|
|
||||||
if self.num_send_streams < self.max_send_streams.unwrap_or(usize::MAX) {
|
|
||||||
if let Some(task) = self.blocked_open.take() {
|
|
||||||
task.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.num_recv_streams -= 1;
|
self.num_recv_streams -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Counts<client::Peer> {
|
|
||||||
pub fn poll_open_ready(&mut self) -> Async<()> {
|
|
||||||
if !self.can_inc_num_send_streams() {
|
|
||||||
self.blocked_open = Some(task::current());
|
|
||||||
return Async::NotReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Async::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ mod stream;
|
|||||||
mod streams;
|
mod streams;
|
||||||
|
|
||||||
pub(crate) use self::prioritize::Prioritized;
|
pub(crate) use self::prioritize::Prioritized;
|
||||||
|
pub(crate) use self::store::Key;
|
||||||
pub(crate) use self::streams::{StreamRef, Streams};
|
pub(crate) use self::streams::{StreamRef, Streams};
|
||||||
|
|
||||||
use self::buffer::Buffer;
|
use self::buffer::Buffer;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ where
|
|||||||
/// Queue of streams waiting for window capacity to produce data.
|
/// Queue of streams waiting for window capacity to produce data.
|
||||||
pending_capacity: store::Queue<B, stream::NextSendCapacity, P>,
|
pending_capacity: store::Queue<B, stream::NextSendCapacity, P>,
|
||||||
|
|
||||||
|
/// Streams waiting for capacity due to max concurrency
|
||||||
|
pending_open: store::Queue<B, stream::NextOpen, P>,
|
||||||
|
|
||||||
/// Connection level flow control governing sent data
|
/// Connection level flow control governing sent data
|
||||||
flow: FlowControl,
|
flow: FlowControl,
|
||||||
|
|
||||||
@@ -60,6 +63,7 @@ where
|
|||||||
Prioritize {
|
Prioritize {
|
||||||
pending_send: store::Queue::new(),
|
pending_send: store::Queue::new(),
|
||||||
pending_capacity: store::Queue::new(),
|
pending_capacity: store::Queue::new(),
|
||||||
|
pending_open: store::Queue::new(),
|
||||||
flow: flow,
|
flow: flow,
|
||||||
buffer: Buffer::new(),
|
buffer: Buffer::new(),
|
||||||
}
|
}
|
||||||
@@ -75,15 +79,22 @@ where
|
|||||||
// Queue the frame in the buffer
|
// Queue the frame in the buffer
|
||||||
stream.pending_send.push_back(&mut self.buffer, frame);
|
stream.pending_send.push_back(&mut self.buffer, frame);
|
||||||
|
|
||||||
// Queue the stream
|
// If the stream is waiting to be opened, nothing more to do.
|
||||||
self.pending_send.push(stream);
|
if !stream.is_pending_open {
|
||||||
|
// Queue the stream
|
||||||
|
self.pending_send.push(stream);
|
||||||
|
|
||||||
// Notify the connection.
|
// Notify the connection.
|
||||||
if let Some(task) = task.take() {
|
if let Some(task) = task.take() {
|
||||||
task.notify();
|
task.notify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn queue_open(&mut self, stream: &mut store::Ptr<B, P>) {
|
||||||
|
self.pending_open.push(stream);
|
||||||
|
}
|
||||||
|
|
||||||
/// Send a data frame
|
/// Send a data frame
|
||||||
pub fn send_data(
|
pub fn send_data(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -371,6 +382,7 @@ where
|
|||||||
trace!("poll_complete");
|
trace!("poll_complete");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
self.schedule_pending_open(store, counts);
|
||||||
match self.pop_frame(store, max_frame_len, counts) {
|
match self.pop_frame(store, max_frame_len, counts) {
|
||||||
Some(frame) => {
|
Some(frame) => {
|
||||||
trace!("writing frame={:?}", frame);
|
trace!("writing frame={:?}", frame);
|
||||||
@@ -482,7 +494,7 @@ where
|
|||||||
trace!("pop_frame; stream={:?}", stream.id);
|
trace!("pop_frame; stream={:?}", stream.id);
|
||||||
debug_assert!(!stream.pending_send.is_empty());
|
debug_assert!(!stream.pending_send.is_empty());
|
||||||
|
|
||||||
let is_counted = stream.state.is_counted();
|
let is_counted = stream.is_counted();
|
||||||
|
|
||||||
let frame = match stream.pending_send.pop_front(&mut self.buffer).unwrap() {
|
let frame = match stream.pending_send.pop_front(&mut self.buffer).unwrap() {
|
||||||
Frame::Data(mut frame) => {
|
Frame::Data(mut frame) => {
|
||||||
@@ -594,6 +606,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schedule_pending_open(&mut self, store: &mut Store<B, P>, counts: &mut Counts<P>) {
|
||||||
|
trace!("schedule_pending_open");
|
||||||
|
// check for any pending open streams
|
||||||
|
while counts.can_inc_num_send_streams() {
|
||||||
|
if let Some(mut stream) = self.pending_open.pop(store) {
|
||||||
|
trace!("schedule_pending_open; stream={:?}", stream.id);
|
||||||
|
counts.inc_num_send_streams();
|
||||||
|
self.pending_send.push(&mut stream);
|
||||||
|
if let Some(task) = stream.open_task.take() {
|
||||||
|
task.notify();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl Prioritized =====
|
// ===== impl Prioritized =====
|
||||||
|
|||||||
@@ -43,20 +43,9 @@ where
|
|||||||
self.init_window_sz
|
self.init_window_sz
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update state reflecting a new, locally opened stream
|
pub fn open(&mut self) -> Result<StreamId, UserError> {
|
||||||
///
|
|
||||||
/// Returns the stream state if successful. `None` if refused
|
|
||||||
pub fn open(&mut self, counts: &mut Counts<P>) -> Result<StreamId, UserError> {
|
|
||||||
if !counts.can_inc_num_send_streams() {
|
|
||||||
return Err(Rejected.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let stream_id = self.try_open()?;
|
let stream_id = self.try_open()?;
|
||||||
|
|
||||||
// Increment the number of locally initiated streams
|
|
||||||
counts.inc_num_send_streams();
|
|
||||||
self.next_stream_id = stream_id.next_id();
|
self.next_stream_id = stream_id.next_id();
|
||||||
|
|
||||||
Ok(stream_id)
|
Ok(stream_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +53,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
frame: frame::Headers,
|
frame: frame::Headers,
|
||||||
stream: &mut store::Ptr<B, P>,
|
stream: &mut store::Ptr<B, P>,
|
||||||
|
counts: &mut Counts<P>,
|
||||||
task: &mut Option<Task>,
|
task: &mut Option<Task>,
|
||||||
) -> Result<(), UserError> {
|
) -> Result<(), UserError> {
|
||||||
trace!(
|
trace!(
|
||||||
@@ -77,6 +67,14 @@ where
|
|||||||
// Update the state
|
// Update the state
|
||||||
stream.state.send_open(end_stream)?;
|
stream.state.send_open(end_stream)?;
|
||||||
|
|
||||||
|
if P::is_local_init(frame.stream_id()) {
|
||||||
|
if counts.can_inc_num_send_streams() {
|
||||||
|
counts.inc_num_send_streams();
|
||||||
|
} else {
|
||||||
|
self.prioritize.queue_open(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Queue the frame for sending
|
// Queue the frame for sending
|
||||||
self.prioritize.queue_frame(frame.into(), stream, task);
|
self.prioritize.queue_frame(frame.into(), stream, task);
|
||||||
|
|
||||||
|
|||||||
@@ -251,9 +251,8 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if a stream with the current state counts against the
|
/// Returns true if a stream is open or half-closed.
|
||||||
/// concurrency limit.
|
pub fn is_at_least_half_open(&self) -> bool {
|
||||||
pub fn is_counted(&self) -> bool {
|
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open {
|
Open {
|
||||||
..
|
..
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ pub(super) struct Store<B, P>
|
|||||||
where
|
where
|
||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
slab: slab::Slab<Stream<B, P>>,
|
slab: slab::Slab<(StoreId, Stream<B, P>)>,
|
||||||
ids: OrderMap<StreamId, usize>,
|
ids: OrderMap<StreamId, (usize, StoreId)>,
|
||||||
|
counter: StoreId,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "Pointer" to an entry in the store
|
/// "Pointer" to an entry in the store
|
||||||
@@ -28,7 +29,12 @@ where
|
|||||||
|
|
||||||
/// References an entry in the store.
|
/// References an entry in the store.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(super) struct Key(usize);
|
pub(crate) struct Key {
|
||||||
|
index: usize,
|
||||||
|
store_id: StoreId,
|
||||||
|
}
|
||||||
|
|
||||||
|
type StoreId = usize;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Queue<B, N, P>
|
pub(super) struct Queue<B, N, P>
|
||||||
@@ -64,15 +70,16 @@ pub(super) enum Entry<'a, B: 'a, P: Peer + 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct OccupiedEntry<'a> {
|
pub(super) struct OccupiedEntry<'a> {
|
||||||
ids: ordermap::OccupiedEntry<'a, StreamId, usize>,
|
ids: ordermap::OccupiedEntry<'a, StreamId, (usize, StoreId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct VacantEntry<'a, B: 'a, P>
|
pub(super) struct VacantEntry<'a, B: 'a, P>
|
||||||
where
|
where
|
||||||
P: Peer + 'a,
|
P: Peer + 'a,
|
||||||
{
|
{
|
||||||
ids: ordermap::VacantEntry<'a, StreamId, usize>,
|
ids: ordermap::VacantEntry<'a, StreamId, (usize, StoreId)>,
|
||||||
slab: &'a mut slab::Slab<Stream<B, P>>,
|
slab: &'a mut slab::Slab<(StoreId, Stream<B, P>)>,
|
||||||
|
counter: &'a mut usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) trait Resolve<B, P>
|
pub(super) trait Resolve<B, P>
|
||||||
@@ -92,6 +99,7 @@ where
|
|||||||
Store {
|
Store {
|
||||||
slab: slab::Slab::new(),
|
slab: slab::Slab::new(),
|
||||||
ids: OrderMap::new(),
|
ids: OrderMap::new(),
|
||||||
|
counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +114,25 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
Some(Ptr {
|
Some(Ptr {
|
||||||
key: Key(key),
|
key: Key {
|
||||||
|
index: key.0,
|
||||||
|
store_id: key.1,
|
||||||
|
},
|
||||||
store: self,
|
store: self,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, id: StreamId, val: Stream<B, P>) -> Ptr<B, P> {
|
pub fn insert(&mut self, id: StreamId, val: Stream<B, P>) -> Ptr<B, P> {
|
||||||
let key = self.slab.insert(val);
|
let store_id = self.counter;
|
||||||
assert!(self.ids.insert(id, key).is_none());
|
self.counter = self.counter.wrapping_add(1);
|
||||||
|
let key = self.slab.insert((store_id, val));
|
||||||
|
assert!(self.ids.insert(id, (key, store_id)).is_none());
|
||||||
|
|
||||||
Ptr {
|
Ptr {
|
||||||
key: Key(key),
|
key: Key {
|
||||||
|
index: key,
|
||||||
|
store_id,
|
||||||
|
},
|
||||||
store: self,
|
store: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +147,7 @@ where
|
|||||||
Vacant(e) => Entry::Vacant(VacantEntry {
|
Vacant(e) => Entry::Vacant(VacantEntry {
|
||||||
ids: e,
|
ids: e,
|
||||||
slab: &mut self.slab,
|
slab: &mut self.slab,
|
||||||
|
counter: &mut self.counter,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +164,10 @@ where
|
|||||||
let key = *self.ids.get_index(i).unwrap().1;
|
let key = *self.ids.get_index(i).unwrap().1;
|
||||||
|
|
||||||
f(Ptr {
|
f(Ptr {
|
||||||
key: Key(key),
|
key: Key {
|
||||||
|
index: key.0,
|
||||||
|
store_id: key.1,
|
||||||
|
},
|
||||||
store: self,
|
store: self,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -185,7 +205,9 @@ where
|
|||||||
type Output = Stream<B, P>;
|
type Output = Stream<B, P>;
|
||||||
|
|
||||||
fn index(&self, key: Key) -> &Self::Output {
|
fn index(&self, key: Key) -> &Self::Output {
|
||||||
self.slab.index(key.0)
|
let slot = self.slab.index(key.index);
|
||||||
|
assert_eq!(slot.0, key.store_id);
|
||||||
|
&slot.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +216,9 @@ where
|
|||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
|
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
|
||||||
self.slab.index_mut(key.0)
|
let slot = self.slab.index_mut(key.index);
|
||||||
|
assert_eq!(slot.0, key.store_id);
|
||||||
|
&mut slot.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +343,7 @@ where
|
|||||||
debug_assert!(!self.store.ids.contains_key(&self.id));
|
debug_assert!(!self.store.ids.contains_key(&self.id));
|
||||||
|
|
||||||
// Remove the stream state
|
// Remove the stream state
|
||||||
self.store.slab.remove(self.key.0).id
|
self.store.slab.remove(self.key.index).1.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the StreamId -> stream state association.
|
/// Remove the StreamId -> stream state association.
|
||||||
@@ -351,7 +375,7 @@ where
|
|||||||
type Target = Stream<B, P>;
|
type Target = Stream<B, P>;
|
||||||
|
|
||||||
fn deref(&self) -> &Stream<B, P> {
|
fn deref(&self) -> &Stream<B, P> {
|
||||||
&self.store.slab[self.key.0]
|
&self.store.slab[self.key.index].1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +384,7 @@ where
|
|||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
fn deref_mut(&mut self) -> &mut Stream<B, P> {
|
fn deref_mut(&mut self) -> &mut Stream<B, P> {
|
||||||
&mut self.store.slab[self.key.0]
|
&mut self.store.slab[self.key.index].1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +392,11 @@ where
|
|||||||
|
|
||||||
impl<'a> OccupiedEntry<'a> {
|
impl<'a> OccupiedEntry<'a> {
|
||||||
pub fn key(&self) -> Key {
|
pub fn key(&self) -> Key {
|
||||||
Key(*self.ids.get())
|
let tup = self.ids.get();
|
||||||
|
Key {
|
||||||
|
index: tup.0,
|
||||||
|
store_id: tup.1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,11 +408,16 @@ where
|
|||||||
{
|
{
|
||||||
pub fn insert(self, value: Stream<B, P>) -> Key {
|
pub fn insert(self, value: Stream<B, P>) -> Key {
|
||||||
// Insert the value in the slab
|
// Insert the value in the slab
|
||||||
let key = self.slab.insert(value);
|
let store_id = *self.counter;
|
||||||
|
*self.counter = store_id.wrapping_add(1);
|
||||||
|
let index = self.slab.insert((store_id, value));
|
||||||
|
|
||||||
// Insert the handle in the ID map
|
// Insert the handle in the ID map
|
||||||
self.ids.insert(key);
|
self.ids.insert((index, store_id));
|
||||||
|
|
||||||
Key(key)
|
Key {
|
||||||
|
index,
|
||||||
|
store_id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,15 @@ where
|
|||||||
/// Set to true when the send capacity has been incremented
|
/// Set to true when the send capacity has been incremented
|
||||||
pub send_capacity_inc: bool,
|
pub send_capacity_inc: bool,
|
||||||
|
|
||||||
|
/// Next node in the open linked list
|
||||||
|
pub next_open: Option<store::Key>,
|
||||||
|
|
||||||
|
/// Set to true when the stream is pending to be opened
|
||||||
|
pub is_pending_open: bool,
|
||||||
|
|
||||||
|
/// Task tracking when stream can be "opened", or initially sent to socket.
|
||||||
|
pub open_task: Option<task::Task>,
|
||||||
|
|
||||||
// ===== Fields related to receiving =====
|
// ===== Fields related to receiving =====
|
||||||
/// Next node in the accept linked list
|
/// Next node in the accept linked list
|
||||||
pub next_pending_accept: Option<store::Key>,
|
pub next_pending_accept: Option<store::Key>,
|
||||||
@@ -111,6 +120,9 @@ pub(super) struct NextSendCapacity;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct NextWindowUpdate;
|
pub(super) struct NextWindowUpdate;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct NextOpen;
|
||||||
|
|
||||||
impl<B, P> Stream<B, P>
|
impl<B, P> Stream<B, P>
|
||||||
where
|
where
|
||||||
P: Peer,
|
P: Peer,
|
||||||
@@ -150,6 +162,9 @@ where
|
|||||||
is_pending_send_capacity: false,
|
is_pending_send_capacity: false,
|
||||||
next_pending_send_capacity: None,
|
next_pending_send_capacity: None,
|
||||||
send_capacity_inc: false,
|
send_capacity_inc: false,
|
||||||
|
is_pending_open: false,
|
||||||
|
next_open: None,
|
||||||
|
open_task: None,
|
||||||
|
|
||||||
// ===== Fields related to receiving =====
|
// ===== Fields related to receiving =====
|
||||||
next_pending_accept: None,
|
next_pending_accept: None,
|
||||||
@@ -177,6 +192,12 @@ where
|
|||||||
self.ref_count -= 1;
|
self.ref_count -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if a stream with the current state counts against the
|
||||||
|
/// concurrency limit.
|
||||||
|
pub fn is_counted(&self) -> bool {
|
||||||
|
!self.is_pending_open && self.state.is_at_least_half_open()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the stream is closed
|
/// Returns true if the stream is closed
|
||||||
pub fn is_closed(&self) -> bool {
|
pub fn is_closed(&self) -> bool {
|
||||||
// The state has fully transitioned to closed.
|
// The state has fully transitioned to closed.
|
||||||
@@ -337,6 +358,28 @@ impl store::Next for NextWindowUpdate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl store::Next for NextOpen {
|
||||||
|
fn next<B, P: Peer>(stream: &Stream<B, P>) -> Option<store::Key> {
|
||||||
|
stream.next_open
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_next<B, P: Peer>(stream: &mut Stream<B, P>, key: Option<store::Key>) {
|
||||||
|
stream.next_open = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_next<B, P: Peer>(stream: &mut Stream<B, P>) -> Option<store::Key> {
|
||||||
|
stream.next_open.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_queued<B, P: Peer>(stream: &Stream<B, P>) -> bool {
|
||||||
|
stream.is_pending_open
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_queued<B, P: Peer>(stream: &mut Stream<B, P>, val: bool) {
|
||||||
|
stream.is_pending_open = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===== impl ContentLength =====
|
// ===== impl ContentLength =====
|
||||||
|
|
||||||
impl ContentLength {
|
impl ContentLength {
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
request: Request<()>,
|
request: Request<()>,
|
||||||
end_of_stream: bool,
|
end_of_stream: bool,
|
||||||
|
pending: Option<&store::Key>,
|
||||||
) -> Result<StreamRef<B, P>, SendError> {
|
) -> Result<StreamRef<B, P>, SendError> {
|
||||||
use super::stream::ContentLength;
|
use super::stream::ContentLength;
|
||||||
use http::Method;
|
use http::Method;
|
||||||
@@ -336,8 +337,21 @@ where
|
|||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
// Initialize a new stream. This fails if the connection is at capacity.
|
me.actions.send.ensure_next_stream_id()?;
|
||||||
let stream_id = me.actions.send.open(&mut me.counts)?;
|
|
||||||
|
// The `pending` argument is provided by the `Client`, and holds
|
||||||
|
// a store `Key` of a `Stream` that may have been not been opened
|
||||||
|
// yet.
|
||||||
|
//
|
||||||
|
// If that stream is still pending, the Client isn't allowed to
|
||||||
|
// queue up another pending stream. They should use `poll_ready`.
|
||||||
|
if let Some(key) = pending {
|
||||||
|
if me.store.resolve(*key).is_pending_open {
|
||||||
|
return Err(UserError::Rejected.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream_id = me.actions.send.open()?;
|
||||||
|
|
||||||
let mut stream = Stream::new(
|
let mut stream = Stream::new(
|
||||||
stream_id,
|
stream_id,
|
||||||
@@ -354,9 +368,12 @@ where
|
|||||||
|
|
||||||
let mut stream = me.store.insert(stream.id, stream);
|
let mut stream = me.store.insert(stream.id, stream);
|
||||||
|
|
||||||
me.actions
|
me.actions.send.send_headers(
|
||||||
.send
|
headers,
|
||||||
.send_headers(headers, &mut stream, &mut me.actions.task)?;
|
&mut stream,
|
||||||
|
&mut me.counts,
|
||||||
|
&mut me.actions.task,
|
||||||
|
)?;
|
||||||
|
|
||||||
// Given that the stream has been initialized, it should not be in the
|
// Given that the stream has been initialized, it should not be in the
|
||||||
// closed state.
|
// closed state.
|
||||||
@@ -403,13 +420,21 @@ impl<B> Streams<B, client::Peer>
|
|||||||
where
|
where
|
||||||
B: Buf,
|
B: Buf,
|
||||||
{
|
{
|
||||||
pub fn poll_send_request_ready(&mut self) -> Poll<(), ::Error> {
|
pub fn poll_pending_open(&mut self, key: Option<&store::Key>) -> Poll<(), ::Error> {
|
||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
me.actions.send.ensure_next_stream_id()?;
|
me.actions.send.ensure_next_stream_id()?;
|
||||||
|
|
||||||
Ok(me.counts.poll_open_ready())
|
if let Some(key) = key {
|
||||||
|
let mut stream = me.store.resolve(*key);
|
||||||
|
trace!("poll_pending_open; stream = {:?}", stream.is_pending_open);
|
||||||
|
if stream.is_pending_open {
|
||||||
|
stream.send_task = Some(task::current());
|
||||||
|
return Ok(Async::NotReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,6 +455,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no derive because we don't need B and P to be Clone.
|
||||||
|
impl<B, P> Clone for Streams<B, P>
|
||||||
|
where
|
||||||
|
B: Buf,
|
||||||
|
P: Peer,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Streams {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===== impl StreamRef =====
|
// ===== impl StreamRef =====
|
||||||
|
|
||||||
impl<B, P> StreamRef<B, P>
|
impl<B, P> StreamRef<B, P>
|
||||||
@@ -493,10 +531,12 @@ where
|
|||||||
let stream = me.store.resolve(self.key);
|
let stream = me.store.resolve(self.key);
|
||||||
let actions = &mut me.actions;
|
let actions = &mut me.actions;
|
||||||
|
|
||||||
me.counts.transition(stream, |_, stream| {
|
me.counts.transition(stream, |counts, stream| {
|
||||||
let frame = server::Peer::convert_send_message(stream.id, response, end_of_stream);
|
let frame = server::Peer::convert_send_message(stream.id, response, end_of_stream);
|
||||||
|
|
||||||
actions.send.send_headers(frame, stream, &mut actions.task)
|
actions
|
||||||
|
.send
|
||||||
|
.send_headers(frame, stream, counts, &mut actions.task)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +609,10 @@ where
|
|||||||
|
|
||||||
me.actions.send.poll_capacity(&mut stream)
|
me.actions.send.poll_capacity(&mut stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn key(&self) -> store::Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> StreamRef<B, server::Peer>
|
impl<B> StreamRef<B, server::Peer>
|
||||||
@@ -603,6 +647,12 @@ where
|
|||||||
|
|
||||||
me.actions.recv.poll_response(&mut stream)
|
me.actions.recv.poll_response(&mut stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn is_pending_open(&self) -> bool {
|
||||||
|
let mut me = self.inner.lock().unwrap();
|
||||||
|
me.store.resolve(self.key).is_pending_open
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, P> Clone for StreamRef<B, P>
|
impl<B, P> Clone for StreamRef<B, P>
|
||||||
@@ -625,7 +675,15 @@ where
|
|||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = match self.inner.lock() {
|
||||||
|
Ok(inner) => inner,
|
||||||
|
Err(_) => if ::std::thread::panicking() {
|
||||||
|
trace!("StreamRef::drop; mutex poisoned");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
panic!("StreamRef::drop; mutex poisoned");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ fn handshake() {
|
|||||||
.write(SETTINGS_ACK)
|
.write(SETTINGS_ACK)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let h2 = Client::handshake(mock).wait().unwrap();
|
let (_, h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
trace!("hands have been shook");
|
trace!("hands have been shook");
|
||||||
|
|
||||||
@@ -21,6 +21,43 @@ fn handshake() {
|
|||||||
h2.wait().unwrap();
|
h2.wait().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn client_other_thread() {
|
||||||
|
let _ = ::env_logger::init();
|
||||||
|
let (io, srv) = mock::new();
|
||||||
|
|
||||||
|
let srv = srv.assert_client_handshake()
|
||||||
|
.unwrap()
|
||||||
|
.recv_settings()
|
||||||
|
.recv_frame(
|
||||||
|
frames::headers(1)
|
||||||
|
.request("GET", "https://http2.akamai.com/")
|
||||||
|
.eos(),
|
||||||
|
)
|
||||||
|
.send_frame(frames::headers(1).response(200).eos())
|
||||||
|
.close();
|
||||||
|
|
||||||
|
let h2 = Client::handshake(io)
|
||||||
|
.expect("handshake")
|
||||||
|
.and_then(|(mut client, h2)| {
|
||||||
|
::std::thread::spawn(move || {
|
||||||
|
let request = Request::builder()
|
||||||
|
.uri("https://http2.akamai.com/")
|
||||||
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
let res = client
|
||||||
|
.send_request(request, true)
|
||||||
|
.unwrap()
|
||||||
|
.wait()
|
||||||
|
.expect("request");
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
});
|
||||||
|
|
||||||
|
h2.expect("h2")
|
||||||
|
});
|
||||||
|
h2.join(srv).wait().expect("wait");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recv_invalid_server_stream_id() {
|
fn recv_invalid_server_stream_id() {
|
||||||
let _ = ::env_logger::init();
|
let _ = ::env_logger::init();
|
||||||
@@ -39,7 +76,7 @@ fn recv_invalid_server_stream_id() {
|
|||||||
.write(&[0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
|
.write(&[0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
@@ -48,7 +85,7 @@ fn recv_invalid_server_stream_id() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let stream = h2.send_request(request, true).unwrap();
|
let stream = client.send_request(request, true).unwrap();
|
||||||
|
|
||||||
// The connection errors
|
// The connection errors
|
||||||
assert!(h2.wait().is_err());
|
assert!(h2.wait().is_err());
|
||||||
@@ -67,7 +104,7 @@ fn request_stream_id_overflows() {
|
|||||||
.initial_stream_id(::std::u32::MAX >> 1)
|
.initial_stream_id(::std::u32::MAX >> 1)
|
||||||
.handshake::<_, Bytes>(io)
|
.handshake::<_, Bytes>(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://example.com/")
|
.uri("https://example.com/")
|
||||||
@@ -75,24 +112,26 @@ fn request_stream_id_overflows() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// first request is allowed
|
// first request is allowed
|
||||||
let req = h2.send_request(request, true).unwrap().unwrap();
|
let req = client.send_request(request, true).unwrap().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
h2.drive(req).and_then(move |(h2, _)| {
|
||||||
.method(Method::GET)
|
let request = Request::builder()
|
||||||
.uri("https://example.com/")
|
.method(Method::GET)
|
||||||
.body(())
|
.uri("https://example.com/")
|
||||||
.unwrap();
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
// second cannot use the next stream id, it's over
|
// second cannot use the next stream id, it's over
|
||||||
|
|
||||||
let poll_err = h2.poll_ready().unwrap_err();
|
let poll_err = client.poll_ready().unwrap_err();
|
||||||
assert_eq!(poll_err.to_string(), "user error: stream ID overflowed");
|
assert_eq!(poll_err.to_string(), "user error: stream ID overflowed");
|
||||||
|
|
||||||
let err = h2.send_request(request, true).unwrap_err();
|
let err = client.send_request(request, true).unwrap_err();
|
||||||
assert_eq!(err.to_string(), "user error: stream ID overflowed");
|
assert_eq!(err.to_string(), "user error: stream ID overflowed");
|
||||||
|
|
||||||
h2.expect("h2").join(req)
|
h2.expect("h2")
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let srv = srv.assert_client_handshake()
|
let srv = srv.assert_client_handshake()
|
||||||
@@ -120,13 +159,27 @@ fn request_over_max_concurrent_streams_errors() {
|
|||||||
.max_concurrent_streams(1))
|
.max_concurrent_streams(1))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.recv_settings()
|
.recv_settings()
|
||||||
.recv_frame(frames::headers(1).request("POST", "https://example.com/"))
|
.recv_frame(
|
||||||
.send_frame(frames::headers(1).response(200))
|
frames::headers(1)
|
||||||
|
.request("POST", "https://example.com/")
|
||||||
|
.eos(),
|
||||||
|
)
|
||||||
|
.send_frame(frames::headers(1).response(200).eos())
|
||||||
|
.recv_frame(frames::headers(3).request("POST", "https://example.com/"))
|
||||||
|
.send_frame(frames::headers(3).response(200))
|
||||||
|
.recv_frame(frames::data(3, "hello").eos())
|
||||||
|
.send_frame(frames::data(3, "").eos())
|
||||||
|
.recv_frame(frames::headers(5).request("POST", "https://example.com/"))
|
||||||
|
.send_frame(frames::headers(5).response(200))
|
||||||
|
.recv_frame(frames::data(5, "hello").eos())
|
||||||
|
.send_frame(frames::data(5, "").eos())
|
||||||
.close();
|
.close();
|
||||||
|
|
||||||
let h2 = Client::handshake(io)
|
let h2 = Client::handshake(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
|
// we send a simple req here just to drive the connection so we can
|
||||||
|
// receive the server settings.
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://example.com/")
|
.uri("https://example.com/")
|
||||||
@@ -134,28 +187,48 @@ fn request_over_max_concurrent_streams_errors() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// first request is allowed
|
// first request is allowed
|
||||||
let req = h2.send_request(request, false).unwrap().unwrap();
|
let req = client.send_request(request, true).unwrap().unwrap();
|
||||||
|
h2.drive(req).map(move |(h2, _)| (client, h2))
|
||||||
// drive the connection some so we can receive the server settings
|
|
||||||
h2.drive(req)
|
|
||||||
})
|
})
|
||||||
.and_then(|(mut h2, _)| {
|
.and_then(|(mut client, h2)| {
|
||||||
|
let request = Request::builder()
|
||||||
|
.method(Method::POST)
|
||||||
|
.uri("https://example.com/")
|
||||||
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// first request is allowed
|
||||||
|
let mut req = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
|
let request = Request::builder()
|
||||||
|
.method(Method::POST)
|
||||||
|
.uri("https://example.com/")
|
||||||
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// second request is put into pending_open
|
||||||
|
let mut req2 = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://example.com/")
|
.uri("https://example.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// second stream is over max concurrent
|
// third stream is over max concurrent
|
||||||
assert!(h2.poll_ready().expect("poll_ready").is_not_ready());
|
assert!(client.poll_ready().expect("poll_ready").is_not_ready());
|
||||||
|
|
||||||
let err = h2.send_request(request, true).unwrap_err();
|
let err = client.send_request(request, true).unwrap_err();
|
||||||
assert_eq!(err.to_string(), "user error: rejected");
|
assert_eq!(err.to_string(), "user error: rejected");
|
||||||
|
|
||||||
h2.expect("h2")
|
req.send_data("hello".into(), true).expect("req send_data");
|
||||||
|
h2.drive(req.expect("req")).and_then(move |(h2, _)| {
|
||||||
|
req2.send_data("hello".into(), true)
|
||||||
|
.expect("req2 send_data");
|
||||||
|
h2.expect("h2").join(req2.expect("req2"))
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
h2.join(srv).wait().expect("wait");
|
h2.join(srv).wait().expect("wait");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ fn send_data_without_requesting_capacity() {
|
|||||||
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
@@ -35,7 +35,7 @@ fn send_data_without_requesting_capacity() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// The capacity should be immediately allocated
|
// The capacity should be immediately allocated
|
||||||
assert_eq!(stream.capacity(), 0);
|
assert_eq!(stream.capacity(), 0);
|
||||||
@@ -82,14 +82,14 @@ fn release_capacity_sends_window_update() {
|
|||||||
// gotta end the connection
|
// gotta end the connection
|
||||||
.map(drop);
|
.map(drop);
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true).unwrap()
|
let req = client.send_request(request, true).unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
// Get the response
|
// Get the response
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -145,14 +145,14 @@ fn release_capacity_of_small_amount_does_not_send_window_update() {
|
|||||||
// gotta end the connection
|
// gotta end the connection
|
||||||
.map(drop);
|
.map(drop);
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true).unwrap()
|
let req = client.send_request(request, true).unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
// Get the response
|
// Get the response
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -212,14 +212,15 @@ fn recv_data_overflows_connection_window() {
|
|||||||
.recv_frame(frames::go_away(0).flow_control());
|
.recv_frame(frames::go_away(0).flow_control());
|
||||||
// connection is ended by client
|
// connection is ended by client
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true)
|
let req = client
|
||||||
|
.send_request(request, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -281,14 +282,15 @@ fn recv_data_overflows_stream_window() {
|
|||||||
.initial_window_size(16_384)
|
.initial_window_size(16_384)
|
||||||
.handshake::<_, Bytes>(io)
|
.handshake::<_, Bytes>(io)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true)
|
let req = client
|
||||||
|
.send_request(request, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -333,7 +335,7 @@ fn stream_close_by_data_frame_releases_capacity() {
|
|||||||
|
|
||||||
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
|
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
@@ -341,7 +343,7 @@ fn stream_close_by_data_frame_releases_capacity() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
let mut s1 = h2.send_request(request, false).unwrap();
|
let mut s1 = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// This effectively reserves the entire connection window
|
// This effectively reserves the entire connection window
|
||||||
s1.reserve_capacity(window_size);
|
s1.reserve_capacity(window_size);
|
||||||
@@ -357,7 +359,7 @@ fn stream_close_by_data_frame_releases_capacity() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Create a second stream
|
// Create a second stream
|
||||||
let mut s2 = h2.send_request(request, false).unwrap();
|
let mut s2 = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Request capacity
|
// Request capacity
|
||||||
s2.reserve_capacity(5);
|
s2.reserve_capacity(5);
|
||||||
@@ -401,7 +403,7 @@ fn stream_close_by_trailers_frame_releases_capacity() {
|
|||||||
|
|
||||||
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
|
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
@@ -409,7 +411,7 @@ fn stream_close_by_trailers_frame_releases_capacity() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
let mut s1 = h2.send_request(request, false).unwrap();
|
let mut s1 = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// This effectively reserves the entire connection window
|
// This effectively reserves the entire connection window
|
||||||
s1.reserve_capacity(window_size);
|
s1.reserve_capacity(window_size);
|
||||||
@@ -425,7 +427,7 @@ fn stream_close_by_trailers_frame_releases_capacity() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Create a second stream
|
// Create a second stream
|
||||||
let mut s2 = h2.send_request(request, false).unwrap();
|
let mut s2 = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Request capacity
|
// Request capacity
|
||||||
s2.reserve_capacity(5);
|
s2.reserve_capacity(5);
|
||||||
@@ -504,14 +506,14 @@ fn recv_window_update_on_stream_closed_by_data_frame() {
|
|||||||
|
|
||||||
let h2 = Client::handshake(io)
|
let h2 = Client::handshake(io)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stream = h2.send_request(request, false).unwrap();
|
let stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Wait for the response
|
// Wait for the response
|
||||||
h2.drive(GetResponse {
|
h2.drive(GetResponse {
|
||||||
@@ -547,14 +549,14 @@ fn reserved_capacity_assigned_in_multi_window_updates() {
|
|||||||
|
|
||||||
let h2 = Client::handshake(io)
|
let h2 = Client::handshake(io)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Consume the capacity
|
// Consume the capacity
|
||||||
let payload = vec![0; frame::DEFAULT_INITIAL_WINDOW_SIZE as usize];
|
let payload = vec![0; frame::DEFAULT_INITIAL_WINDOW_SIZE as usize];
|
||||||
@@ -674,17 +676,19 @@ fn connection_notified_on_released_capacity() {
|
|||||||
|
|
||||||
|
|
||||||
let th2 = thread::spawn(move || {
|
let th2 = thread::spawn(move || {
|
||||||
let h2 = Client::handshake(io).wait().unwrap();
|
let (mut client, h2) = Client::handshake(io).wait().unwrap();
|
||||||
|
|
||||||
let (mut h2, _) = h2.drive(settings_rx).wait().unwrap();
|
let (h2, _) = h2.drive(settings_rx).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::get("https://example.com/a").body(()).unwrap();
|
let request = Request::get("https://example.com/a").body(()).unwrap();
|
||||||
|
|
||||||
tx.send(h2.send_request(request, true).unwrap()).unwrap();
|
tx.send(client.send_request(request, true).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let request = Request::get("https://example.com/b").body(()).unwrap();
|
let request = Request::get("https://example.com/b").body(()).unwrap();
|
||||||
|
|
||||||
tx.send(h2.send_request(request, true).unwrap()).unwrap();
|
tx.send(client.send_request(request, true).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Run the connection to completion
|
// Run the connection to completion
|
||||||
h2.wait().unwrap();
|
h2.wait().unwrap();
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ fn recv_single_ping() {
|
|||||||
let (m, mock) = mock::new();
|
let (m, mock) = mock::new();
|
||||||
|
|
||||||
// Create the handshake
|
// Create the handshake
|
||||||
let h2 = Client::handshake(m).unwrap().and_then(|conn| conn.unwrap());
|
let h2 = Client::handshake(m)
|
||||||
|
.unwrap()
|
||||||
|
.and_then(|(_, conn)| conn.unwrap());
|
||||||
|
|
||||||
let mock = mock.assert_client_handshake()
|
let mock = mock.assert_client_handshake()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fn single_stream_send_large_body() {
|
|||||||
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
@@ -33,7 +33,7 @@ fn single_stream_send_large_body() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Reserve capacity to send the payload
|
// Reserve capacity to send the payload
|
||||||
stream.reserve_capacity(payload.len());
|
stream.reserve_capacity(payload.len());
|
||||||
@@ -79,7 +79,7 @@ fn single_stream_send_extra_large_body_multi_frames_one_buffer() {
|
|||||||
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
@@ -87,7 +87,7 @@ fn single_stream_send_extra_large_body_multi_frames_one_buffer() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
stream.reserve_capacity(payload.len());
|
stream.reserve_capacity(payload.len());
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ fn single_stream_send_extra_large_body_multi_frames_multi_buffer() {
|
|||||||
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
@@ -152,7 +152,7 @@ fn single_stream_send_extra_large_body_multi_frames_multi_buffer() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
stream.reserve_capacity(payload.len());
|
stream.reserve_capacity(payload.len());
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ fn send_data_receive_window_update() {
|
|||||||
|
|
||||||
let h2 = Client::handshake(m)
|
let h2 = Client::handshake(m)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
@@ -185,7 +185,7 @@ fn send_data_receive_window_update() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Send data frame
|
// Send data frame
|
||||||
stream.send_data("hello".into(), false).unwrap();
|
stream.send_data("hello".into(), false).unwrap();
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ fn recv_push_works() {
|
|||||||
.send_frame(frames::headers(1).response(200).eos())
|
.send_frame(frames::headers(1).response(200).eos())
|
||||||
.send_frame(frames::headers(2).response(200).eos());
|
.send_frame(frames::headers(2).response(200).eos());
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let req = h2.send_request(request, true)
|
let req = client
|
||||||
|
.send_request(request, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -61,13 +62,13 @@ fn recv_push_when_push_disabled_is_conn_error() {
|
|||||||
.enable_push(false)
|
.enable_push(false)
|
||||||
.handshake::<_, Bytes>(io)
|
.handshake::<_, Bytes>(io)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://http2.akamai.com/")
|
.uri("https://http2.akamai.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let req = h2.send_request(request, true).unwrap().then(|res| {
|
let req = client.send_request(request, true).unwrap().then(|res| {
|
||||||
let err = res.unwrap_err();
|
let err = res.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.to_string(),
|
err.to_string(),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fn send_recv_headers_only() {
|
|||||||
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
@@ -29,7 +29,7 @@ fn send_recv_headers_only() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let mut stream = h2.send_request(request, true).unwrap();
|
let mut stream = client.send_request(request, true).unwrap();
|
||||||
|
|
||||||
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||||
@@ -62,7 +62,7 @@ fn send_recv_data() {
|
|||||||
])
|
])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::builder().handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::builder().handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
@@ -71,7 +71,7 @@ fn send_recv_data() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Reserve send capacity
|
// Reserve send capacity
|
||||||
stream.reserve_capacity(5);
|
stream.reserve_capacity(5);
|
||||||
@@ -119,7 +119,7 @@ fn send_headers_recv_data_single_frame() {
|
|||||||
])
|
])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
@@ -128,7 +128,7 @@ fn send_headers_recv_data_single_frame() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let mut stream = h2.send_request(request, true).unwrap();
|
let mut stream = client.send_request(request, true).unwrap();
|
||||||
|
|
||||||
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@@ -154,32 +154,29 @@ fn closed_streams_are_released() {
|
|||||||
let _ = ::env_logger::init();
|
let _ = ::env_logger::init();
|
||||||
let (io, srv) = mock::new();
|
let (io, srv) = mock::new();
|
||||||
|
|
||||||
let h2 = Client::handshake(io)
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
.unwrap()
|
let request = Request::get("https://example.com/").body(()).unwrap();
|
||||||
.and_then(|mut h2| {
|
|
||||||
let request = Request::get("https://example.com/").body(()).unwrap();
|
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
let stream = h2.send_request(request, true).unwrap();
|
let stream = client.send_request(request, true).unwrap();
|
||||||
h2.drive(stream)
|
h2.drive(stream).and_then(move |(_, response)| {
|
||||||
})
|
|
||||||
.and_then(|(h2, response)| {
|
|
||||||
assert_eq!(response.status(), StatusCode::NO_CONTENT);
|
assert_eq!(response.status(), StatusCode::NO_CONTENT);
|
||||||
|
|
||||||
// There are no active streams
|
// There are no active streams
|
||||||
assert_eq!(0, h2.num_active_streams());
|
assert_eq!(0, client.num_active_streams());
|
||||||
|
|
||||||
// The response contains a handle for the body. This keeps the
|
// The response contains a handle for the body. This keeps the
|
||||||
// stream wired.
|
// stream wired.
|
||||||
assert_eq!(1, h2.num_wired_streams());
|
assert_eq!(1, client.num_wired_streams());
|
||||||
|
|
||||||
drop(response);
|
drop(response);
|
||||||
|
|
||||||
// The stream state is now free
|
// The stream state is now free
|
||||||
assert_eq!(0, h2.num_wired_streams());
|
assert_eq!(0, client.num_wired_streams());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let srv = srv.assert_client_handshake()
|
let srv = srv.assert_client_handshake()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -200,14 +197,15 @@ fn errors_if_recv_frame_exceeds_max_frame_size() {
|
|||||||
let _ = ::env_logger::init();
|
let _ = ::env_logger::init();
|
||||||
let (io, mut srv) = mock::new();
|
let (io, mut srv) = mock::new();
|
||||||
|
|
||||||
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
|
let h2 = Client::handshake(io).unwrap().and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://example.com/")
|
.uri("https://example.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true)
|
let req = client
|
||||||
|
.send_request(request, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
@@ -258,14 +256,15 @@ fn configure_max_frame_size() {
|
|||||||
.max_frame_size(16_384 * 2)
|
.max_frame_size(16_384 * 2)
|
||||||
.handshake::<_, Bytes>(io)
|
.handshake::<_, Bytes>(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|mut h2| {
|
.and_then(|(mut client, h2)| {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("https://example.com/")
|
.uri("https://example.com/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = h2.send_request(request, true)
|
let req = client
|
||||||
|
.send_request(request, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.expect("response")
|
.expect("response")
|
||||||
.and_then(|resp| {
|
.and_then(|resp| {
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ where
|
|||||||
Async::Ready((frame, handle)) => (frame, handle),
|
Async::Ready((frame, handle)) => (frame, handle),
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
};
|
};
|
||||||
assert_eq!(frame.unwrap(), self.frame);
|
assert_eq!(frame.unwrap(), self.frame, "recv_frame");
|
||||||
Ok(Async::Ready(handle))
|
Ok(Async::Ready(handle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
//! Utilities to support tests.
|
//! Utilities to support tests.
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unstable"))]
|
||||||
|
compile_error!(
|
||||||
|
"Tests depend on the 'unstable' feature on h2. \
|
||||||
|
Retry with `cargo test --features unstable`"
|
||||||
|
);
|
||||||
|
|
||||||
pub extern crate bytes;
|
pub extern crate bytes;
|
||||||
pub extern crate env_logger;
|
pub extern crate env_logger;
|
||||||
pub extern crate futures;
|
pub extern crate futures;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub trait ClientExt {
|
|||||||
fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error>;
|
fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B> ClientExt for Client<T, B>
|
impl<T, B> ClientExt for client::Connection<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + 'static,
|
T: AsyncRead + AsyncWrite + 'static,
|
||||||
B: IntoBuf + 'static,
|
B: IntoBuf + 'static,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ fn recv_trailers_only() {
|
|||||||
])
|
])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
@@ -32,7 +32,7 @@ fn recv_trailers_only() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let mut stream = h2.send_request(request, true).unwrap();
|
let mut stream = client.send_request(request, true).unwrap();
|
||||||
|
|
||||||
let response = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
let response = h2.run(poll_fn(|| stream.poll_response())).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
@@ -71,7 +71,7 @@ fn send_trailers_immediately() {
|
|||||||
])
|
])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = Client::handshake(mock).wait().unwrap();
|
let (mut client, mut h2) = Client::handshake(mock).wait().unwrap();
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
@@ -80,7 +80,7 @@ fn send_trailers_immediately() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("sending request");
|
info!("sending request");
|
||||||
let mut stream = h2.send_request(request, false).unwrap();
|
let mut stream = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
let mut trailers = HeaderMap::new();
|
let mut trailers = HeaderMap::new();
|
||||||
trailers.insert("zomg", "hello".parse().unwrap());
|
trailers.insert("zomg", "hello".parse().unwrap());
|
||||||
|
|||||||
Reference in New Issue
Block a user