414 lines
12 KiB
Rust
414 lines
12 KiB
Rust
use {client, ConnectionError, Frame};
|
|
use HeaderMap;
|
|
use frame::{self, StreamId};
|
|
|
|
use proto::*;
|
|
|
|
use http::{Request, Response};
|
|
use bytes::{Bytes, IntoBuf};
|
|
use tokio_io::{AsyncRead, AsyncWrite};
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
/// An H2 connection
|
|
#[derive(Debug)]
|
|
pub struct Connection<T, P, B: IntoBuf = Bytes> {
|
|
// Codec
|
|
codec: Codec<T, B::Buf>,
|
|
|
|
// TODO: Remove <B>
|
|
ping_pong: PingPong<B::Buf>,
|
|
settings: Settings,
|
|
streams: Streams<P, B::Buf>,
|
|
|
|
_phantom: PhantomData<P>,
|
|
}
|
|
|
|
impl<T, P, B> Connection<T, P, B>
|
|
where T: AsyncRead + AsyncWrite,
|
|
P: Peer,
|
|
B: IntoBuf,
|
|
{
|
|
pub fn new(codec: Codec<T, B::Buf>) -> Connection<T, P, B> {
|
|
// TODO: Actually configure
|
|
let streams = Streams::new(streams::Config {
|
|
max_remote_initiated: None,
|
|
init_remote_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
|
|
max_local_initiated: None,
|
|
init_local_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
|
|
});
|
|
|
|
Connection {
|
|
codec: codec,
|
|
ping_pong: PingPong::new(),
|
|
settings: Settings::new(),
|
|
streams: streams,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Polls for the next update to a remote flow control window.
|
|
pub fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> {
|
|
self.streams.poll_window_update()
|
|
}
|
|
|
|
/// Increases the capacity of a local flow control window.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// THis function panics if `incr` is not a valid window size.
|
|
pub fn expand_window(&mut self, id: StreamId, incr: usize)
|
|
-> Result<(), ConnectionError>
|
|
{
|
|
assert!(incr <= MAX_WINDOW_SIZE as usize);
|
|
self.streams.expand_window(id, incr as WindowSize)
|
|
}
|
|
|
|
pub fn update_local_settings(&mut self, _local: frame::SettingSet) -> Result<(), ConnectionError> {
|
|
unimplemented!();
|
|
}
|
|
|
|
pub fn remote_initial_window_size(&self) -> u32 {
|
|
unimplemented!();
|
|
}
|
|
|
|
pub fn remote_max_concurrent_streams(&self) -> Option<usize> {
|
|
unimplemented!();
|
|
}
|
|
|
|
pub fn remote_push_enabled(&self) -> Option<bool> {
|
|
unimplemented!();
|
|
}
|
|
|
|
/// Returns `Ready` when the connection is ready to receive a frame.
|
|
pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
|
|
try_ready!(self.poll_send_ready());
|
|
|
|
// TODO: Once there is write buffering, this shouldn't be needed
|
|
try_ready!(self.codec.poll_ready());
|
|
|
|
Ok(().into())
|
|
}
|
|
|
|
/// Advances the internal state of the connection.
|
|
pub fn poll(&mut self) -> Poll<(), ConnectionError> {
|
|
use frame::Frame::*;
|
|
|
|
loop {
|
|
// First, ensure that the `Connection` is able to receive a frame
|
|
try_ready!(self.poll_recv_ready());
|
|
|
|
trace!("polling codec");
|
|
|
|
let frame = match try!(self.codec.poll()) {
|
|
Async::Ready(frame) => frame,
|
|
Async::NotReady => {
|
|
// Flush any pending writes
|
|
let _ = try!(self.poll_complete());
|
|
return Ok(Async::NotReady);
|
|
}
|
|
};
|
|
|
|
match frame {
|
|
Some(Headers(frame)) => {
|
|
trace!("recv HEADERS; frame={:?}", frame);
|
|
|
|
if let Some(frame) = try!(self.streams.recv_headers(frame)) {
|
|
unimplemented!();
|
|
}
|
|
|
|
/*
|
|
// Update stream state while ensuring that the headers frame
|
|
// can be received.
|
|
if let Some(frame) = try!(self.streams.recv_headers(frame)) {
|
|
let frame = Self::convert_poll_message(frame)?;
|
|
return Ok(Some(frame).into());
|
|
}
|
|
*/
|
|
}
|
|
Some(Data(frame)) => {
|
|
unimplemented!();
|
|
/*
|
|
trace!("recv DATA; frame={:?}", frame);
|
|
try!(self.streams.recv_data(&frame));
|
|
|
|
let frame = Frame::Data {
|
|
id: frame.stream_id(),
|
|
end_of_stream: frame.is_end_stream(),
|
|
data: frame.into_payload(),
|
|
};
|
|
|
|
return Ok(Some(frame).into());
|
|
*/
|
|
}
|
|
Some(Reset(frame)) => {
|
|
unimplemented!();
|
|
/*
|
|
trace!("recv RST_STREAM; frame={:?}", frame);
|
|
try!(self.streams.recv_reset(&frame));
|
|
|
|
let frame = Frame::Reset {
|
|
id: frame.stream_id(),
|
|
error: frame.reason(),
|
|
};
|
|
|
|
return Ok(Some(frame).into());
|
|
*/
|
|
}
|
|
Some(PushPromise(frame)) => {
|
|
unimplemented!();
|
|
/*
|
|
trace!("recv PUSH_PROMISE; frame={:?}", frame);
|
|
try!(self.streams.recv_push_promise(frame));
|
|
*/
|
|
}
|
|
Some(Settings(frame)) => {
|
|
trace!("recv SETTINGS; frame={:?}", frame);
|
|
self.settings.recv_settings(frame);
|
|
|
|
// TODO: ACK must be sent THEN settings applied.
|
|
}
|
|
Some(Ping(frame)) => {
|
|
unimplemented!();
|
|
/*
|
|
trace!("recv PING; frame={:?}", frame);
|
|
self.ping_pong.recv_ping(frame);
|
|
*/
|
|
}
|
|
Some(WindowUpdate(frame)) => {
|
|
unimplemented!();
|
|
/*
|
|
trace!("recv WINDOW_UPDATE; frame={:?}", frame);
|
|
try!(self.streams.recv_window_update(frame));
|
|
*/
|
|
}
|
|
None => {
|
|
// TODO: Is this correct?
|
|
trace!("codec closed");
|
|
return Ok(Async::Ready(()));
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Flush the write buffer
|
|
unimplemented!();
|
|
}
|
|
|
|
/*
|
|
pub fn send_data(self,
|
|
id: StreamId,
|
|
data: B,
|
|
end_of_stream: bool)
|
|
-> sink::Send<Self>
|
|
{
|
|
self.send(Frame::Data {
|
|
id,
|
|
data,
|
|
end_of_stream,
|
|
})
|
|
}
|
|
|
|
pub fn send_trailers(self,
|
|
id: StreamId,
|
|
headers: HeaderMap)
|
|
-> sink::Send<Self>
|
|
{
|
|
self.send(Frame::Trailers {
|
|
id,
|
|
headers,
|
|
})
|
|
}
|
|
*/
|
|
|
|
// ===== Private =====
|
|
|
|
/// Returns `Ready` when the `Connection` is ready to receive a frame from
|
|
/// the socket.
|
|
fn poll_recv_ready(&mut self) -> Poll<(), ConnectionError> {
|
|
// Pong, settings ack, and stream refusals are high priority frames to
|
|
// send. If the write buffer is full, we stop reading any further frames
|
|
// until these high priority writes can be committed to the buffer.
|
|
|
|
try_ready!(self.ping_pong.send_pending_pong(&mut self.codec));
|
|
try_ready!(self.settings.send_pending_ack(&mut self.codec));
|
|
try_ready!(self.streams.send_pending_refusal(&mut self.codec));
|
|
|
|
Ok(().into())
|
|
}
|
|
|
|
/// Returns `Ready` when the `Connection` is ready to accept a frame from
|
|
/// the user
|
|
///
|
|
/// This function is currently used by poll_complete, but at some point it
|
|
/// will probably not be required.
|
|
fn poll_send_ready(&mut self) -> Poll<(), ConnectionError> {
|
|
// TODO: Is this function needed?
|
|
try_ready!(self.poll_recv_ready());
|
|
|
|
Ok(().into())
|
|
}
|
|
|
|
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
|
|
try_ready!(self.poll_send_ready());
|
|
|
|
// Ensure all window updates have been sent.
|
|
try_ready!(self.streams.poll_complete(&mut self.codec));
|
|
try_ready!(self.codec.poll_complete());
|
|
|
|
Ok(().into())
|
|
}
|
|
|
|
fn convert_poll_message(frame: frame::Headers) -> Result<Frame<P::Poll>, ConnectionError> {
|
|
if frame.is_trailers() {
|
|
Ok(Frame::Trailers {
|
|
id: frame.stream_id(),
|
|
headers: frame.into_fields()
|
|
})
|
|
} else {
|
|
Ok(Frame::Headers {
|
|
id: frame.stream_id(),
|
|
end_of_stream: frame.is_end_stream(),
|
|
headers: P::convert_poll_message(frame)?,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T, B> Connection<T, client::Peer, B>
|
|
where T: AsyncRead + AsyncWrite,
|
|
B: IntoBuf,
|
|
{
|
|
/// 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<client::Peer, B::Buf>, ConnectionError>
|
|
{
|
|
self.streams.send_request(request, end_of_stream)
|
|
}
|
|
}
|
|
|
|
/*
|
|
impl<T, B> Connection<T, Client, B>
|
|
where T: AsyncRead + AsyncWrite,
|
|
B: IntoBuf,
|
|
{
|
|
pub fn send_request(self,
|
|
id: StreamId, // TODO: Generate one internally?
|
|
request: request::Head,
|
|
end_of_stream: bool)
|
|
-> sink::Send<Self>
|
|
{
|
|
self.send(Frame::Headers {
|
|
id: id,
|
|
headers: request,
|
|
end_of_stream: end_of_stream,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<T, B> Connection<T, Server, B>
|
|
where T: AsyncRead + AsyncWrite,
|
|
B: IntoBuf,
|
|
{
|
|
pub fn send_response(self,
|
|
id: StreamId, // TODO: Generate one internally?
|
|
response: response::Head,
|
|
end_of_stream: bool)
|
|
-> sink::Send<Self>
|
|
{
|
|
self.send(Frame::Headers {
|
|
id: id,
|
|
headers: response,
|
|
end_of_stream: end_of_stream,
|
|
})
|
|
}
|
|
|
|
pub fn send_push_promise(self,
|
|
id: StreamId,
|
|
promised_id: StreamId)
|
|
-> sink::Send<Self>
|
|
{
|
|
self.send(Frame::PushPromise {
|
|
id,
|
|
promised_id,
|
|
})
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
impl<T, P, B> Sink for Connection<T, P, B>
|
|
where T: AsyncRead + AsyncWrite,
|
|
P: Peer,
|
|
B: IntoBuf,
|
|
{
|
|
type SinkItem = Frame<P::Send, B>;
|
|
type SinkError = ConnectionError;
|
|
|
|
/// Sends a frame to the remote.
|
|
fn start_send(&mut self, item: Self::SinkItem)
|
|
-> StartSend<Self::SinkItem, Self::SinkError>
|
|
{
|
|
// TODO: Ensure connection is not corrupt
|
|
|
|
// Ensure that the connection is ready to accept a new frame
|
|
if !try!(self.poll_ready()).is_ready() {
|
|
return Ok(AsyncSink::NotReady(item));
|
|
}
|
|
|
|
let frame = match item {
|
|
Frame::Headers { id, headers, end_of_stream } => {
|
|
// This is a one-way conversion. By checking `poll_ready` first (above),
|
|
// it's already been determined that the inner `Sink` can accept the item.
|
|
// If the item is rejected, then there is a bug.
|
|
let frame = P::convert_send_message(id, headers, end_of_stream);
|
|
|
|
// Update the stream state
|
|
self.streams.send_headers(&frame)?;
|
|
|
|
frame::Frame::Headers(frame)
|
|
}
|
|
Frame::Data { id, data, end_of_stream } => {
|
|
let frame = frame::Data::from_buf(
|
|
id, data.into_buf(), end_of_stream);
|
|
|
|
self.streams.send_data(&frame)?;
|
|
|
|
frame.into()
|
|
}
|
|
Frame::Reset { id, error } => frame::Reset::new(id, error).into(),
|
|
Frame::Trailers { id, headers } => {
|
|
let mut frame = frame::Headers::new(
|
|
id,
|
|
frame::Pseudo::default(),
|
|
headers);
|
|
|
|
frame.set_end_stream();
|
|
|
|
self.streams.send_headers(&frame)?;
|
|
|
|
frame::Frame::Headers(frame)
|
|
}
|
|
/*
|
|
Frame::PushPromise { id, promise } => {
|
|
unimplemented!();
|
|
}
|
|
Frame::Error { id, error } => {
|
|
unimplemented!();
|
|
}
|
|
*/
|
|
_ => unimplemented!(),
|
|
};
|
|
|
|
// Write the frame to the socket
|
|
let res = self.codec.start_send(frame)?;
|
|
|
|
// Ensure that the write was accepted. This is always true due to the
|
|
// check at the top of the function
|
|
assert!(res.is_ready());
|
|
|
|
// Return success
|
|
Ok(AsyncSink::Ready)
|
|
}
|
|
}
|
|
*/
|