Validate & convert messages before buffering
Malformed requests and responses should immediately result in a RST_STREAM. To support this, received header frames are validated and converted to Request / Response values immediately on receipt and before buffering.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
use {frame, HeaderMap, ConnectionError};
|
use {frame, HeaderMap, ConnectionError};
|
||||||
use frame::StreamId;
|
use frame::StreamId;
|
||||||
use proto::{self, Connection, WindowSize};
|
use proto::{self, Connection, WindowSize, ProtoError};
|
||||||
|
use error::Reason::*;
|
||||||
|
|
||||||
use http::{Request, Response};
|
use http::{Request, Response};
|
||||||
use futures::{Future, Poll, Sink, Async, AsyncSink};
|
use futures::{Future, Poll, Sink, Async, AsyncSink};
|
||||||
@@ -254,7 +255,30 @@ impl proto::Peer for Peer {
|
|||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError> {
|
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ProtoError> {
|
||||||
headers.into_response()
|
let mut b = Response::builder();
|
||||||
|
|
||||||
|
let stream_id = headers.stream_id();
|
||||||
|
let (pseudo, fields) = headers.into_parts();
|
||||||
|
|
||||||
|
if let Some(status) = pseudo.status {
|
||||||
|
b.status(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut response = match b.body(()) {
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(_) => {
|
||||||
|
// TODO: Should there be more specialized handling for different
|
||||||
|
// kinds of errors
|
||||||
|
return Err(ProtoError::Stream {
|
||||||
|
id: stream_id,
|
||||||
|
reason: ProtocolError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
*response.headers_mut() = fields;
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
use super::{StreamId, StreamDependency};
|
use super::{StreamId, StreamDependency};
|
||||||
use ConnectionError;
|
|
||||||
use hpack;
|
use hpack;
|
||||||
use frame::{self, Frame, Head, Kind, Error};
|
use frame::{self, Frame, Head, Kind, Error};
|
||||||
use HeaderMap;
|
use HeaderMap;
|
||||||
use error::Reason::*;
|
|
||||||
|
|
||||||
use http::{version, uri, Request, Response, Method, StatusCode, Uri};
|
use http::{uri, Method, StatusCode, Uri};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use bytes::{BytesMut, Bytes};
|
use bytes::{BytesMut, Bytes};
|
||||||
@@ -70,13 +68,13 @@ pub struct Continuation {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Pseudo {
|
pub struct Pseudo {
|
||||||
// Request
|
// Request
|
||||||
method: Option<Method>,
|
pub method: Option<Method>,
|
||||||
scheme: Option<String<Bytes>>,
|
pub scheme: Option<String<Bytes>>,
|
||||||
authority: Option<String<Bytes>>,
|
pub authority: Option<String<Bytes>>,
|
||||||
path: Option<String<Bytes>>,
|
pub path: Option<String<Bytes>>,
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
status: Option<StatusCode>,
|
pub status: Option<StatusCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -265,57 +263,8 @@ impl Headers {
|
|||||||
self.flags.set_end_stream()
|
self.flags.set_end_stream()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_response(self) -> Result<Response<()>, ConnectionError> {
|
pub fn into_parts(self) -> (Pseudo, HeaderMap) {
|
||||||
let mut b = Response::builder();
|
(self.pseudo, self.fields)
|
||||||
|
|
||||||
if let Some(status) = self.pseudo.status {
|
|
||||||
b.status(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut response = try!(b.body(()));
|
|
||||||
*response.headers_mut() = self.fields;
|
|
||||||
|
|
||||||
Ok(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_request(self) -> Result<Request<()>, ConnectionError> {
|
|
||||||
let mut b = Request::builder();
|
|
||||||
|
|
||||||
b.version(version::HTTP_2);
|
|
||||||
|
|
||||||
if let Some(method) = self.pseudo.method {
|
|
||||||
b.method(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specifying :status for a request is a protocol error
|
|
||||||
if self.pseudo.status.is_some() {
|
|
||||||
return Err(ProtocolError.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the URI
|
|
||||||
let mut parts = uri::Parts::default();
|
|
||||||
|
|
||||||
if let Some(scheme) = self.pseudo.scheme {
|
|
||||||
// TODO: Don't unwrap
|
|
||||||
parts.scheme = Some(uri::Scheme::from_shared(scheme.into_inner()).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(authority) = self.pseudo.authority {
|
|
||||||
// TODO: Don't unwrap
|
|
||||||
parts.authority = Some(uri::Authority::from_shared(authority.into_inner()).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(path) = self.pseudo.path {
|
|
||||||
// TODO: Don't unwrap
|
|
||||||
parts.path_and_query = Some(uri::PathAndQuery::from_shared(path.into_inner()).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
b.uri(parts);
|
|
||||||
|
|
||||||
let mut request = try!(b.body(()));
|
|
||||||
*request.headers_mut() = self.fields;
|
|
||||||
|
|
||||||
Ok(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_fields(self) -> HeaderMap {
|
pub fn into_fields(self) -> HeaderMap {
|
||||||
|
|||||||
@@ -73,16 +73,6 @@ pub enum Frame<T = Bytes> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Frame<T> {
|
impl<T> Frame<T> {
|
||||||
/// Returns true if the frame is a DATA frame.
|
|
||||||
pub fn is_data(&self) -> bool {
|
|
||||||
use self::Frame::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
Data(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map<F, U>(self, f: F) -> Frame<U>
|
pub fn map<F, U>(self, f: F) -> Frame<U>
|
||||||
where F: FnOnce(T) -> U
|
where F: FnOnce(T) -> U
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#![deny(warnings, missing_debug_implementations)]
|
// #![deny(warnings, missing_debug_implementations)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use bytes::{Buf, IntoBuf};
|
|||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use tokio_io::codec::length_delimited;
|
use tokio_io::codec::length_delimited;
|
||||||
|
|
||||||
use std::io;
|
use std::{fmt, io};
|
||||||
|
|
||||||
/// Either a Client or a Server
|
/// Either a Client or a Server
|
||||||
pub trait Peer {
|
pub trait Peer {
|
||||||
@@ -34,7 +34,7 @@ pub trait Peer {
|
|||||||
type Send;
|
type Send;
|
||||||
|
|
||||||
/// Message type polled from the transport
|
/// Message type polled from the transport
|
||||||
type Poll;
|
type Poll: fmt::Debug;
|
||||||
|
|
||||||
fn is_server() -> bool;
|
fn is_server() -> bool;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ pub trait Peer {
|
|||||||
headers: Self::Send,
|
headers: Self::Send,
|
||||||
end_of_stream: bool) -> frame::Headers;
|
end_of_stream: bool) -> frame::Headers;
|
||||||
|
|
||||||
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError>;
|
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ProtoError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PingPayload = [u8; 8];
|
pub type PingPayload = [u8; 8];
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub(super) struct Recv<B, P>
|
|||||||
pending_accept: store::Queue<B, stream::NextAccept, P>,
|
pending_accept: store::Queue<B, stream::NextAccept, P>,
|
||||||
|
|
||||||
/// Holds frames that are waiting to be read
|
/// Holds frames that are waiting to be read
|
||||||
buffer: Buffer<Frame<Bytes>>,
|
buffer: Buffer<Event<P::Poll>>,
|
||||||
|
|
||||||
/// Refused StreamId, this represents a frame that must be sent out.
|
/// Refused StreamId, this represents a frame that must be sent out.
|
||||||
refused: Option<StreamId>,
|
refused: Option<StreamId>,
|
||||||
@@ -44,6 +44,13 @@ pub(super) struct Recv<B, P>
|
|||||||
_p: PhantomData<(B)>,
|
_p: PhantomData<(B)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) enum Event<T> {
|
||||||
|
Headers(T),
|
||||||
|
Data(Bytes),
|
||||||
|
Trailers(::HeaderMap),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct Indices {
|
struct Indices {
|
||||||
head: store::Key,
|
head: store::Key,
|
||||||
@@ -110,44 +117,13 @@ impl<B, P> Recv<B, P>
|
|||||||
Ok(Some(id))
|
Ok(Some(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_request(&mut self, stream: &mut store::Ptr<B, P>)
|
|
||||||
-> Result<Request<()>, ConnectionError>
|
|
||||||
{
|
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
|
||||||
Some(Frame::Headers(frame)) => {
|
|
||||||
// TODO: This error should probably be caught on receipt of the
|
|
||||||
// frame vs. now.
|
|
||||||
Ok(server::Peer::convert_poll_message(frame)?)
|
|
||||||
}
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_response(&mut self, stream: &mut store::Ptr<B, P>)
|
|
||||||
-> Poll<Response<()>, ConnectionError> {
|
|
||||||
// If the buffer is not empty, then the first frame must be a HEADERS
|
|
||||||
// frame or the user violated the contract.
|
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
|
||||||
Some(Frame::Headers(v)) => {
|
|
||||||
// TODO: This error should probably be caught on receipt of the
|
|
||||||
// frame vs. now.
|
|
||||||
Ok(client::Peer::convert_poll_message(v)?.into())
|
|
||||||
}
|
|
||||||
Some(_) => unimplemented!(),
|
|
||||||
None => {
|
|
||||||
stream.state.ensure_recv_open()?;
|
|
||||||
|
|
||||||
stream.recv_task = Some(task::current());
|
|
||||||
Ok(Async::NotReady)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transition the stream state based on receiving headers
|
/// Transition the stream state based on receiving headers
|
||||||
|
///
|
||||||
|
/// The caller ensures that the frame represents headers and not trailers.
|
||||||
pub fn recv_headers(&mut self,
|
pub fn recv_headers(&mut self,
|
||||||
frame: frame::Headers,
|
frame: frame::Headers,
|
||||||
stream: &mut store::Ptr<B, P>)
|
stream: &mut store::Ptr<B, P>)
|
||||||
-> Result<(), ConnectionError>
|
-> Result<(), ProtoError>
|
||||||
{
|
{
|
||||||
trace!("opening stream; init_window={}", self.init_window_sz);
|
trace!("opening stream; init_window={}", self.init_window_sz);
|
||||||
let is_initial = stream.state.recv_open(frame.is_end_stream())?;
|
let is_initial = stream.state.recv_open(frame.is_end_stream())?;
|
||||||
@@ -161,7 +137,7 @@ impl<B, P> Recv<B, P>
|
|||||||
self.next_stream_id = frame.stream_id();
|
self.next_stream_id = frame.stream_id();
|
||||||
self.next_stream_id.increment();
|
self.next_stream_id.increment();
|
||||||
} else {
|
} else {
|
||||||
return Err(ProtocolError.into());
|
return Err(ProtoError::Connection(ProtocolError));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: be smarter about this logic
|
// TODO: be smarter about this logic
|
||||||
@@ -173,8 +149,10 @@ impl<B, P> Recv<B, P>
|
|||||||
self.inc_num_streams();
|
self.inc_num_streams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let message = P::convert_poll_message(frame)?;
|
||||||
|
|
||||||
// Push the frame onto the stream's recv buffer
|
// Push the frame onto the stream's recv buffer
|
||||||
stream.pending_recv.push_back(&mut self.buffer, frame.into());
|
stream.pending_recv.push_back(&mut self.buffer, Event::Headers(message));
|
||||||
stream.notify_recv();
|
stream.notify_recv();
|
||||||
|
|
||||||
// Only servers can receive a headers frame that initiates the stream.
|
// Only servers can receive a headers frame that initiates the stream.
|
||||||
@@ -190,13 +168,15 @@ impl<B, P> Recv<B, P>
|
|||||||
pub fn recv_trailers(&mut self,
|
pub fn recv_trailers(&mut self,
|
||||||
frame: frame::Headers,
|
frame: frame::Headers,
|
||||||
stream: &mut store::Ptr<B, P>)
|
stream: &mut store::Ptr<B, P>)
|
||||||
-> Result<(), ConnectionError>
|
-> Result<(), ProtoError>
|
||||||
{
|
{
|
||||||
// Transition the state
|
// Transition the state
|
||||||
stream.state.recv_close()?;
|
stream.state.recv_close()?;
|
||||||
|
|
||||||
|
let trailers = frame.into_fields();
|
||||||
|
|
||||||
// Push the frame onto the stream's recv buffer
|
// Push the frame onto the stream's recv buffer
|
||||||
stream.pending_recv.push_back(&mut self.buffer, frame.into());
|
stream.pending_recv.push_back(&mut self.buffer, Event::Trailers(trailers));
|
||||||
stream.notify_recv();
|
stream.notify_recv();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -236,7 +216,7 @@ impl<B, P> Recv<B, P>
|
|||||||
}
|
}
|
||||||
|
|
||||||
stream.pending_recv.peek_front(&self.buffer)
|
stream.pending_recv.peek_front(&self.buffer)
|
||||||
.map(|frame| !frame.is_data())
|
.map(|event| !event.is_data())
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,11 +258,15 @@ impl<B, P> Recv<B, P>
|
|||||||
stream.in_flight_recv_data += sz;
|
stream.in_flight_recv_data += sz;
|
||||||
|
|
||||||
if frame.is_end_stream() {
|
if frame.is_end_stream() {
|
||||||
try!(stream.state.recv_close());
|
if stream.state.recv_close().is_err() {
|
||||||
|
return Err(ProtocolError.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let event = Event::Data(frame.into_payload());
|
||||||
|
|
||||||
// Push the frame onto the recv buffer
|
// Push the frame onto the recv buffer
|
||||||
stream.pending_recv.push_back(&mut self.buffer, frame.into());
|
stream.pending_recv.push_back(&mut self.buffer, event);
|
||||||
stream.notify_recv();
|
stream.notify_recv();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -530,12 +514,12 @@ impl<B, P> Recv<B, P>
|
|||||||
-> Poll<Option<Bytes>, ConnectionError>
|
-> Poll<Option<Bytes>, ConnectionError>
|
||||||
{
|
{
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
Some(Frame::Data(frame)) => {
|
Some(Event::Data(payload)) => {
|
||||||
Ok(Some(frame.into_payload()).into())
|
Ok(Some(payload).into())
|
||||||
}
|
}
|
||||||
Some(frame) => {
|
Some(event) => {
|
||||||
// Frame is trailer
|
// Frame is trailer
|
||||||
stream.pending_recv.push_front(&mut self.buffer, frame);
|
stream.pending_recv.push_front(&mut self.buffer, event);
|
||||||
|
|
||||||
// No more data frames
|
// No more data frames
|
||||||
Ok(None.into())
|
Ok(None.into())
|
||||||
@@ -557,8 +541,8 @@ impl<B, P> Recv<B, P>
|
|||||||
-> Poll<Option<HeaderMap>, ConnectionError>
|
-> Poll<Option<HeaderMap>, ConnectionError>
|
||||||
{
|
{
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
Some(Frame::Headers(frame)) => {
|
Some(Event::Trailers(trailers)) => {
|
||||||
Ok(Some(frame.into_fields()).into())
|
Ok(Some(trailers).into())
|
||||||
}
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// TODO: This is a user error. `poll_trailers` was called before
|
// TODO: This is a user error. `poll_trailers` was called before
|
||||||
@@ -583,3 +567,55 @@ impl<B, P> Recv<B, P>
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B> Recv<B, server::Peer>
|
||||||
|
where B: Buf,
|
||||||
|
{
|
||||||
|
/// TODO: Should this fn return `Result`?
|
||||||
|
pub fn take_request(&mut self, stream: &mut store::Ptr<B, server::Peer>)
|
||||||
|
-> Result<Request<()>, ConnectionError>
|
||||||
|
{
|
||||||
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
|
Some(Event::Headers(request)) => Ok(request),
|
||||||
|
/*
|
||||||
|
// TODO: This error should probably be caught on receipt of the
|
||||||
|
// frame vs. now.
|
||||||
|
Ok(server::Peer::convert_poll_message(frame)?)
|
||||||
|
*/
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> Recv<B, client::Peer>
|
||||||
|
where B: Buf,
|
||||||
|
{
|
||||||
|
pub fn poll_response(&mut self, stream: &mut store::Ptr<B, client::Peer>)
|
||||||
|
-> Poll<Response<()>, ConnectionError> {
|
||||||
|
// If the buffer is not empty, then the first frame must be a HEADERS
|
||||||
|
// frame or the user violated the contract.
|
||||||
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
|
Some(Event::Headers(response)) => {
|
||||||
|
Ok(response.into())
|
||||||
|
}
|
||||||
|
Some(_) => unimplemented!(),
|
||||||
|
None => {
|
||||||
|
stream.state.ensure_recv_open()?;
|
||||||
|
|
||||||
|
stream.recv_task = Some(task::current());
|
||||||
|
Ok(Async::NotReady)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== impl Event =====
|
||||||
|
|
||||||
|
impl<T> Event<T> {
|
||||||
|
fn is_data(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Event::Data(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
|
use proto::ProtoError;
|
||||||
use error::Reason;
|
use error::Reason;
|
||||||
use error::Reason::*;
|
use error::Reason::*;
|
||||||
use error::User::*;
|
use error::User::*;
|
||||||
@@ -125,7 +126,7 @@ impl State {
|
|||||||
/// frame is received.
|
/// frame is received.
|
||||||
///
|
///
|
||||||
/// Returns true if this transitions the state to Open
|
/// Returns true if this transitions the state to Open
|
||||||
pub fn recv_open(&mut self, eos: bool) -> Result<bool, ConnectionError> {
|
pub fn recv_open(&mut self, eos: bool) -> Result<bool, ProtoError> {
|
||||||
let remote = Peer::Streaming;
|
let remote = Peer::Streaming;
|
||||||
let mut initial = false;
|
let mut initial = false;
|
||||||
|
|
||||||
@@ -173,7 +174,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// All other transitions result in a protocol error
|
// All other transitions result in a protocol error
|
||||||
return Err(ProtocolError.into());
|
return Err(ProtoError::Connection(ProtocolError));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,7 +193,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates that the remote side will not send more data to the local.
|
/// Indicates that the remote side will not send more data to the local.
|
||||||
pub fn recv_close(&mut self) -> Result<(), ConnectionError> {
|
pub fn recv_close(&mut self) -> Result<(), ProtoError> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open { local, .. } => {
|
Open { local, .. } => {
|
||||||
// The remote side will continue to receive data.
|
// The remote side will continue to receive data.
|
||||||
@@ -205,7 +206,7 @@ impl State {
|
|||||||
self.inner = Closed(None);
|
self.inner = Closed(None);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(ProtocolError.into()),
|
_ => Err(ProtoError::Connection(ProtocolError)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub(super) struct Stream<B, P>
|
|||||||
pub is_pending_window_update: bool,
|
pub is_pending_window_update: bool,
|
||||||
|
|
||||||
/// Frames pending for this stream to read
|
/// Frames pending for this stream to read
|
||||||
pub pending_recv: buffer::Deque<Frame<Bytes>>,
|
pub pending_recv: buffer::Deque<recv::Event<P::Poll>>,
|
||||||
|
|
||||||
/// Task tracking receiving frames
|
/// Task tracking receiving frames
|
||||||
pub recv_task: Option<task::Task>,
|
pub recv_task: Option<task::Task>,
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl<B, P> Streams<B, P>
|
|||||||
let stream = me.store.resolve(key);
|
let stream = me.store.resolve(key);
|
||||||
|
|
||||||
me.actions.transition(stream, |actions, stream| {
|
me.actions.transition(stream, |actions, stream| {
|
||||||
if stream.state.is_recv_headers() {
|
let res = if stream.state.is_recv_headers() {
|
||||||
actions.recv.recv_headers(frame, stream)
|
actions.recv.recv_headers(frame, stream)
|
||||||
} else {
|
} else {
|
||||||
if !frame.is_end_stream() {
|
if !frame.is_end_stream() {
|
||||||
@@ -101,6 +101,17 @@ impl<B, P> Streams<B, P>
|
|||||||
}
|
}
|
||||||
|
|
||||||
actions.recv.recv_trailers(frame, stream)
|
actions.recv.recv_trailers(frame, stream)
|
||||||
|
};
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
Err(ProtoError::Connection(reason)) => Err(reason.into()),
|
||||||
|
Err(ProtoError::Stream { reason, .. }) => {
|
||||||
|
// Reset the stream.
|
||||||
|
actions.send.send_reset(reason, stream, &mut actions.task);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(ProtoError::Io(_)) => unreachable!(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -381,21 +392,6 @@ impl<B, P> StreamRef<B, P>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called by the server after the stream is accepted. Given that clients
|
|
||||||
/// initialize streams by sending HEADERS, the request will always be
|
|
||||||
/// available.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This function panics if the request isn't present.
|
|
||||||
pub fn take_request(&self) -> Result<Request<()>, ConnectionError> {
|
|
||||||
let mut me = self.inner.lock().unwrap();
|
|
||||||
let me = &mut *me;
|
|
||||||
|
|
||||||
let mut stream = me.store.resolve(self.key);
|
|
||||||
me.actions.recv.take_request(&mut stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_reset(&mut self, reason: Reason) {
|
pub fn send_reset(&mut self, reason: Reason) {
|
||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
@@ -431,15 +427,6 @@ impl<B, P> StreamRef<B, P>
|
|||||||
me.actions.recv.body_is_empty(&stream)
|
me.actions.recv.body_is_empty(&stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_response(&mut self) -> Poll<Response<()>, ConnectionError> {
|
|
||||||
let mut me = self.inner.lock().unwrap();
|
|
||||||
let me = &mut *me;
|
|
||||||
|
|
||||||
let mut stream = me.store.resolve(self.key);
|
|
||||||
|
|
||||||
me.actions.recv.poll_response(&mut stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_data(&mut self) -> Poll<Option<Bytes>, ConnectionError> {
|
pub fn poll_data(&mut self) -> Poll<Option<Bytes>, ConnectionError> {
|
||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
@@ -503,6 +490,38 @@ impl<B, P> StreamRef<B, P>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B> StreamRef<B, server::Peer>
|
||||||
|
where B: Buf,
|
||||||
|
{
|
||||||
|
/// Called by the server after the stream is accepted. Given that clients
|
||||||
|
/// initialize streams by sending HEADERS, the request will always be
|
||||||
|
/// available.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function panics if the request isn't present.
|
||||||
|
pub fn take_request(&self) -> Result<Request<()>, ConnectionError> {
|
||||||
|
let mut me = self.inner.lock().unwrap();
|
||||||
|
let me = &mut *me;
|
||||||
|
|
||||||
|
let mut stream = me.store.resolve(self.key);
|
||||||
|
me.actions.recv.take_request(&mut stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> StreamRef<B, client::Peer>
|
||||||
|
where B: Buf,
|
||||||
|
{
|
||||||
|
pub fn poll_response(&mut self) -> Poll<Response<()>, ConnectionError> {
|
||||||
|
let mut me = self.inner.lock().unwrap();
|
||||||
|
let me = &mut *me;
|
||||||
|
|
||||||
|
let mut stream = me.store.resolve(self.key);
|
||||||
|
|
||||||
|
me.actions.recv.poll_response(&mut stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B, P> Clone for StreamRef<B, P>
|
impl<B, P> Clone for StreamRef<B, P>
|
||||||
where P: Peer,
|
where P: Peer,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use {HeaderMap, ConnectionError};
|
use {HeaderMap, ConnectionError};
|
||||||
use frame::{self, StreamId};
|
use frame::{self, StreamId};
|
||||||
use proto::{self, Connection, WindowSize};
|
use proto::{self, Connection, WindowSize, ProtoError};
|
||||||
use error::Reason;
|
use error::Reason;
|
||||||
use error::Reason::*;
|
use error::Reason::*;
|
||||||
|
|
||||||
@@ -401,8 +401,78 @@ impl proto::Peer for Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn convert_poll_message(headers: frame::Headers)
|
fn convert_poll_message(headers: frame::Headers)
|
||||||
-> Result<Self::Poll, ConnectionError>
|
-> Result<Self::Poll, ProtoError>
|
||||||
{
|
{
|
||||||
headers.into_request()
|
use http::{version, uri};
|
||||||
|
|
||||||
|
let mut b = Request::builder();
|
||||||
|
|
||||||
|
let stream_id = headers.stream_id();
|
||||||
|
let (pseudo, fields) = headers.into_parts();
|
||||||
|
|
||||||
|
macro_rules! malformed {
|
||||||
|
() => {
|
||||||
|
return Err(ProtoError::Stream {
|
||||||
|
id: stream_id,
|
||||||
|
reason: ProtocolError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
b.version(version::HTTP_2);
|
||||||
|
|
||||||
|
if let Some(method) = pseudo.method {
|
||||||
|
b.method(method);
|
||||||
|
} else {
|
||||||
|
malformed!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specifying :status for a request is a protocol error
|
||||||
|
if pseudo.status.is_some() {
|
||||||
|
return Err(ProtoError::Connection(ProtocolError));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the URI
|
||||||
|
let mut parts = uri::Parts::default();
|
||||||
|
|
||||||
|
if let Some(scheme) = pseudo.scheme {
|
||||||
|
// TODO: Don't unwrap
|
||||||
|
parts.scheme = Some(uri::Scheme::from_shared(scheme.into_inner()).unwrap());
|
||||||
|
} else {
|
||||||
|
malformed!();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(authority) = pseudo.authority {
|
||||||
|
// TODO: Don't unwrap
|
||||||
|
parts.authority = Some(uri::Authority::from_shared(authority.into_inner()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = pseudo.path {
|
||||||
|
// This cannot be empty
|
||||||
|
if path.is_empty() {
|
||||||
|
malformed!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Don't unwrap
|
||||||
|
parts.path_and_query = Some(uri::PathAndQuery::from_shared(path.into_inner()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
b.uri(parts);
|
||||||
|
|
||||||
|
let mut request = match b.body(()) {
|
||||||
|
Ok(request) => request,
|
||||||
|
Err(_) => {
|
||||||
|
// TODO: Should there be more specialized handling for different
|
||||||
|
// kinds of errors
|
||||||
|
return Err(ProtoError::Stream {
|
||||||
|
id: stream_id,
|
||||||
|
reason: ProtocolError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
*request.headers_mut() = fields;
|
||||||
|
|
||||||
|
Ok(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user