remove unused pieces from PingPong (#134)
Adds some extra tests as well, to be sure.
This commit is contained in:
@@ -13,10 +13,10 @@ pub struct Ping {
|
|||||||
|
|
||||||
impl Ping {
|
impl Ping {
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
pub fn new() -> Ping {
|
pub fn new(payload: Payload) -> Ping {
|
||||||
Ping {
|
Ping {
|
||||||
ack: false,
|
ack: false,
|
||||||
payload: Payload::default(),
|
payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ where
|
|||||||
codec: Codec<T, Prioritized<B::Buf>>,
|
codec: Codec<T, Prioritized<B::Buf>>,
|
||||||
|
|
||||||
/// Ping/pong handler
|
/// Ping/pong handler
|
||||||
ping_pong: PingPong<Prioritized<B::Buf>>,
|
ping_pong: PingPong,
|
||||||
|
|
||||||
/// Connection settings
|
/// Connection settings
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
|
use codec::Codec;
|
||||||
use frame::Ping;
|
use frame::Ping;
|
||||||
use proto::*;
|
use proto::PingPayload;
|
||||||
|
|
||||||
|
use bytes::Buf;
|
||||||
|
use futures::{Async, Poll};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use tokio_io::AsyncWrite;
|
||||||
|
|
||||||
/// Acknowledges ping requests from the remote.
|
/// Acknowledges ping requests from the remote.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PingPong<B> {
|
pub struct PingPong {
|
||||||
// TODO: this doesn't need to save the entire frame
|
sending_pong: Option<PingPayload>,
|
||||||
sending_pong: Option<Frame<B>>,
|
|
||||||
received_pong: Option<PingPayload>,
|
|
||||||
// TODO: factor this out
|
|
||||||
blocked_ping: Option<task::Task>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> PingPong<B>
|
impl PingPong {
|
||||||
where
|
|
||||||
B: Buf,
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
PingPong {
|
PingPong {
|
||||||
sending_pong: None,
|
sending_pong: None,
|
||||||
received_pong: None,
|
|
||||||
blocked_ping: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,24 +26,17 @@ where
|
|||||||
// calling `recv_ping`.
|
// calling `recv_ping`.
|
||||||
assert!(self.sending_pong.is_none());
|
assert!(self.sending_pong.is_none());
|
||||||
|
|
||||||
if ping.is_ack() {
|
if !ping.is_ack() {
|
||||||
// Save acknowledgements to be returned from take_pong().
|
|
||||||
self.received_pong = Some(ping.into_payload());
|
|
||||||
|
|
||||||
if let Some(task) = self.blocked_ping.take() {
|
|
||||||
task.notify();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Save the ping's payload to be sent as an acknowledgement.
|
// Save the ping's payload to be sent as an acknowledgement.
|
||||||
let pong = Ping::pong(ping.into_payload());
|
self.sending_pong = Some(ping.into_payload());
|
||||||
self.sending_pong = Some(pong.into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send any pending pongs.
|
/// Send any pending pongs.
|
||||||
pub fn send_pending_pong<T>(&mut self, dst: &mut Codec<T, B>) -> Poll<(), io::Error>
|
pub fn send_pending_pong<T, B>(&mut self, dst: &mut Codec<T, B>) -> Poll<(), io::Error>
|
||||||
where
|
where
|
||||||
T: AsyncWrite,
|
T: AsyncWrite,
|
||||||
|
B: Buf,
|
||||||
{
|
{
|
||||||
if let Some(pong) = self.sending_pong.take() {
|
if let Some(pong) = self.sending_pong.take() {
|
||||||
if !dst.poll_ready()?.is_ready() {
|
if !dst.poll_ready()?.is_ready() {
|
||||||
@@ -56,7 +44,7 @@ where
|
|||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.buffer(pong).ok().expect("invalid pong frame");
|
dst.buffer(Ping::pong(pong).into()).ok().expect("invalid pong frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Async::Ready(()))
|
Ok(Async::Ready(()))
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fn recv_single_ping() {
|
|||||||
let mock = mock.assert_client_handshake()
|
let mock = mock.assert_client_handshake()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_then(|(_, mut mock)| {
|
.and_then(|(_, mut mock)| {
|
||||||
let frame = frame::Ping::new();
|
let frame = frame::Ping::new(Default::default());
|
||||||
mock.send(frame.into()).unwrap();
|
mock.send(frame.into()).unwrap();
|
||||||
|
|
||||||
mock.into_future().unwrap()
|
mock.into_future().unwrap()
|
||||||
@@ -34,3 +34,73 @@ fn recv_single_ping() {
|
|||||||
|
|
||||||
let _ = h2.join(mock).wait().unwrap();
|
let _ = h2.join(mock).wait().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recv_multiple_pings() {
|
||||||
|
let _ = ::env_logger::init();
|
||||||
|
let (io, client) = mock::new();
|
||||||
|
|
||||||
|
let client = client.assert_server_handshake()
|
||||||
|
.expect("client handshake")
|
||||||
|
.recv_settings()
|
||||||
|
.send_frame(frames::ping([1; 8]))
|
||||||
|
.send_frame(frames::ping([2; 8]))
|
||||||
|
.recv_frame(frames::ping([1; 8]).pong())
|
||||||
|
.recv_frame(frames::ping([2; 8]).pong())
|
||||||
|
.close();
|
||||||
|
|
||||||
|
let srv = Server::handshake(io)
|
||||||
|
.expect("handshake")
|
||||||
|
.and_then(|srv| {
|
||||||
|
// future of first request, which never comes
|
||||||
|
srv.into_future().unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
srv.join(client).wait().expect("wait");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pong_has_highest_priority() {
|
||||||
|
let _ = ::env_logger::init();
|
||||||
|
let (io, client) = mock::new();
|
||||||
|
|
||||||
|
let data = Bytes::from(vec![0; 16_384]);
|
||||||
|
|
||||||
|
let client = client.assert_server_handshake()
|
||||||
|
.expect("client handshake")
|
||||||
|
.recv_settings()
|
||||||
|
.send_frame(
|
||||||
|
frames::headers(1)
|
||||||
|
.request("POST", "https://http2.akamai.com/")
|
||||||
|
)
|
||||||
|
.send_frame(frames::data(1, data.clone()).eos())
|
||||||
|
.send_frame(frames::ping([1; 8]))
|
||||||
|
.recv_frame(frames::ping([1; 8]).pong())
|
||||||
|
.recv_frame(frames::headers(1).response(200).eos())
|
||||||
|
.close();
|
||||||
|
|
||||||
|
let srv = Server::handshake(io)
|
||||||
|
.expect("handshake")
|
||||||
|
.and_then(|srv| {
|
||||||
|
// future of first request
|
||||||
|
srv.into_future().unwrap()
|
||||||
|
}).and_then(move |(reqstream, srv)| {
|
||||||
|
let (req, mut stream) = reqstream.expect("request");
|
||||||
|
assert_eq!(req.method(), "POST");
|
||||||
|
let body = req.into_parts().1;
|
||||||
|
|
||||||
|
body.concat2()
|
||||||
|
.expect("body")
|
||||||
|
.and_then(move |body| {
|
||||||
|
assert_eq!(body.len(), data.len());
|
||||||
|
let res = Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
stream.send_response(res, true).expect("response");
|
||||||
|
srv.into_future().unwrap()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
srv.join(client).wait().expect("wait");
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ pub fn settings() -> Mock<frame::Settings> {
|
|||||||
Mock(frame::Settings::default())
|
Mock(frame::Settings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ping(payload: [u8; 8]) -> Mock<frame::Ping> {
|
||||||
|
Mock(frame::Ping::new(payload))
|
||||||
|
}
|
||||||
|
|
||||||
// === Generic helpers of all frame types
|
// === Generic helpers of all frame types
|
||||||
|
|
||||||
pub struct Mock<T>(T);
|
pub struct Mock<T>(T);
|
||||||
@@ -263,6 +267,21 @@ impl From<Mock<frame::Settings>> for SendFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==== Ping helpers
|
||||||
|
|
||||||
|
impl Mock<frame::Ping> {
|
||||||
|
pub fn pong(self) -> Self {
|
||||||
|
let payload = self.0.into_payload();
|
||||||
|
Mock(frame::Ping::pong(payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Mock<frame::Ping>> for SendFrame {
|
||||||
|
fn from(src: Mock<frame::Ping>) -> Self {
|
||||||
|
Frame::Ping(src.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== "trait alias" for types that are HttpTryFrom and have Debug Errors ====
|
// ==== "trait alias" for types that are HttpTryFrom and have Debug Errors ====
|
||||||
|
|
||||||
pub trait HttpTryInto<T> {
|
pub trait HttpTryInto<T> {
|
||||||
|
|||||||
Reference in New Issue
Block a user