chore: cargo fmt, clippy
This commit is contained in:
committed by
Sean McArthur
parent
e72d6dc189
commit
f46840f3fa
@@ -6,8 +6,8 @@ use bytes::*;
|
|||||||
use futures::*;
|
use futures::*;
|
||||||
use http::{Response, StatusCode};
|
use http::{Response, StatusCode};
|
||||||
|
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() -> Result<(), Box<dyn Error>> {
|
pub async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
@@ -21,7 +21,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
while let Some(socket) = incoming.next().await {
|
while let Some(socket) = incoming.next().await {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = handle(socket).await {
|
if let Err(e) = handle(socket).await {
|
||||||
println!(" -> err={:?}", e);
|
println!(" -> err={:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,6 @@ async fn handle(socket: io::Result<TcpStream>) -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! ~~~~~~~~~~~");
|
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! ~~~~~~~~~~~");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
//! pub async fn main() -> Result<(), Box<dyn Error>> {
|
//! pub async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
//! let addr = "127.0.0.1:5928".parse().unwrap();
|
//! let addr = "127.0.0.1:5928".parse().unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Establish TCP connection to the server.
|
//! // Establish TCP connection to the server.
|
||||||
//! let tcp = TcpStream::connect(&addr).await?;
|
//! let tcp = TcpStream::connect(&addr).await?;
|
||||||
//! let (h2, connection) = client::handshake(tcp).await?;
|
//! let (h2, connection) = client::handshake(tcp).await?;
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
//! // Send the request. The second tuple item allows the caller
|
//! // Send the request. The second tuple item allows the caller
|
||||||
//! // to stream a request body.
|
//! // to stream a request body.
|
||||||
//! let (response, _) = h2.send_request(request, true).unwrap();
|
//! let (response, _) = h2.send_request(request, true).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let (head, mut body) = response.await?.into_parts();
|
//! let (head, mut body) = response.await?.into_parts();
|
||||||
//!
|
//!
|
||||||
//! println!("Received response: {:?}", head);
|
//! println!("Received response: {:?}", head);
|
||||||
@@ -585,7 +585,7 @@ where
|
|||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match &mut self.inner {
|
match &mut self.inner {
|
||||||
Some(send_request) => {
|
Some(send_request) => {
|
||||||
let _ = ready!(send_request.poll_ready(cx))?;
|
ready!(send_request.poll_ready(cx))?;
|
||||||
}
|
}
|
||||||
None => panic!("called `poll` after future completed"),
|
None => panic!("called `poll` after future completed"),
|
||||||
}
|
}
|
||||||
@@ -1269,7 +1269,7 @@ impl Future for ResponseFuture {
|
|||||||
let (parts, _) = ready!(self.inner.poll_response(cx))?.into_parts();
|
let (parts, _) = ready!(self.inner.poll_response(cx))?.into_parts();
|
||||||
let body = RecvStream::new(ReleaseCapacity::new(self.inner.clone()));
|
let body = RecvStream::new(ReleaseCapacity::new(self.inner.clone()));
|
||||||
|
|
||||||
Poll::Ready(Ok(Response::from_parts(parts, body).into()))
|
Poll::Ready(Ok(Response::from_parts(parts, body)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,9 +76,7 @@ impl error::Error for RecvError {
|
|||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Connection(ref reason) => reason.description(),
|
Connection(ref reason) => reason.description(),
|
||||||
Stream {
|
Stream { ref reason, .. } => reason.description(),
|
||||||
ref reason, ..
|
|
||||||
} => reason.description(),
|
|
||||||
Io(ref e) => e.description(),
|
Io(ref e) => e.description(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ use std::io;
|
|||||||
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio_codec::{LengthDelimitedCodec, LengthDelimitedCodecError};
|
|
||||||
use tokio_codec::FramedRead as InnerFramedRead;
|
use tokio_codec::FramedRead as InnerFramedRead;
|
||||||
|
use tokio_codec::{LengthDelimitedCodec, LengthDelimitedCodecError};
|
||||||
use tokio_io::AsyncRead;
|
use tokio_io::AsyncRead;
|
||||||
|
|
||||||
// 16 MB "sane default" taken from golang http2
|
// 16 MB "sane default" taken from golang http2
|
||||||
@@ -52,7 +52,7 @@ enum Continuable {
|
|||||||
impl<T> FramedRead<T> {
|
impl<T> FramedRead<T> {
|
||||||
pub fn new(inner: InnerFramedRead<T, LengthDelimitedCodec>) -> FramedRead<T> {
|
pub fn new(inner: InnerFramedRead<T, LengthDelimitedCodec>) -> FramedRead<T> {
|
||||||
FramedRead {
|
FramedRead {
|
||||||
inner: inner,
|
inner,
|
||||||
hpack: hpack::Decoder::new(DEFAULT_SETTINGS_HEADER_TABLE_SIZE),
|
hpack: hpack::Decoder::new(DEFAULT_SETTINGS_HEADER_TABLE_SIZE),
|
||||||
max_header_list_size: DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE,
|
max_header_list_size: DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE,
|
||||||
partial: None,
|
partial: None,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use bytes::{Buf, BufMut, Bytes};
|
|
||||||
use crate::frame::{util, Error, Frame, Head, Kind, StreamId};
|
use crate::frame::{util, Error, Frame, Head, Kind, StreamId};
|
||||||
|
use bytes::{Buf, BufMut, Bytes};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ impl<T> Data<T> {
|
|||||||
assert!(!stream_id.is_zero());
|
assert!(!stream_id.is_zero());
|
||||||
|
|
||||||
Data {
|
Data {
|
||||||
stream_id: stream_id,
|
stream_id,
|
||||||
data: payload,
|
data: payload,
|
||||||
flags: DataFlags::default(),
|
flags: DataFlags::default(),
|
||||||
pad_len: None,
|
pad_len: None,
|
||||||
@@ -135,8 +135,8 @@ impl Data<Bytes> {
|
|||||||
Ok(Data {
|
Ok(Data {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
data: payload,
|
data: payload,
|
||||||
flags: flags,
|
flags,
|
||||||
pad_len: pad_len,
|
pad_len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
|
use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
|
||||||
|
|
||||||
use bytes::{BufMut};
|
use bytes::BufMut;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct GoAway {
|
pub struct GoAway {
|
||||||
@@ -33,7 +33,7 @@ impl GoAway {
|
|||||||
let error_code = unpack_octets_4!(payload, 4, u32);
|
let error_code = unpack_octets_4!(payload, 4, u32);
|
||||||
|
|
||||||
Ok(GoAway {
|
Ok(GoAway {
|
||||||
last_stream_id: last_stream_id,
|
last_stream_id,
|
||||||
error_code: error_code.into(),
|
error_code: error_code.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::StreamId;
|
use super::StreamId;
|
||||||
|
|
||||||
use bytes::{BufMut};
|
use bytes::BufMut;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Head {
|
pub struct Head {
|
||||||
@@ -30,9 +30,9 @@ pub enum Kind {
|
|||||||
impl Head {
|
impl Head {
|
||||||
pub fn new(kind: Kind, flag: u8, stream_id: StreamId) -> Head {
|
pub fn new(kind: Kind, flag: u8, stream_id: StreamId) -> Head {
|
||||||
Head {
|
Head {
|
||||||
kind: kind,
|
kind,
|
||||||
flag: flag,
|
flag,
|
||||||
stream_id: stream_id,
|
stream_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use super::{util, StreamDependency, StreamId};
|
|||||||
use crate::frame::{Error, Frame, Head, Kind};
|
use crate::frame::{Error, Frame, Head, Kind};
|
||||||
use crate::hpack;
|
use crate::hpack;
|
||||||
|
|
||||||
use http::{uri, HeaderMap, Method, StatusCode, Uri};
|
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
use http::{uri, HeaderMap, Method, StatusCode, Uri};
|
||||||
|
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use string::String;
|
use string::String;
|
||||||
@@ -118,12 +118,12 @@ impl Headers {
|
|||||||
/// Create a new HEADERS frame
|
/// Create a new HEADERS frame
|
||||||
pub fn new(stream_id: StreamId, pseudo: Pseudo, fields: HeaderMap) -> Self {
|
pub fn new(stream_id: StreamId, pseudo: Pseudo, fields: HeaderMap) -> Self {
|
||||||
Headers {
|
Headers {
|
||||||
stream_id: stream_id,
|
stream_id,
|
||||||
stream_dep: None,
|
stream_dep: None,
|
||||||
header_block: HeaderBlock {
|
header_block: HeaderBlock {
|
||||||
fields: fields,
|
fields,
|
||||||
is_over_size: false,
|
is_over_size: false,
|
||||||
pseudo: pseudo,
|
pseudo,
|
||||||
},
|
},
|
||||||
flags: HeadersFlag::default(),
|
flags: HeadersFlag::default(),
|
||||||
}
|
}
|
||||||
@@ -137,11 +137,11 @@ impl Headers {
|
|||||||
stream_id,
|
stream_id,
|
||||||
stream_dep: None,
|
stream_dep: None,
|
||||||
header_block: HeaderBlock {
|
header_block: HeaderBlock {
|
||||||
fields: fields,
|
fields,
|
||||||
is_over_size: false,
|
is_over_size: false,
|
||||||
pseudo: Pseudo::default(),
|
pseudo: Pseudo::default(),
|
||||||
},
|
},
|
||||||
flags: flags,
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ impl Headers {
|
|||||||
|
|
||||||
// Read the padding length
|
// Read the padding length
|
||||||
if flags.is_padded() {
|
if flags.is_padded() {
|
||||||
if src.len() < 1 {
|
if src.is_empty() {
|
||||||
return Err(Error::MalformedMessage);
|
return Err(Error::MalformedMessage);
|
||||||
}
|
}
|
||||||
pad = src[0] as usize;
|
pad = src[0] as usize;
|
||||||
@@ -195,19 +195,24 @@ impl Headers {
|
|||||||
|
|
||||||
let headers = Headers {
|
let headers = Headers {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
stream_dep: stream_dep,
|
stream_dep,
|
||||||
header_block: HeaderBlock {
|
header_block: HeaderBlock {
|
||||||
fields: HeaderMap::new(),
|
fields: HeaderMap::new(),
|
||||||
is_over_size: false,
|
is_over_size: false,
|
||||||
pseudo: Pseudo::default(),
|
pseudo: Pseudo::default(),
|
||||||
},
|
},
|
||||||
flags: flags,
|
flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((headers, src))
|
Ok((headers, src))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_hpack(&mut self, src: &mut BytesMut, max_header_list_size: usize, decoder: &mut hpack::Decoder) -> Result<(), Error> {
|
pub fn load_hpack(
|
||||||
|
&mut self,
|
||||||
|
src: &mut BytesMut,
|
||||||
|
max_header_list_size: usize,
|
||||||
|
decoder: &mut hpack::Decoder,
|
||||||
|
) -> Result<(), Error> {
|
||||||
self.header_block.load(src, max_header_list_size, decoder)
|
self.header_block.load(src, max_header_list_size, decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,9 +268,9 @@ impl Headers {
|
|||||||
// Get the HEADERS frame head
|
// Get the HEADERS frame head
|
||||||
let head = self.head();
|
let head = self.head();
|
||||||
|
|
||||||
self.header_block.into_encoding()
|
self.header_block
|
||||||
.encode(&head, encoder, dst, |_| {
|
.into_encoding()
|
||||||
})
|
.encode(&head, encoder, dst, |_| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn head(&self) -> Head {
|
fn head(&self) -> Head {
|
||||||
@@ -307,7 +312,7 @@ impl PushPromise {
|
|||||||
|
|
||||||
// Read the padding length
|
// Read the padding length
|
||||||
if flags.is_padded() {
|
if flags.is_padded() {
|
||||||
if src.len() < 1 {
|
if src.is_empty() {
|
||||||
return Err(Error::MalformedMessage);
|
return Err(Error::MalformedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,19 +341,24 @@ impl PushPromise {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let frame = PushPromise {
|
let frame = PushPromise {
|
||||||
flags: flags,
|
flags,
|
||||||
header_block: HeaderBlock {
|
header_block: HeaderBlock {
|
||||||
fields: HeaderMap::new(),
|
fields: HeaderMap::new(),
|
||||||
is_over_size: false,
|
is_over_size: false,
|
||||||
pseudo: Pseudo::default(),
|
pseudo: Pseudo::default(),
|
||||||
},
|
},
|
||||||
promised_id: promised_id,
|
promised_id,
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
};
|
};
|
||||||
Ok((frame, src))
|
Ok((frame, src))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_hpack(&mut self, src: &mut BytesMut, max_header_list_size: usize, decoder: &mut hpack::Decoder) -> Result<(), Error> {
|
pub fn load_hpack(
|
||||||
|
&mut self,
|
||||||
|
src: &mut BytesMut,
|
||||||
|
max_header_list_size: usize,
|
||||||
|
decoder: &mut hpack::Decoder,
|
||||||
|
) -> Result<(), Error> {
|
||||||
self.header_block.load(src, max_header_list_size, decoder)
|
self.header_block.load(src, max_header_list_size, decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +391,8 @@ impl PushPromise {
|
|||||||
let head = self.head();
|
let head = self.head();
|
||||||
let promised_id = self.promised_id;
|
let promised_id = self.promised_id;
|
||||||
|
|
||||||
self.header_block.into_encoding()
|
self.header_block
|
||||||
|
.into_encoding()
|
||||||
.encode(&head, encoder, dst, |dst| {
|
.encode(&head, encoder, dst, |dst| {
|
||||||
dst.put_u32_be(promised_id.into());
|
dst.put_u32_be(promised_id.into());
|
||||||
})
|
})
|
||||||
@@ -456,9 +467,7 @@ impl Continuation {
|
|||||||
// Get the CONTINUATION frame head
|
// Get the CONTINUATION frame head
|
||||||
let head = self.head();
|
let head = self.head();
|
||||||
|
|
||||||
self.header_block
|
self.header_block.encode(&head, encoder, dst, |_| {})
|
||||||
.encode(&head, encoder, dst, |_| {
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +480,7 @@ impl Pseudo {
|
|||||||
let mut path = parts
|
let mut path = parts
|
||||||
.path_and_query
|
.path_and_query
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.unwrap_or_else(|| Bytes::new());
|
.unwrap_or_else(Bytes::new);
|
||||||
|
|
||||||
if path.is_empty() && method != Method::OPTIONS {
|
if path.is_empty() && method != Method::OPTIONS {
|
||||||
path = Bytes::from_static(b"/");
|
path = Bytes::from_static(b"/");
|
||||||
@@ -527,13 +536,15 @@ fn to_string(src: Bytes) -> String<Bytes> {
|
|||||||
// ===== impl EncodingHeaderBlock =====
|
// ===== impl EncodingHeaderBlock =====
|
||||||
|
|
||||||
impl EncodingHeaderBlock {
|
impl EncodingHeaderBlock {
|
||||||
fn encode<F>(mut self,
|
fn encode<F>(
|
||||||
head: &Head,
|
mut self,
|
||||||
encoder: &mut hpack::Encoder,
|
head: &Head,
|
||||||
dst: &mut BytesMut,
|
encoder: &mut hpack::Encoder,
|
||||||
f: F)
|
dst: &mut BytesMut,
|
||||||
-> Option<Continuation>
|
f: F,
|
||||||
where F: FnOnce(&mut BytesMut),
|
) -> Option<Continuation>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut BytesMut),
|
||||||
{
|
{
|
||||||
let head_pos = dst.len();
|
let head_pos = dst.len();
|
||||||
|
|
||||||
@@ -610,12 +621,9 @@ impl Iterator for Iter {
|
|||||||
|
|
||||||
self.pseudo = None;
|
self.pseudo = None;
|
||||||
|
|
||||||
self.fields.next().map(|(name, value)| {
|
self.fields
|
||||||
Field {
|
.next()
|
||||||
name: name,
|
.map(|(name, value)| Field { name, value })
|
||||||
value: value,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,9 +735,13 @@ impl fmt::Debug for PushPromiseFlag {
|
|||||||
|
|
||||||
// ===== HeaderBlock =====
|
// ===== HeaderBlock =====
|
||||||
|
|
||||||
|
|
||||||
impl HeaderBlock {
|
impl HeaderBlock {
|
||||||
fn load(&mut self, src: &mut BytesMut, max_header_list_size: usize, decoder: &mut hpack::Decoder) -> Result<(), Error> {
|
fn load(
|
||||||
|
&mut self,
|
||||||
|
src: &mut BytesMut,
|
||||||
|
max_header_list_size: usize,
|
||||||
|
decoder: &mut hpack::Decoder,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let mut reg = !self.fields.is_empty();
|
let mut reg = !self.fields.is_empty();
|
||||||
let mut malformed = false;
|
let mut malformed = false;
|
||||||
let mut headers_size = self.calculate_header_list_size();
|
let mut headers_size = self.calculate_header_list_size();
|
||||||
@@ -744,7 +756,8 @@ impl HeaderBlock {
|
|||||||
malformed = true;
|
malformed = true;
|
||||||
} else {
|
} else {
|
||||||
let __val = $val;
|
let __val = $val;
|
||||||
headers_size += decoded_header_size(stringify!($ident).len() + 1, __val.as_str().len());
|
headers_size +=
|
||||||
|
decoded_header_size(stringify!($ident).len() + 1, __val.as_str().len());
|
||||||
if headers_size < max_header_list_size {
|
if headers_size < max_header_list_size {
|
||||||
self.pseudo.$field = Some(__val);
|
self.pseudo.$field = Some(__val);
|
||||||
} else if !self.is_over_size {
|
} else if !self.is_over_size {
|
||||||
@@ -752,7 +765,7 @@ impl HeaderBlock {
|
|||||||
self.is_over_size = true;
|
self.is_over_size = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor = Cursor::new(src);
|
let mut cursor = Cursor::new(src);
|
||||||
@@ -765,10 +778,7 @@ impl HeaderBlock {
|
|||||||
use crate::hpack::Header::*;
|
use crate::hpack::Header::*;
|
||||||
|
|
||||||
match header {
|
match header {
|
||||||
Field {
|
Field { name, value } => {
|
||||||
name,
|
|
||||||
value,
|
|
||||||
} => {
|
|
||||||
// Connection level header fields are not supported and must
|
// Connection level header fields are not supported and must
|
||||||
// result in a protocol error.
|
// result in a protocol error.
|
||||||
|
|
||||||
@@ -794,7 +804,7 @@ impl HeaderBlock {
|
|||||||
self.is_over_size = true;
|
self.is_over_size = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Authority(v) => set_pseudo!(authority, v),
|
Authority(v) => set_pseudo!(authority, v),
|
||||||
Method(v) => set_pseudo!(method, v),
|
Method(v) => set_pseudo!(method, v),
|
||||||
Scheme(v) => set_pseudo!(scheme, v),
|
Scheme(v) => set_pseudo!(scheme, v),
|
||||||
@@ -810,7 +820,7 @@ impl HeaderBlock {
|
|||||||
|
|
||||||
if malformed {
|
if malformed {
|
||||||
log::trace!("malformed message");
|
log::trace!("malformed message");
|
||||||
return Err(Error::MalformedMessage.into());
|
return Err(Error::MalformedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -835,36 +845,38 @@ impl HeaderBlock {
|
|||||||
/// > overhead of 32 octets for each header field.
|
/// > overhead of 32 octets for each header field.
|
||||||
fn calculate_header_list_size(&self) -> usize {
|
fn calculate_header_list_size(&self) -> usize {
|
||||||
macro_rules! pseudo_size {
|
macro_rules! pseudo_size {
|
||||||
($name:ident) => ({
|
($name:ident) => {{
|
||||||
self.pseudo
|
self.pseudo
|
||||||
.$name
|
.$name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
|
.map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
});
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo_size!(method) +
|
pseudo_size!(method)
|
||||||
pseudo_size!(scheme) +
|
+ pseudo_size!(scheme)
|
||||||
pseudo_size!(status) +
|
+ pseudo_size!(status)
|
||||||
pseudo_size!(authority) +
|
+ pseudo_size!(authority)
|
||||||
pseudo_size!(path) +
|
+ pseudo_size!(path)
|
||||||
self.fields.iter()
|
+ self
|
||||||
.map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
|
.fields
|
||||||
.sum::<usize>()
|
.iter()
|
||||||
|
.map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
|
||||||
|
.sum::<usize>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all pseudos and headers to see if any individual pair
|
/// Iterate over all pseudos and headers to see if any individual pair
|
||||||
/// would be too large to encode.
|
/// would be too large to encode.
|
||||||
pub(crate) fn has_too_big_field(&self) -> bool {
|
pub(crate) fn has_too_big_field(&self) -> bool {
|
||||||
macro_rules! pseudo_size {
|
macro_rules! pseudo_size {
|
||||||
($name:ident) => ({
|
($name:ident) => {{
|
||||||
self.pseudo
|
self.pseudo
|
||||||
.$name
|
.$name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
|
.map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
});
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
if pseudo_size!(method) > MAX_HEADER_LENGTH {
|
if pseudo_size!(method) > MAX_HEADER_LENGTH {
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ use std::fmt;
|
|||||||
#[macro_escape]
|
#[macro_escape]
|
||||||
macro_rules! unpack_octets_4 {
|
macro_rules! unpack_octets_4 {
|
||||||
// TODO: Get rid of this macro
|
// TODO: Get rid of this macro
|
||||||
($buf:expr, $offset:expr, $tip:ty) => (
|
($buf:expr, $offset:expr, $tip:ty) => {
|
||||||
(($buf[$offset + 0] as $tip) << 24) |
|
(($buf[$offset + 0] as $tip) << 24)
|
||||||
(($buf[$offset + 1] as $tip) << 16) |
|
| (($buf[$offset + 1] as $tip) << 16)
|
||||||
(($buf[$offset + 2] as $tip) << 8) |
|
| (($buf[$offset + 2] as $tip) << 8)
|
||||||
(($buf[$offset + 3] as $tip) << 0)
|
| (($buf[$offset + 3] as $tip) << 0)
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
@@ -54,11 +54,8 @@ pub use self::window_update::WindowUpdate;
|
|||||||
// Re-export some constants
|
// Re-export some constants
|
||||||
|
|
||||||
pub use self::settings::{
|
pub use self::settings::{
|
||||||
DEFAULT_INITIAL_WINDOW_SIZE,
|
DEFAULT_INITIAL_WINDOW_SIZE, DEFAULT_MAX_FRAME_SIZE, DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
|
||||||
DEFAULT_MAX_FRAME_SIZE,
|
MAX_INITIAL_WINDOW_SIZE, MAX_MAX_FRAME_SIZE,
|
||||||
DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
|
|
||||||
MAX_INITIAL_WINDOW_SIZE,
|
|
||||||
MAX_MAX_FRAME_SIZE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type FrameSize = u32;
|
pub type FrameSize = u32;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use bytes::{Buf, BufMut, IntoBuf};
|
|
||||||
use crate::frame::{Error, Frame, Head, Kind, StreamId};
|
use crate::frame::{Error, Frame, Head, Kind, StreamId};
|
||||||
|
use bytes::{Buf, BufMut, IntoBuf};
|
||||||
|
|
||||||
const ACK_FLAG: u8 = 0x1;
|
const ACK_FLAG: u8 = 0x1;
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ const SHUTDOWN_PAYLOAD: Payload = [0x0b, 0x7b, 0xa2, 0xf0, 0x8b, 0x9b, 0xfe, 0x5
|
|||||||
const USER_PAYLOAD: Payload = [0x3b, 0x7c, 0xdb, 0x7a, 0x0b, 0x87, 0x16, 0xb4];
|
const USER_PAYLOAD: Payload = [0x3b, 0x7c, 0xdb, 0x7a, 0x0b, 0x87, 0x16, 0xb4];
|
||||||
|
|
||||||
impl Ping {
|
impl Ping {
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
pub const SHUTDOWN: Payload = SHUTDOWN_PAYLOAD;
|
pub const SHUTDOWN: Payload = SHUTDOWN_PAYLOAD;
|
||||||
|
|
||||||
@@ -38,10 +37,7 @@ impl Ping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn pong(payload: Payload) -> Ping {
|
pub fn pong(payload: Payload) -> Ping {
|
||||||
Ping {
|
Ping { ack: true, payload }
|
||||||
ack: true,
|
|
||||||
payload,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ack(&self) -> bool {
|
pub fn is_ack(&self) -> bool {
|
||||||
@@ -84,10 +80,7 @@ impl Ping {
|
|||||||
// endpoint MUST NOT respond to PING frames containing this flag.
|
// endpoint MUST NOT respond to PING frames containing this flag.
|
||||||
let ack = head.flag() & ACK_FLAG != 0;
|
let ack = head.flag() & ACK_FLAG != 0;
|
||||||
|
|
||||||
Ok(Ping {
|
Ok(Ping { ack, payload })
|
||||||
ack,
|
|
||||||
payload,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode<B: BufMut>(&self, dst: &mut B) {
|
pub fn encode<B: BufMut>(&self, dst: &mut B) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ impl Priority {
|
|||||||
|
|
||||||
Ok(Priority {
|
Ok(Priority {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
dependency: dependency,
|
dependency,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|
||||||
/// HTTP/2.0 error codes.
|
/// HTTP/2.0 error codes.
|
||||||
///
|
///
|
||||||
/// Error codes are used in `RST_STREAM` and `GOAWAY` frames to convey the
|
/// Error codes are used in `RST_STREAM` and `GOAWAY` frames to convey the
|
||||||
@@ -76,7 +75,7 @@ impl Reason {
|
|||||||
10 => {
|
10 => {
|
||||||
"connection established in response to a CONNECT request was reset or abnormally \
|
"connection established in response to a CONNECT request was reset or abnormally \
|
||||||
closed"
|
closed"
|
||||||
},
|
}
|
||||||
11 => "detected excessive load generating behavior",
|
11 => "detected excessive load generating behavior",
|
||||||
12 => "security properties do not meet minimum requirements",
|
12 => "security properties do not meet minimum requirements",
|
||||||
13 => "endpoint requires HTTP/1.1",
|
13 => "endpoint requires HTTP/1.1",
|
||||||
@@ -114,9 +113,7 @@ impl fmt::Debug for Reason {
|
|||||||
11 => "ENHANCE_YOUR_CALM",
|
11 => "ENHANCE_YOUR_CALM",
|
||||||
12 => "INADEQUATE_SECURITY",
|
12 => "INADEQUATE_SECURITY",
|
||||||
13 => "HTTP_1_1_REQUIRED",
|
13 => "HTTP_1_1_REQUIRED",
|
||||||
other => return f.debug_tuple("Reason")
|
other => return f.debug_tuple("Reason").field(&Hex(other)).finish(),
|
||||||
.field(&Hex(other))
|
|
||||||
.finish(),
|
|
||||||
};
|
};
|
||||||
f.write_str(name)
|
f.write_str(name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
|
use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
|
||||||
|
|
||||||
use bytes::{BufMut};
|
use bytes::BufMut;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct Reset {
|
pub struct Reset {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
|
||||||
use crate::frame::{util, Error, Frame, FrameSize, Head, Kind, StreamId};
|
use crate::frame::{util, Error, Frame, FrameSize, Head, Kind, StreamId};
|
||||||
|
use bytes::{BufMut, BytesMut};
|
||||||
|
|
||||||
#[derive(Clone, Default, Eq, PartialEq)]
|
#[derive(Clone, Default, Eq, PartialEq)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
@@ -121,7 +121,7 @@ impl Settings {
|
|||||||
|
|
||||||
if flag.is_ack() {
|
if flag.is_ack() {
|
||||||
// Ensure that the payload is empty
|
// Ensure that the payload is empty
|
||||||
if payload.len() > 0 {
|
if !payload.is_empty() {
|
||||||
return Err(Error::InvalidPayloadLength);
|
return Err(Error::InvalidPayloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,34 +142,36 @@ impl Settings {
|
|||||||
match Setting::load(raw) {
|
match Setting::load(raw) {
|
||||||
Some(HeaderTableSize(val)) => {
|
Some(HeaderTableSize(val)) => {
|
||||||
settings.header_table_size = Some(val);
|
settings.header_table_size = Some(val);
|
||||||
},
|
}
|
||||||
Some(EnablePush(val)) => match val {
|
Some(EnablePush(val)) => match val {
|
||||||
0 | 1 => {
|
0 | 1 => {
|
||||||
settings.enable_push = Some(val);
|
settings.enable_push = Some(val);
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::InvalidSettingValue);
|
return Err(Error::InvalidSettingValue);
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
Some(MaxConcurrentStreams(val)) => {
|
Some(MaxConcurrentStreams(val)) => {
|
||||||
settings.max_concurrent_streams = Some(val);
|
settings.max_concurrent_streams = Some(val);
|
||||||
},
|
}
|
||||||
Some(InitialWindowSize(val)) => if val as usize > MAX_INITIAL_WINDOW_SIZE {
|
Some(InitialWindowSize(val)) => {
|
||||||
return Err(Error::InvalidSettingValue);
|
if val as usize > MAX_INITIAL_WINDOW_SIZE {
|
||||||
} else {
|
return Err(Error::InvalidSettingValue);
|
||||||
settings.initial_window_size = Some(val);
|
} else {
|
||||||
},
|
settings.initial_window_size = Some(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(MaxFrameSize(val)) => {
|
Some(MaxFrameSize(val)) => {
|
||||||
if val < DEFAULT_MAX_FRAME_SIZE || val > MAX_MAX_FRAME_SIZE {
|
if val < DEFAULT_MAX_FRAME_SIZE || val > MAX_MAX_FRAME_SIZE {
|
||||||
return Err(Error::InvalidSettingValue);
|
return Err(Error::InvalidSettingValue);
|
||||||
} else {
|
} else {
|
||||||
settings.max_frame_size = Some(val);
|
settings.max_frame_size = Some(val);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Some(MaxHeaderListSize(val)) => {
|
Some(MaxHeaderListSize(val)) => {
|
||||||
settings.max_header_list_size = Some(val);
|
settings.max_header_list_size = Some(val);
|
||||||
},
|
}
|
||||||
None => {},
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +296,7 @@ impl Setting {
|
|||||||
///
|
///
|
||||||
/// If given a buffer shorter than 6 bytes, the function will panic.
|
/// If given a buffer shorter than 6 bytes, the function will panic.
|
||||||
fn load(raw: &[u8]) -> Option<Setting> {
|
fn load(raw: &[u8]) -> Option<Setting> {
|
||||||
let id: u16 = ((raw[0] as u16) << 8) | (raw[1] as u16);
|
let id: u16 = (u16::from(raw[0]) << 8) | u16::from(raw[1]);
|
||||||
let val: u32 = unpack_octets_4!(raw, 2, u32);
|
let val: u32 = unpack_octets_4!(raw, 2, u32);
|
||||||
|
|
||||||
Setting::from_id(id, val)
|
Setting::from_id(id, val)
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ pub fn strip_padding(payload: &mut Bytes) -> Result<u8, Error> {
|
|||||||
Ok(pad_len as u8)
|
Ok(pad_len as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn debug_flags<'a, 'f: 'a>(fmt: &'a mut fmt::Formatter<'f>, bits: u8) -> DebugFlags<'a, 'f> {
|
pub(super) fn debug_flags<'a, 'f: 'a>(
|
||||||
|
fmt: &'a mut fmt::Formatter<'f>,
|
||||||
|
bits: u8,
|
||||||
|
) -> DebugFlags<'a, 'f> {
|
||||||
let result = write!(fmt, "({:#x}", bits);
|
let result = write!(fmt, "({:#x}", bits);
|
||||||
DebugFlags {
|
DebugFlags {
|
||||||
fmt,
|
fmt,
|
||||||
@@ -71,8 +74,6 @@ impl<'a, 'f: 'a> DebugFlags<'a, 'f> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn finish(&mut self) -> fmt::Result {
|
pub(super) fn finish(&mut self) -> fmt::Result {
|
||||||
self.result.and_then(|()| {
|
self.result.and_then(|()| write!(self.fmt, ")"))
|
||||||
write!(self.fmt, ")")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::frame::{self, Error, Head, Kind, StreamId};
|
use crate::frame::{self, Error, Head, Kind, StreamId};
|
||||||
|
|
||||||
use bytes::{BufMut};
|
use bytes::BufMut;
|
||||||
|
|
||||||
const SIZE_INCREMENT_MASK: u32 = 1 << 31;
|
const SIZE_INCREMENT_MASK: u32 = 1 << 31;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ impl WindowUpdate {
|
|||||||
let size_increment = unpack_octets_4!(payload, 0, u32) & !SIZE_INCREMENT_MASK;
|
let size_increment = unpack_octets_4!(payload, 0, u32) & !SIZE_INCREMENT_MASK;
|
||||||
|
|
||||||
if size_increment == 0 {
|
if size_increment == 0 {
|
||||||
return Err(Error::InvalidWindowUpdateValue.into());
|
return Err(Error::InvalidWindowUpdateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(WindowUpdate {
|
Ok(WindowUpdate {
|
||||||
|
|||||||
@@ -168,7 +168,11 @@ impl Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes the headers found in the given buffer.
|
/// Decodes the headers found in the given buffer.
|
||||||
pub fn decode<F>(&mut self, src: &mut Cursor<&mut BytesMut>, mut f: F) -> Result<(), DecoderError>
|
pub fn decode<F>(
|
||||||
|
&mut self,
|
||||||
|
src: &mut Cursor<&mut BytesMut>,
|
||||||
|
mut f: F,
|
||||||
|
) -> Result<(), DecoderError>
|
||||||
where
|
where
|
||||||
F: FnMut(Header),
|
F: FnMut(Header),
|
||||||
{
|
{
|
||||||
@@ -193,7 +197,7 @@ impl Decoder {
|
|||||||
let entry = self.decode_indexed(src)?;
|
let entry = self.decode_indexed(src)?;
|
||||||
consume(src);
|
consume(src);
|
||||||
f(entry);
|
f(entry);
|
||||||
},
|
}
|
||||||
LiteralWithIndexing => {
|
LiteralWithIndexing => {
|
||||||
log::trace!(" LiteralWithIndexing; rem={:?}", src.remaining());
|
log::trace!(" LiteralWithIndexing; rem={:?}", src.remaining());
|
||||||
can_resize = false;
|
can_resize = false;
|
||||||
@@ -204,14 +208,14 @@ impl Decoder {
|
|||||||
consume(src);
|
consume(src);
|
||||||
|
|
||||||
f(entry);
|
f(entry);
|
||||||
},
|
}
|
||||||
LiteralWithoutIndexing => {
|
LiteralWithoutIndexing => {
|
||||||
log::trace!(" LiteralWithoutIndexing; rem={:?}", src.remaining());
|
log::trace!(" LiteralWithoutIndexing; rem={:?}", src.remaining());
|
||||||
can_resize = false;
|
can_resize = false;
|
||||||
let entry = self.decode_literal(src, false)?;
|
let entry = self.decode_literal(src, false)?;
|
||||||
consume(src);
|
consume(src);
|
||||||
f(entry);
|
f(entry);
|
||||||
},
|
}
|
||||||
LiteralNeverIndexed => {
|
LiteralNeverIndexed => {
|
||||||
log::trace!(" LiteralNeverIndexed; rem={:?}", src.remaining());
|
log::trace!(" LiteralNeverIndexed; rem={:?}", src.remaining());
|
||||||
can_resize = false;
|
can_resize = false;
|
||||||
@@ -221,7 +225,7 @@ impl Decoder {
|
|||||||
// TODO: Track that this should never be indexed
|
// TODO: Track that this should never be indexed
|
||||||
|
|
||||||
f(entry);
|
f(entry);
|
||||||
},
|
}
|
||||||
SizeUpdate => {
|
SizeUpdate => {
|
||||||
log::trace!(" SizeUpdate; rem={:?}", src.remaining());
|
log::trace!(" SizeUpdate; rem={:?}", src.remaining());
|
||||||
if !can_resize {
|
if !can_resize {
|
||||||
@@ -231,7 +235,7 @@ impl Decoder {
|
|||||||
// Handle the dynamic table size update
|
// Handle the dynamic table size update
|
||||||
self.process_size_update(src)?;
|
self.process_size_update(src)?;
|
||||||
consume(src);
|
consume(src);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +291,7 @@ impl Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> {
|
fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> {
|
||||||
const HUFF_FLAG: u8 = 0b10000000;
|
const HUFF_FLAG: u8 = 0b1000_0000;
|
||||||
|
|
||||||
// The first bit in the first byte contains the huffman encoded flag.
|
// The first bit in the first byte contains the huffman encoded flag.
|
||||||
let huff = match peek_u8(buf) {
|
let huff = match peek_u8(buf) {
|
||||||
@@ -331,12 +335,12 @@ impl Default for Decoder {
|
|||||||
|
|
||||||
impl Representation {
|
impl Representation {
|
||||||
pub fn load(byte: u8) -> Result<Representation, DecoderError> {
|
pub fn load(byte: u8) -> Result<Representation, DecoderError> {
|
||||||
const INDEXED: u8 = 0b10000000;
|
const INDEXED: u8 = 0b1000_0000;
|
||||||
const LITERAL_WITH_INDEXING: u8 = 0b01000000;
|
const LITERAL_WITH_INDEXING: u8 = 0b0100_0000;
|
||||||
const LITERAL_WITHOUT_INDEXING: u8 = 0b11110000;
|
const LITERAL_WITHOUT_INDEXING: u8 = 0b1111_0000;
|
||||||
const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
|
const LITERAL_NEVER_INDEXED: u8 = 0b0001_0000;
|
||||||
const SIZE_UPDATE_MASK: u8 = 0b11100000;
|
const SIZE_UPDATE_MASK: u8 = 0b1110_0000;
|
||||||
const SIZE_UPDATE: u8 = 0b00100000;
|
const SIZE_UPDATE: u8 = 0b0010_0000;
|
||||||
|
|
||||||
// TODO: What did I even write here?
|
// TODO: What did I even write here?
|
||||||
|
|
||||||
@@ -361,8 +365,8 @@ fn decode_int<B: Buf>(buf: &mut B, prefix_size: u8) -> Result<usize, DecoderErro
|
|||||||
// never overflow an unsigned 32-bit integer. The maximum value of any
|
// never overflow an unsigned 32-bit integer. The maximum value of any
|
||||||
// integer that can be encoded with 5 octets is ~2^28
|
// integer that can be encoded with 5 octets is ~2^28
|
||||||
const MAX_BYTES: usize = 5;
|
const MAX_BYTES: usize = 5;
|
||||||
const VARINT_MASK: u8 = 0b01111111;
|
const VARINT_MASK: u8 = 0b0111_1111;
|
||||||
const VARINT_FLAG: u8 = 0b10000000;
|
const VARINT_FLAG: u8 = 0b1000_0000;
|
||||||
|
|
||||||
if prefix_size < 1 || prefix_size > 8 {
|
if prefix_size < 1 || prefix_size > 8 {
|
||||||
return Err(DecoderError::InvalidIntegerPrefix);
|
return Err(DecoderError::InvalidIntegerPrefix);
|
||||||
@@ -445,7 +449,7 @@ impl Table {
|
|||||||
Table {
|
Table {
|
||||||
entries: VecDeque::new(),
|
entries: VecDeque::new(),
|
||||||
size: 0,
|
size: 0,
|
||||||
max_size: max_size,
|
max_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +520,7 @@ impl Table {
|
|||||||
// Can never happen as the size of the table must reach
|
// Can never happen as the size of the table must reach
|
||||||
// 0 by the time we've exhausted all elements.
|
// 0 by the time we've exhausted all elements.
|
||||||
panic!("Size of table != 0, but no headers left!");
|
panic!("Size of table != 0, but no headers left!");
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.size -= last.len();
|
self.size -= last.len();
|
||||||
@@ -827,15 +831,20 @@ mod test {
|
|||||||
let mut buf = buf.into();
|
let mut buf = buf.into();
|
||||||
|
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
let _ = de.decode(&mut Cursor::new(&mut buf), |h| {
|
let _ = de
|
||||||
res.push(h);
|
.decode(&mut Cursor::new(&mut buf), |h| {
|
||||||
}).unwrap();
|
res.push(h);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(res.len(), 1);
|
assert_eq!(res.len(), 1);
|
||||||
assert_eq!(de.table.size(), 0);
|
assert_eq!(de.table.size(), 0);
|
||||||
|
|
||||||
match res[0] {
|
match res[0] {
|
||||||
Header::Field { ref name, ref value } => {
|
Header::Field {
|
||||||
|
ref name,
|
||||||
|
ref value,
|
||||||
|
} => {
|
||||||
assert_eq!(name, "foo");
|
assert_eq!(name, "foo");
|
||||||
assert_eq!(value, "bar");
|
assert_eq!(value, "bar");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::{huffman, Header};
|
|
||||||
use super::table::{Index, Table};
|
use super::table::{Index, Table};
|
||||||
|
use super::{huffman, Header};
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
@@ -47,27 +47,31 @@ impl Encoder {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn update_max_size(&mut self, val: usize) {
|
pub fn update_max_size(&mut self, val: usize) {
|
||||||
match self.size_update {
|
match self.size_update {
|
||||||
Some(SizeUpdate::One(old)) => if val > old {
|
Some(SizeUpdate::One(old)) => {
|
||||||
if old > self.table.max_size() {
|
if val > old {
|
||||||
|
if old > self.table.max_size() {
|
||||||
|
self.size_update = Some(SizeUpdate::One(val));
|
||||||
|
} else {
|
||||||
|
self.size_update = Some(SizeUpdate::Two(old, val));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.size_update = Some(SizeUpdate::One(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(SizeUpdate::Two(min, _)) => {
|
||||||
|
if val < min {
|
||||||
self.size_update = Some(SizeUpdate::One(val));
|
self.size_update = Some(SizeUpdate::One(val));
|
||||||
} else {
|
} else {
|
||||||
self.size_update = Some(SizeUpdate::Two(old, val));
|
self.size_update = Some(SizeUpdate::Two(min, val));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
self.size_update = Some(SizeUpdate::One(val));
|
|
||||||
},
|
|
||||||
Some(SizeUpdate::Two(min, _)) => if val < min {
|
|
||||||
self.size_update = Some(SizeUpdate::One(val));
|
|
||||||
} else {
|
|
||||||
self.size_update = Some(SizeUpdate::Two(min, val));
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
if val != self.table.max_size() {
|
if val != self.table.max_size() {
|
||||||
// Don't bother writing a frame if the value already matches
|
// Don't bother writing a frame if the value already matches
|
||||||
// the table's max size.
|
// the table's max size.
|
||||||
self.size_update = Some(SizeUpdate::One(val));
|
self.size_update = Some(SizeUpdate::One(val));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,14 +124,11 @@ impl Encoder {
|
|||||||
|
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
dst.truncate(len);
|
dst.truncate(len);
|
||||||
return Encode::Partial(EncodeState {
|
return Encode::Partial(EncodeState { index, value: None });
|
||||||
index: index,
|
|
||||||
value: None,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last_index = Some(index);
|
last_index = Some(index);
|
||||||
},
|
}
|
||||||
// The header does not have an associated name. This means that
|
// The header does not have an associated name. This means that
|
||||||
// the name is the same as the previously yielded header. In
|
// the name is the same as the previously yielded header. In
|
||||||
// which case, we skip table lookup and just use the same index
|
// which case, we skip table lookup and just use the same index
|
||||||
@@ -148,7 +149,7 @@ impl Encoder {
|
|||||||
value: Some(value),
|
value: Some(value),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,14 +161,14 @@ impl Encoder {
|
|||||||
Some(SizeUpdate::One(val)) => {
|
Some(SizeUpdate::One(val)) => {
|
||||||
self.table.resize(val);
|
self.table.resize(val);
|
||||||
encode_size_update(val, dst)?;
|
encode_size_update(val, dst)?;
|
||||||
},
|
}
|
||||||
Some(SizeUpdate::Two(min, max)) => {
|
Some(SizeUpdate::Two(min, max)) => {
|
||||||
self.table.resize(min);
|
self.table.resize(min);
|
||||||
self.table.resize(max);
|
self.table.resize(max);
|
||||||
encode_size_update(min, dst)?;
|
encode_size_update(min, dst)?;
|
||||||
encode_size_update(max, dst)?;
|
encode_size_update(max, dst)?;
|
||||||
},
|
}
|
||||||
None => {},
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -177,12 +178,12 @@ impl Encoder {
|
|||||||
match *index {
|
match *index {
|
||||||
Index::Indexed(idx, _) => {
|
Index::Indexed(idx, _) => {
|
||||||
encode_int(idx, 7, 0x80, dst)?;
|
encode_int(idx, 7, 0x80, dst)?;
|
||||||
},
|
}
|
||||||
Index::Name(idx, _) => {
|
Index::Name(idx, _) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
encode_not_indexed(idx, header.value_slice(), header.is_sensitive(), dst)?;
|
encode_not_indexed(idx, header.value_slice(), header.is_sensitive(), dst)?;
|
||||||
},
|
}
|
||||||
Index::Inserted(_) => {
|
Index::Inserted(_) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
@@ -192,19 +193,19 @@ impl Encoder {
|
|||||||
return Err(EncoderError::BufferOverflow);
|
return Err(EncoderError::BufferOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.put_u8(0b01000000);
|
dst.put_u8(0b0100_0000);
|
||||||
|
|
||||||
encode_str(header.name().as_slice(), dst)?;
|
encode_str(header.name().as_slice(), dst)?;
|
||||||
encode_str(header.value_slice(), dst)?;
|
encode_str(header.value_slice(), dst)?;
|
||||||
},
|
}
|
||||||
Index::InsertedValue(idx, _) => {
|
Index::InsertedValue(idx, _) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
assert!(!header.is_sensitive());
|
assert!(!header.is_sensitive());
|
||||||
|
|
||||||
encode_int(idx, 6, 0b01000000, dst)?;
|
encode_int(idx, 6, 0b0100_0000, dst)?;
|
||||||
encode_str(header.value_slice(), dst)?;
|
encode_str(header.value_slice(), dst)?;
|
||||||
},
|
}
|
||||||
Index::NotIndexed(_) => {
|
Index::NotIndexed(_) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
@@ -214,7 +215,7 @@ impl Encoder {
|
|||||||
header.is_sensitive(),
|
header.is_sensitive(),
|
||||||
dst,
|
dst,
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -227,14 +228,14 @@ impl Encoder {
|
|||||||
dst: &mut BytesMut,
|
dst: &mut BytesMut,
|
||||||
) -> Result<(), EncoderError> {
|
) -> Result<(), EncoderError> {
|
||||||
match *last {
|
match *last {
|
||||||
Index::Indexed(..) |
|
Index::Indexed(..)
|
||||||
Index::Name(..) |
|
| Index::Name(..)
|
||||||
Index::Inserted(..) |
|
| Index::Inserted(..)
|
||||||
Index::InsertedValue(..) => {
|
| Index::InsertedValue(..) => {
|
||||||
let idx = self.table.resolve_idx(last);
|
let idx = self.table.resolve_idx(last);
|
||||||
|
|
||||||
encode_not_indexed(idx, value.as_ref(), value.is_sensitive(), dst)?;
|
encode_not_indexed(idx, value.as_ref(), value.is_sensitive(), dst)?;
|
||||||
},
|
}
|
||||||
Index::NotIndexed(_) => {
|
Index::NotIndexed(_) => {
|
||||||
let last = self.table.resolve(last);
|
let last = self.table.resolve(last);
|
||||||
|
|
||||||
@@ -244,7 +245,7 @@ impl Encoder {
|
|||||||
value.is_sensitive(),
|
value.is_sensitive(),
|
||||||
dst,
|
dst,
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -258,7 +259,7 @@ impl Default for Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderError> {
|
fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderError> {
|
||||||
encode_int(val, 5, 0b00100000, dst)
|
encode_int(val, 5, 0b0010_0000, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_not_indexed(
|
fn encode_not_indexed(
|
||||||
@@ -305,7 +306,7 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
|||||||
return Err(EncoderError::BufferOverflow);
|
return Err(EncoderError::BufferOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.len() != 0 {
|
if !val.is_empty() {
|
||||||
let idx = dst.len();
|
let idx = dst.len();
|
||||||
|
|
||||||
// Push a placeholder byte for the length header
|
// Push a placeholder byte for the length header
|
||||||
@@ -378,7 +379,7 @@ fn encode_int<B: BufMut>(
|
|||||||
|
|
||||||
value -= low;
|
value -= low;
|
||||||
|
|
||||||
if value > 0x0fffffff {
|
if value > 0x0fff_ffff {
|
||||||
panic!("value out of range");
|
panic!("value out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,10 +391,10 @@ fn encode_int<B: BufMut>(
|
|||||||
return Err(EncoderError::BufferOverflow);
|
return Err(EncoderError::BufferOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.put_u8(0b10000000 | value as u8);
|
dst.put_u8(0b1000_0000 | value as u8);
|
||||||
rem -= 1;
|
rem -= 1;
|
||||||
|
|
||||||
value = value >> 7;
|
value >>= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
if rem == 0 {
|
if rem == 0 {
|
||||||
@@ -560,7 +561,7 @@ mod test {
|
|||||||
|
|
||||||
let header = Header::Field {
|
let header = Header::Field {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
value: value,
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now, try to encode the sensitive header
|
// Now, try to encode the sensitive header
|
||||||
@@ -580,7 +581,7 @@ mod test {
|
|||||||
|
|
||||||
let header = Header::Field {
|
let header = Header::Field {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
value: value,
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut encoder = Encoder::default();
|
let mut encoder = Encoder::default();
|
||||||
@@ -604,7 +605,7 @@ mod test {
|
|||||||
|
|
||||||
let header = Header::Field {
|
let header = Header::Field {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
value: value,
|
value,
|
||||||
};
|
};
|
||||||
let res = encode(&mut encoder, vec![header]);
|
let res = encode(&mut encoder, vec![header]);
|
||||||
|
|
||||||
@@ -808,7 +809,8 @@ mod test {
|
|||||||
name: None,
|
name: None,
|
||||||
value: HeaderValue::from_bytes(b"sup").unwrap(),
|
value: HeaderValue::from_bytes(b"sup").unwrap(),
|
||||||
},
|
},
|
||||||
].into_iter();
|
]
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
let resume = match encoder.encode(None, &mut input, &mut dst) {
|
let resume = match encoder.encode(None, &mut input, &mut dst) {
|
||||||
Encode::Partial(r) => r,
|
Encode::Partial(r) => r,
|
||||||
@@ -823,7 +825,7 @@ mod test {
|
|||||||
dst.clear();
|
dst.clear();
|
||||||
|
|
||||||
match encoder.encode(Some(resume), &mut input, &mut dst) {
|
match encoder.encode(Some(resume), &mut input, &mut dst) {
|
||||||
Encode::Full => {},
|
Encode::Full => {}
|
||||||
unexpected => panic!("resume returned unexpected: {:?}", unexpected),
|
unexpected => panic!("resume returned unexpected: {:?}", unexpected),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,7 +858,7 @@ mod test {
|
|||||||
|
|
||||||
Header::Field {
|
Header::Field {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
value: value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::{DecoderError, NeedMore};
|
use super::{DecoderError, NeedMore};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use http::{Method, StatusCode};
|
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
|
use http::{Method, StatusCode};
|
||||||
use string::{String, TryFrom};
|
use string::{String, TryFrom};
|
||||||
|
|
||||||
/// HTTP/2.0 Header
|
/// HTTP/2.0 Header
|
||||||
@@ -41,14 +41,8 @@ impl Header<Option<HeaderName>> {
|
|||||||
Field {
|
Field {
|
||||||
name: Some(n),
|
name: Some(n),
|
||||||
value,
|
value,
|
||||||
} => Field {
|
} => Field { name: n, value },
|
||||||
name: n,
|
Field { name: None, value } => return Err(value),
|
||||||
value: value,
|
|
||||||
},
|
|
||||||
Field {
|
|
||||||
name: None,
|
|
||||||
value,
|
|
||||||
} => return Err(value),
|
|
||||||
Authority(v) => Authority(v),
|
Authority(v) => Authority(v),
|
||||||
Method(v) => Method(v),
|
Method(v) => Method(v),
|
||||||
Scheme(v) => Scheme(v),
|
Scheme(v) => Scheme(v),
|
||||||
@@ -60,7 +54,7 @@ impl Header<Option<HeaderName>> {
|
|||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
|
pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
|
||||||
if name.len() == 0 {
|
if name.is_empty() {
|
||||||
return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream));
|
return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream));
|
||||||
}
|
}
|
||||||
if name[0] == b':' {
|
if name[0] == b':' {
|
||||||
@@ -68,23 +62,23 @@ impl Header {
|
|||||||
b"authority" => {
|
b"authority" => {
|
||||||
let value = String::try_from(value)?;
|
let value = String::try_from(value)?;
|
||||||
Ok(Header::Authority(value))
|
Ok(Header::Authority(value))
|
||||||
},
|
}
|
||||||
b"method" => {
|
b"method" => {
|
||||||
let method = Method::from_bytes(&value)?;
|
let method = Method::from_bytes(&value)?;
|
||||||
Ok(Header::Method(method))
|
Ok(Header::Method(method))
|
||||||
},
|
}
|
||||||
b"scheme" => {
|
b"scheme" => {
|
||||||
let value = String::try_from(value)?;
|
let value = String::try_from(value)?;
|
||||||
Ok(Header::Scheme(value))
|
Ok(Header::Scheme(value))
|
||||||
},
|
}
|
||||||
b"path" => {
|
b"path" => {
|
||||||
let value = String::try_from(value)?;
|
let value = String::try_from(value)?;
|
||||||
Ok(Header::Path(value))
|
Ok(Header::Path(value))
|
||||||
},
|
}
|
||||||
b"status" => {
|
b"status" => {
|
||||||
let status = StatusCode::from_bytes(&value)?;
|
let status = StatusCode::from_bytes(&value)?;
|
||||||
Ok(Header::Status(status))
|
Ok(Header::Status(status))
|
||||||
},
|
}
|
||||||
_ => Err(DecoderError::InvalidPseudoheader),
|
_ => Err(DecoderError::InvalidPseudoheader),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -92,10 +86,7 @@ impl Header {
|
|||||||
let name = HeaderName::from_lowercase(&name)?;
|
let name = HeaderName::from_lowercase(&name)?;
|
||||||
let value = HeaderValue::from_bytes(&value)?;
|
let value = HeaderValue::from_bytes(&value)?;
|
||||||
|
|
||||||
Ok(Header::Field {
|
Ok(Header::Field { name, value })
|
||||||
name: name,
|
|
||||||
value: value,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,9 +107,7 @@ impl Header {
|
|||||||
/// Returns the header name
|
/// Returns the header name
|
||||||
pub fn name(&self) -> Name {
|
pub fn name(&self) -> Name {
|
||||||
match *self {
|
match *self {
|
||||||
Header::Field {
|
Header::Field { ref name, .. } => Name::Field(name),
|
||||||
ref name, ..
|
|
||||||
} => Name::Field(name),
|
|
||||||
Header::Authority(..) => Name::Authority,
|
Header::Authority(..) => Name::Authority,
|
||||||
Header::Method(..) => Name::Method,
|
Header::Method(..) => Name::Method,
|
||||||
Header::Scheme(..) => Name::Scheme,
|
Header::Scheme(..) => Name::Scheme,
|
||||||
@@ -129,9 +118,7 @@ impl Header {
|
|||||||
|
|
||||||
pub fn value_slice(&self) -> &[u8] {
|
pub fn value_slice(&self) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
Header::Field {
|
Header::Field { ref value, .. } => value.as_ref(),
|
||||||
ref value, ..
|
|
||||||
} => value.as_ref(),
|
|
||||||
Header::Authority(ref v) => v.as_ref(),
|
Header::Authority(ref v) => v.as_ref(),
|
||||||
Header::Method(ref v) => v.as_ref().as_ref(),
|
Header::Method(ref v) => v.as_ref().as_ref(),
|
||||||
Header::Scheme(ref v) => v.as_ref(),
|
Header::Scheme(ref v) => v.as_ref(),
|
||||||
@@ -142,17 +129,13 @@ impl Header {
|
|||||||
|
|
||||||
pub fn value_eq(&self, other: &Header) -> bool {
|
pub fn value_eq(&self, other: &Header) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Header::Field {
|
Header::Field { ref value, .. } => {
|
||||||
ref value, ..
|
|
||||||
} => {
|
|
||||||
let a = value;
|
let a = value;
|
||||||
match *other {
|
match *other {
|
||||||
Header::Field {
|
Header::Field { ref value, .. } => a == value,
|
||||||
ref value, ..
|
|
||||||
} => a == value,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Header::Authority(ref a) => match *other {
|
Header::Authority(ref a) => match *other {
|
||||||
Header::Authority(ref b) => a == b,
|
Header::Authority(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -178,9 +161,7 @@ impl Header {
|
|||||||
|
|
||||||
pub fn is_sensitive(&self) -> bool {
|
pub fn is_sensitive(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Header::Field {
|
Header::Field { ref value, .. } => value.is_sensitive(),
|
||||||
ref value, ..
|
|
||||||
} => value.is_sensitive(),
|
|
||||||
// TODO: Technically these other header values can be sensitive too.
|
// TODO: Technically these other header values can be sensitive too.
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -190,18 +171,16 @@ impl Header {
|
|||||||
use http::header;
|
use http::header;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Header::Field {
|
Header::Field { ref name, .. } => match *name {
|
||||||
ref name, ..
|
header::AGE
|
||||||
} => match *name {
|
| header::AUTHORIZATION
|
||||||
header::AGE |
|
| header::CONTENT_LENGTH
|
||||||
header::AUTHORIZATION |
|
| header::ETAG
|
||||||
header::CONTENT_LENGTH |
|
| header::IF_MODIFIED_SINCE
|
||||||
header::ETAG |
|
| header::IF_NONE_MATCH
|
||||||
header::IF_MODIFIED_SINCE |
|
| header::LOCATION
|
||||||
header::IF_NONE_MATCH |
|
| header::COOKIE
|
||||||
header::LOCATION |
|
| header::SET_COOKIE => true,
|
||||||
header::COOKIE |
|
|
||||||
header::SET_COOKIE => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Header::Path(..) => true,
|
Header::Path(..) => true,
|
||||||
@@ -214,10 +193,7 @@ impl Header {
|
|||||||
impl From<Header> for Header<Option<HeaderName>> {
|
impl From<Header> for Header<Option<HeaderName>> {
|
||||||
fn from(src: Header) -> Self {
|
fn from(src: Header) -> Self {
|
||||||
match src {
|
match src {
|
||||||
Header::Field {
|
Header::Field { name, value } => Header::Field {
|
||||||
name,
|
|
||||||
value,
|
|
||||||
} => Header::Field {
|
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
@@ -247,7 +223,7 @@ impl<'a> Name<'a> {
|
|||||||
// TODO: better error handling
|
// TODO: better error handling
|
||||||
Err(_) => Err(DecoderError::InvalidStatusCode),
|
Err(_) => Err(DecoderError::InvalidStatusCode),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,37 +3,37 @@
|
|||||||
// (num-bits, bits)
|
// (num-bits, bits)
|
||||||
pub const ENCODE_TABLE: [(usize, u64); 257] = [
|
pub const ENCODE_TABLE: [(usize, u64); 257] = [
|
||||||
(13, 0x1ff8),
|
(13, 0x1ff8),
|
||||||
(23, 0x7fffd8),
|
(23, 0x007f_ffd8),
|
||||||
(28, 0xfffffe2),
|
(28, 0x0fff_ffe2),
|
||||||
(28, 0xfffffe3),
|
(28, 0x0fff_ffe3),
|
||||||
(28, 0xfffffe4),
|
(28, 0x0fff_ffe4),
|
||||||
(28, 0xfffffe5),
|
(28, 0x0fff_ffe5),
|
||||||
(28, 0xfffffe6),
|
(28, 0x0fff_ffe6),
|
||||||
(28, 0xfffffe7),
|
(28, 0x0fff_ffe7),
|
||||||
(28, 0xfffffe8),
|
(28, 0x0fff_ffe8),
|
||||||
(24, 0xffffea),
|
(24, 0x00ff_ffea),
|
||||||
(30, 0x3ffffffc),
|
(30, 0x3fff_fffc),
|
||||||
(28, 0xfffffe9),
|
(28, 0x0fff_ffe9),
|
||||||
(28, 0xfffffea),
|
(28, 0x0fff_ffea),
|
||||||
(30, 0x3ffffffd),
|
(30, 0x3fff_fffd),
|
||||||
(28, 0xfffffeb),
|
(28, 0x0fff_ffeb),
|
||||||
(28, 0xfffffec),
|
(28, 0x0fff_ffec),
|
||||||
(28, 0xfffffed),
|
(28, 0x0fff_ffed),
|
||||||
(28, 0xfffffee),
|
(28, 0x0fff_ffee),
|
||||||
(28, 0xfffffef),
|
(28, 0x0fff_ffef),
|
||||||
(28, 0xffffff0),
|
(28, 0x0fff_fff0),
|
||||||
(28, 0xffffff1),
|
(28, 0x0fff_fff1),
|
||||||
(28, 0xffffff2),
|
(28, 0x0fff_fff2),
|
||||||
(30, 0x3ffffffe),
|
(30, 0x3fff_fffe),
|
||||||
(28, 0xffffff3),
|
(28, 0x0fff_fff3),
|
||||||
(28, 0xffffff4),
|
(28, 0x0fff_fff4),
|
||||||
(28, 0xffffff5),
|
(28, 0x0fff_fff5),
|
||||||
(28, 0xffffff6),
|
(28, 0x0fff_fff6),
|
||||||
(28, 0xffffff7),
|
(28, 0x0fff_fff7),
|
||||||
(28, 0xffffff8),
|
(28, 0x0fff_fff8),
|
||||||
(28, 0xffffff9),
|
(28, 0x0fff_fff9),
|
||||||
(28, 0xffffffa),
|
(28, 0x0fff_fffa),
|
||||||
(28, 0xffffffb),
|
(28, 0x0fff_fffb),
|
||||||
(6, 0x14),
|
(6, 0x14),
|
||||||
(10, 0x3f8),
|
(10, 0x3f8),
|
||||||
(10, 0x3f9),
|
(10, 0x3f9),
|
||||||
@@ -129,136 +129,136 @@ pub const ENCODE_TABLE: [(usize, u64); 257] = [
|
|||||||
(11, 0x7fc),
|
(11, 0x7fc),
|
||||||
(14, 0x3ffd),
|
(14, 0x3ffd),
|
||||||
(13, 0x1ffd),
|
(13, 0x1ffd),
|
||||||
(28, 0xffffffc),
|
(28, 0x0fff_fffc),
|
||||||
(20, 0xfffe6),
|
(20, 0xfffe6),
|
||||||
(22, 0x3fffd2),
|
(22, 0x003f_ffd2),
|
||||||
(20, 0xfffe7),
|
(20, 0xfffe7),
|
||||||
(20, 0xfffe8),
|
(20, 0xfffe8),
|
||||||
(22, 0x3fffd3),
|
(22, 0x003f_ffd3),
|
||||||
(22, 0x3fffd4),
|
(22, 0x003f_ffd4),
|
||||||
(22, 0x3fffd5),
|
(22, 0x003f_ffd5),
|
||||||
(23, 0x7fffd9),
|
(23, 0x007f_ffd9),
|
||||||
(22, 0x3fffd6),
|
(22, 0x003f_ffd6),
|
||||||
(23, 0x7fffda),
|
(23, 0x007f_ffda),
|
||||||
(23, 0x7fffdb),
|
(23, 0x007f_ffdb),
|
||||||
(23, 0x7fffdc),
|
(23, 0x007f_ffdc),
|
||||||
(23, 0x7fffdd),
|
(23, 0x007f_ffdd),
|
||||||
(23, 0x7fffde),
|
(23, 0x007f_ffde),
|
||||||
(24, 0xffffeb),
|
(24, 0x00ff_ffeb),
|
||||||
(23, 0x7fffdf),
|
(23, 0x007f_ffdf),
|
||||||
(24, 0xffffec),
|
(24, 0x00ff_ffec),
|
||||||
(24, 0xffffed),
|
(24, 0x00ff_ffed),
|
||||||
(22, 0x3fffd7),
|
(22, 0x003f_ffd7),
|
||||||
(23, 0x7fffe0),
|
(23, 0x007f_ffe0),
|
||||||
(24, 0xffffee),
|
(24, 0x00ff_ffee),
|
||||||
(23, 0x7fffe1),
|
(23, 0x007f_ffe1),
|
||||||
(23, 0x7fffe2),
|
(23, 0x007f_ffe2),
|
||||||
(23, 0x7fffe3),
|
(23, 0x007f_ffe3),
|
||||||
(23, 0x7fffe4),
|
(23, 0x007f_ffe4),
|
||||||
(21, 0x1fffdc),
|
(21, 0x001f_ffdc),
|
||||||
(22, 0x3fffd8),
|
(22, 0x003f_ffd8),
|
||||||
(23, 0x7fffe5),
|
(23, 0x007f_ffe5),
|
||||||
(22, 0x3fffd9),
|
(22, 0x003f_ffd9),
|
||||||
(23, 0x7fffe6),
|
(23, 0x007f_ffe6),
|
||||||
(23, 0x7fffe7),
|
(23, 0x007f_ffe7),
|
||||||
(24, 0xffffef),
|
(24, 0x00ff_ffef),
|
||||||
(22, 0x3fffda),
|
(22, 0x003f_ffda),
|
||||||
(21, 0x1fffdd),
|
(21, 0x001f_ffdd),
|
||||||
(20, 0xfffe9),
|
(20, 0xfffe9),
|
||||||
(22, 0x3fffdb),
|
(22, 0x003f_ffdb),
|
||||||
(22, 0x3fffdc),
|
(22, 0x003f_ffdc),
|
||||||
(23, 0x7fffe8),
|
(23, 0x007f_ffe8),
|
||||||
(23, 0x7fffe9),
|
(23, 0x007f_ffe9),
|
||||||
(21, 0x1fffde),
|
(21, 0x001f_ffde),
|
||||||
(23, 0x7fffea),
|
(23, 0x007f_ffea),
|
||||||
(22, 0x3fffdd),
|
(22, 0x003f_ffdd),
|
||||||
(22, 0x3fffde),
|
(22, 0x003f_ffde),
|
||||||
(24, 0xfffff0),
|
(24, 0x00ff_fff0),
|
||||||
(21, 0x1fffdf),
|
(21, 0x001f_ffdf),
|
||||||
(22, 0x3fffdf),
|
(22, 0x003f_ffdf),
|
||||||
(23, 0x7fffeb),
|
(23, 0x007f_ffeb),
|
||||||
(23, 0x7fffec),
|
(23, 0x007f_ffec),
|
||||||
(21, 0x1fffe0),
|
(21, 0x001f_ffe0),
|
||||||
(21, 0x1fffe1),
|
(21, 0x001f_ffe1),
|
||||||
(22, 0x3fffe0),
|
(22, 0x003f_ffe0),
|
||||||
(21, 0x1fffe2),
|
(21, 0x001f_ffe2),
|
||||||
(23, 0x7fffed),
|
(23, 0x007f_ffed),
|
||||||
(22, 0x3fffe1),
|
(22, 0x003f_ffe1),
|
||||||
(23, 0x7fffee),
|
(23, 0x007f_ffee),
|
||||||
(23, 0x7fffef),
|
(23, 0x007f_ffef),
|
||||||
(20, 0xfffea),
|
(20, 0xfffea),
|
||||||
(22, 0x3fffe2),
|
(22, 0x003f_ffe2),
|
||||||
(22, 0x3fffe3),
|
(22, 0x003f_ffe3),
|
||||||
(22, 0x3fffe4),
|
(22, 0x003f_ffe4),
|
||||||
(23, 0x7ffff0),
|
(23, 0x007f_fff0),
|
||||||
(22, 0x3fffe5),
|
(22, 0x003f_ffe5),
|
||||||
(22, 0x3fffe6),
|
(22, 0x003f_ffe6),
|
||||||
(23, 0x7ffff1),
|
(23, 0x007f_fff1),
|
||||||
(26, 0x3ffffe0),
|
(26, 0x03ff_ffe0),
|
||||||
(26, 0x3ffffe1),
|
(26, 0x03ff_ffe1),
|
||||||
(20, 0xfffeb),
|
(20, 0xfffeb),
|
||||||
(19, 0x7fff1),
|
(19, 0x7fff1),
|
||||||
(22, 0x3fffe7),
|
(22, 0x003f_ffe7),
|
||||||
(23, 0x7ffff2),
|
(23, 0x007f_fff2),
|
||||||
(22, 0x3fffe8),
|
(22, 0x003f_ffe8),
|
||||||
(25, 0x1ffffec),
|
(25, 0x01ff_ffec),
|
||||||
(26, 0x3ffffe2),
|
(26, 0x03ff_ffe2),
|
||||||
(26, 0x3ffffe3),
|
(26, 0x03ff_ffe3),
|
||||||
(26, 0x3ffffe4),
|
(26, 0x03ff_ffe4),
|
||||||
(27, 0x7ffffde),
|
(27, 0x07ff_ffde),
|
||||||
(27, 0x7ffffdf),
|
(27, 0x07ff_ffdf),
|
||||||
(26, 0x3ffffe5),
|
(26, 0x03ff_ffe5),
|
||||||
(24, 0xfffff1),
|
(24, 0x00ff_fff1),
|
||||||
(25, 0x1ffffed),
|
(25, 0x01ff_ffed),
|
||||||
(19, 0x7fff2),
|
(19, 0x7fff2),
|
||||||
(21, 0x1fffe3),
|
(21, 0x001f_ffe3),
|
||||||
(26, 0x3ffffe6),
|
(26, 0x03ff_ffe6),
|
||||||
(27, 0x7ffffe0),
|
(27, 0x07ff_ffe0),
|
||||||
(27, 0x7ffffe1),
|
(27, 0x07ff_ffe1),
|
||||||
(26, 0x3ffffe7),
|
(26, 0x03ff_ffe7),
|
||||||
(27, 0x7ffffe2),
|
(27, 0x07ff_ffe2),
|
||||||
(24, 0xfffff2),
|
(24, 0x00ff_fff2),
|
||||||
(21, 0x1fffe4),
|
(21, 0x001f_ffe4),
|
||||||
(21, 0x1fffe5),
|
(21, 0x001f_ffe5),
|
||||||
(26, 0x3ffffe8),
|
(26, 0x03ff_ffe8),
|
||||||
(26, 0x3ffffe9),
|
(26, 0x03ff_ffe9),
|
||||||
(28, 0xffffffd),
|
(28, 0x0fff_fffd),
|
||||||
(27, 0x7ffffe3),
|
(27, 0x07ff_ffe3),
|
||||||
(27, 0x7ffffe4),
|
(27, 0x07ff_ffe4),
|
||||||
(27, 0x7ffffe5),
|
(27, 0x07ff_ffe5),
|
||||||
(20, 0xfffec),
|
(20, 0xfffec),
|
||||||
(24, 0xfffff3),
|
(24, 0x00ff_fff3),
|
||||||
(20, 0xfffed),
|
(20, 0xfffed),
|
||||||
(21, 0x1fffe6),
|
(21, 0x001f_ffe6),
|
||||||
(22, 0x3fffe9),
|
(22, 0x003f_ffe9),
|
||||||
(21, 0x1fffe7),
|
(21, 0x001f_ffe7),
|
||||||
(21, 0x1fffe8),
|
(21, 0x001f_ffe8),
|
||||||
(23, 0x7ffff3),
|
(23, 0x007f_fff3),
|
||||||
(22, 0x3fffea),
|
(22, 0x003f_ffea),
|
||||||
(22, 0x3fffeb),
|
(22, 0x003f_ffeb),
|
||||||
(25, 0x1ffffee),
|
(25, 0x01ff_ffee),
|
||||||
(25, 0x1ffffef),
|
(25, 0x01ff_ffef),
|
||||||
(24, 0xfffff4),
|
(24, 0x00ff_fff4),
|
||||||
(24, 0xfffff5),
|
(24, 0x00ff_fff5),
|
||||||
(26, 0x3ffffea),
|
(26, 0x03ff_ffea),
|
||||||
(23, 0x7ffff4),
|
(23, 0x007f_fff4),
|
||||||
(26, 0x3ffffeb),
|
(26, 0x03ff_ffeb),
|
||||||
(27, 0x7ffffe6),
|
(27, 0x07ff_ffe6),
|
||||||
(26, 0x3ffffec),
|
(26, 0x03ff_ffec),
|
||||||
(26, 0x3ffffed),
|
(26, 0x03ff_ffed),
|
||||||
(27, 0x7ffffe7),
|
(27, 0x07ff_ffe7),
|
||||||
(27, 0x7ffffe8),
|
(27, 0x07ff_ffe8),
|
||||||
(27, 0x7ffffe9),
|
(27, 0x07ff_ffe9),
|
||||||
(27, 0x7ffffea),
|
(27, 0x07ff_ffea),
|
||||||
(27, 0x7ffffeb),
|
(27, 0x07ff_ffeb),
|
||||||
(28, 0xffffffe),
|
(28, 0x0fff_fffe),
|
||||||
(27, 0x7ffffec),
|
(27, 0x07ff_ffec),
|
||||||
(27, 0x7ffffed),
|
(27, 0x07ff_ffed),
|
||||||
(27, 0x7ffffee),
|
(27, 0x07ff_ffee),
|
||||||
(27, 0x7ffffef),
|
(27, 0x07ff_ffef),
|
||||||
(27, 0x7fffff0),
|
(27, 0x07ff_fff0),
|
||||||
(26, 0x3ffffee),
|
(26, 0x03ff_ffee),
|
||||||
(30, 0x3fffffff),
|
(30, 0x3fff_ffff),
|
||||||
];
|
];
|
||||||
|
|
||||||
// (next-state, byte, flags)
|
// (next-state, byte, flags)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod encoder;
|
|
||||||
mod decoder;
|
mod decoder;
|
||||||
|
mod encoder;
|
||||||
pub(crate) mod header;
|
pub(crate) mod header;
|
||||||
mod huffman;
|
mod huffman;
|
||||||
mod table;
|
mod table;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use fnv::FnvHasher;
|
|||||||
use http::header;
|
use http::header;
|
||||||
use http::method::Method;
|
use http::method::Method;
|
||||||
|
|
||||||
use std::{cmp, mem, usize};
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::{cmp, mem, usize};
|
||||||
|
|
||||||
/// HPACK encoder table
|
/// HPACK encoder table
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -80,7 +80,7 @@ impl Table {
|
|||||||
slots: VecDeque::new(),
|
slots: VecDeque::new(),
|
||||||
inserted: 0,
|
inserted: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
max_size: max_size,
|
max_size,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let capacity = cmp::max(to_raw_capacity(capacity).next_power_of_two(), 8);
|
let capacity = cmp::max(to_raw_capacity(capacity).next_power_of_two(), 8);
|
||||||
@@ -91,7 +91,7 @@ impl Table {
|
|||||||
slots: VecDeque::with_capacity(usable_capacity(capacity)),
|
slots: VecDeque::with_capacity(usable_capacity(capacity)),
|
||||||
inserted: 0,
|
inserted: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
max_size: max_size,
|
max_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,10 +140,7 @@ impl Table {
|
|||||||
// Right now, if this is true, the header name is always in the
|
// Right now, if this is true, the header name is always in the
|
||||||
// static table. At some point in the future, this might not be true
|
// static table. At some point in the future, this might not be true
|
||||||
// and this logic will need to be updated.
|
// and this logic will need to be updated.
|
||||||
debug_assert!(
|
debug_assert!(statik.is_some(), "skip_value_index requires a static name",);
|
||||||
statik.is_some(),
|
|
||||||
"skip_value_index requires a static name",
|
|
||||||
);
|
|
||||||
return Index::new(statik, header);
|
return Index::new(statik, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +310,7 @@ impl Table {
|
|||||||
&mut self.indices[probe],
|
&mut self.indices[probe],
|
||||||
Some(Pos {
|
Some(Pos {
|
||||||
index: pos_idx,
|
index: pos_idx,
|
||||||
hash: hash,
|
hash,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -344,8 +341,8 @@ impl Table {
|
|||||||
self.inserted = self.inserted.wrapping_add(1);
|
self.inserted = self.inserted.wrapping_add(1);
|
||||||
|
|
||||||
self.slots.push_front(Slot {
|
self.slots.push_front(Slot {
|
||||||
hash: hash,
|
hash,
|
||||||
header: header,
|
header,
|
||||||
next: None,
|
next: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -534,89 +531,89 @@ impl Table {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn assert_valid_state(&self, _msg: &'static str) -> bool {
|
fn assert_valid_state(&self, _msg: &'static str) -> bool {
|
||||||
/*
|
/*
|
||||||
// Checks that the internal map structure is valid
|
// Checks that the internal map structure is valid
|
||||||
//
|
//
|
||||||
// Ensure all hash codes in indices match the associated slot
|
// Ensure all hash codes in indices match the associated slot
|
||||||
for pos in &self.indices {
|
for pos in &self.indices {
|
||||||
if let Some(pos) = *pos {
|
|
||||||
let real_idx = pos.index.wrapping_add(self.inserted);
|
|
||||||
|
|
||||||
if real_idx.wrapping_add(1) != 0 {
|
|
||||||
assert!(real_idx < self.slots.len(),
|
|
||||||
"out of index; real={}; len={}, msg={}",
|
|
||||||
real_idx, self.slots.len(), msg);
|
|
||||||
|
|
||||||
assert_eq!(pos.hash, self.slots[real_idx].hash,
|
|
||||||
"index hash does not match slot; msg={}", msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Every index is only available once
|
|
||||||
for i in 0..self.indices.len() {
|
|
||||||
if self.indices[i].is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in i+1..self.indices.len() {
|
|
||||||
assert_ne!(self.indices[i], self.indices[j],
|
|
||||||
"duplicate indices; msg={}", msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index, slot) in self.slots.iter().enumerate() {
|
|
||||||
let mut indexed = None;
|
|
||||||
|
|
||||||
// First, see if the slot is indexed
|
|
||||||
for (i, pos) in self.indices.iter().enumerate() {
|
|
||||||
if let Some(pos) = *pos {
|
if let Some(pos) = *pos {
|
||||||
let real_idx = pos.index.wrapping_add(self.inserted);
|
let real_idx = pos.index.wrapping_add(self.inserted);
|
||||||
if real_idx == index {
|
|
||||||
indexed = Some(i);
|
if real_idx.wrapping_add(1) != 0 {
|
||||||
// Already know that there is no dup, so break
|
assert!(real_idx < self.slots.len(),
|
||||||
break;
|
"out of index; real={}; len={}, msg={}",
|
||||||
|
real_idx, self.slots.len(), msg);
|
||||||
|
|
||||||
|
assert_eq!(pos.hash, self.slots[real_idx].hash,
|
||||||
|
"index hash does not match slot; msg={}", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(actual) = indexed {
|
// Every index is only available once
|
||||||
// Ensure that it is accessible..
|
for i in 0..self.indices.len() {
|
||||||
let desired = desired_pos(self.mask, slot.hash);
|
if self.indices[i].is_none() {
|
||||||
let mut probe = desired;
|
continue;
|
||||||
let mut dist = 0;
|
}
|
||||||
|
|
||||||
probe_loop!(probe < self.indices.len(), {
|
for j in i+1..self.indices.len() {
|
||||||
assert!(self.indices[probe].is_some(),
|
assert_ne!(self.indices[i], self.indices[j],
|
||||||
"unexpected empty slot; probe={}; hash={:?}; msg={}",
|
"duplicate indices; msg={}", msg);
|
||||||
probe, slot.hash, msg);
|
}
|
||||||
|
|
||||||
let pos = self.indices[probe].unwrap();
|
|
||||||
|
|
||||||
let their_dist = probe_distance(self.mask, pos.hash, probe);
|
|
||||||
let real_idx = pos.index.wrapping_add(self.inserted);
|
|
||||||
|
|
||||||
if real_idx == index {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(dist <= their_dist,
|
|
||||||
"could not find entry; actual={}; desired={};" +
|
|
||||||
"probe={}, dist={}; their_dist={}; index={}; msg={}",
|
|
||||||
actual, desired, probe, dist, their_dist,
|
|
||||||
index.wrapping_sub(self.inserted), msg);
|
|
||||||
|
|
||||||
dist += 1;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// There is exactly one next link
|
|
||||||
let cnt = self.slots.iter().map(|s| s.next)
|
|
||||||
.filter(|n| *n == Some(index.wrapping_sub(self.inserted)))
|
|
||||||
.count();
|
|
||||||
|
|
||||||
assert_eq!(1, cnt, "more than one node pointing here; msg={}", msg);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
for (index, slot) in self.slots.iter().enumerate() {
|
||||||
|
let mut indexed = None;
|
||||||
|
|
||||||
|
// First, see if the slot is indexed
|
||||||
|
for (i, pos) in self.indices.iter().enumerate() {
|
||||||
|
if let Some(pos) = *pos {
|
||||||
|
let real_idx = pos.index.wrapping_add(self.inserted);
|
||||||
|
if real_idx == index {
|
||||||
|
indexed = Some(i);
|
||||||
|
// Already know that there is no dup, so break
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(actual) = indexed {
|
||||||
|
// Ensure that it is accessible..
|
||||||
|
let desired = desired_pos(self.mask, slot.hash);
|
||||||
|
let mut probe = desired;
|
||||||
|
let mut dist = 0;
|
||||||
|
|
||||||
|
probe_loop!(probe < self.indices.len(), {
|
||||||
|
assert!(self.indices[probe].is_some(),
|
||||||
|
"unexpected empty slot; probe={}; hash={:?}; msg={}",
|
||||||
|
probe, slot.hash, msg);
|
||||||
|
|
||||||
|
let pos = self.indices[probe].unwrap();
|
||||||
|
|
||||||
|
let their_dist = probe_distance(self.mask, pos.hash, probe);
|
||||||
|
let real_idx = pos.index.wrapping_add(self.inserted);
|
||||||
|
|
||||||
|
if real_idx == index {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(dist <= their_dist,
|
||||||
|
"could not find entry; actual={}; desired={};" +
|
||||||
|
"probe={}, dist={}; their_dist={}; index={}; msg={}",
|
||||||
|
actual, desired, probe, dist, their_dist,
|
||||||
|
index.wrapping_sub(self.inserted), msg);
|
||||||
|
|
||||||
|
dist += 1;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// There is exactly one next link
|
||||||
|
let cnt = self.slots.iter().map(|s| s.next)
|
||||||
|
.filter(|n| *n == Some(index.wrapping_sub(self.inserted)))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
assert_eq!(1, cnt, "more than one node pointing here; msg={}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// TODO: Ensure linked lists are correct: no cycles, etc...
|
// TODO: Ensure linked lists are correct: no cycles, etc...
|
||||||
|
|
||||||
@@ -684,11 +681,13 @@ fn index_static(header: &Header) -> Option<(usize, bool)> {
|
|||||||
ref value,
|
ref value,
|
||||||
} => match *name {
|
} => match *name {
|
||||||
header::ACCEPT_CHARSET => Some((15, false)),
|
header::ACCEPT_CHARSET => Some((15, false)),
|
||||||
header::ACCEPT_ENCODING => if value == "gzip, deflate" {
|
header::ACCEPT_ENCODING => {
|
||||||
Some((16, true))
|
if value == "gzip, deflate" {
|
||||||
} else {
|
Some((16, true))
|
||||||
Some((16, false))
|
} else {
|
||||||
},
|
Some((16, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
header::ACCEPT_LANGUAGE => Some((17, false)),
|
header::ACCEPT_LANGUAGE => Some((17, false)),
|
||||||
header::ACCEPT_RANGES => Some((18, false)),
|
header::ACCEPT_RANGES => Some((18, false)),
|
||||||
header::ACCEPT => Some((19, false)),
|
header::ACCEPT => Some((19, false)),
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use hex::FromHex;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Cursor;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::io::Cursor;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
@@ -30,13 +30,15 @@ fn test_story(story: Value) {
|
|||||||
.map(|case| {
|
.map(|case| {
|
||||||
let case = case.as_object().unwrap();
|
let case = case.as_object().unwrap();
|
||||||
|
|
||||||
let size = case.get("header_table_size")
|
let size = case
|
||||||
|
.get("header_table_size")
|
||||||
.map(|v| v.as_u64().unwrap() as usize);
|
.map(|v| v.as_u64().unwrap() as usize);
|
||||||
|
|
||||||
let wire = case.get("wire").unwrap().as_str().unwrap();
|
let wire = case.get("wire").unwrap().as_str().unwrap();
|
||||||
let wire: Vec<u8> = FromHex::from_hex(wire.as_bytes()).unwrap();
|
let wire: Vec<u8> = FromHex::from_hex(wire.as_bytes()).unwrap();
|
||||||
|
|
||||||
let expect: Vec<_> = case.get("headers")
|
let expect: Vec<_> = case
|
||||||
|
.get("headers")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_array()
|
.as_array()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -92,7 +94,8 @@ fn test_story(story: Value) {
|
|||||||
decoder.queue_size_update(size);
|
decoder.queue_size_update(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut input: Vec<_> = case.expect
|
let mut input: Vec<_> = case
|
||||||
|
.expect
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(ref name, ref value)| {
|
.map(|&(ref name, ref value)| {
|
||||||
Header::new(name.clone().into(), value.clone().into())
|
Header::new(name.clone().into(), value.clone().into())
|
||||||
@@ -123,9 +126,7 @@ struct Case {
|
|||||||
|
|
||||||
fn key_str(e: &Header) -> &str {
|
fn key_str(e: &Header) -> &str {
|
||||||
match *e {
|
match *e {
|
||||||
Header::Field {
|
Header::Field { ref name, .. } => name.as_str(),
|
||||||
ref name, ..
|
|
||||||
} => name.as_str(),
|
|
||||||
Header::Authority(..) => ":authority",
|
Header::Authority(..) => ":authority",
|
||||||
Header::Method(..) => ":method",
|
Header::Method(..) => ":method",
|
||||||
Header::Scheme(..) => ":scheme",
|
Header::Scheme(..) => ":scheme",
|
||||||
@@ -136,9 +137,7 @@ fn key_str(e: &Header) -> &str {
|
|||||||
|
|
||||||
fn value_str(e: &Header) -> &str {
|
fn value_str(e: &Header) -> &str {
|
||||||
match *e {
|
match *e {
|
||||||
Header::Field {
|
Header::Field { ref value, .. } => value.to_str().unwrap(),
|
||||||
ref value, ..
|
|
||||||
} => value.to_str().unwrap(),
|
|
||||||
Header::Authority(ref v) => &**v,
|
Header::Authority(ref v) => &**v,
|
||||||
Header::Method(ref m) => m.as_str(),
|
Header::Method(ref m) => m.as_str(),
|
||||||
Header::Scheme(ref v) => &**v,
|
Header::Scheme(ref v) => &**v,
|
||||||
|
|||||||
@@ -78,17 +78,16 @@ impl FuzzHpack {
|
|||||||
let low = rng.gen_range(0, high);
|
let low = rng.gen_range(0, high);
|
||||||
|
|
||||||
frame.resizes.extend(&[low, high]);
|
frame.resizes.extend(&[low, high]);
|
||||||
},
|
}
|
||||||
1..=3 => {
|
1..=3 => {
|
||||||
frame.resizes.push(rng.gen_range(128, MAX_CHUNK * 2));
|
frame.resizes.push(rng.gen_range(128, MAX_CHUNK * 2));
|
||||||
},
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut is_name_required = true;
|
let mut is_name_required = true;
|
||||||
|
|
||||||
for _ in 0..rng.gen_range(1, (num - added) + 1) {
|
for _ in 0..rng.gen_range(1, (num - added) + 1) {
|
||||||
|
|
||||||
let x: f64 = rng.gen_range(0.0, 1.0);
|
let x: f64 = rng.gen_range(0.0, 1.0);
|
||||||
let x = x.powi(skew);
|
let x = x.powi(skew);
|
||||||
|
|
||||||
@@ -100,10 +99,10 @@ impl FuzzHpack {
|
|||||||
if is_name_required {
|
if is_name_required {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Header::Field { .. } => {
|
Header::Field { .. } => {
|
||||||
is_name_required = false;
|
is_name_required = false;
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// pseudos can't be followed by a header with no name
|
// pseudos can't be followed by a header with no name
|
||||||
is_name_required = true;
|
is_name_required = true;
|
||||||
@@ -153,7 +152,7 @@ impl FuzzHpack {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
expect.push(h);
|
expect.push(h);
|
||||||
},
|
}
|
||||||
Err(value) => {
|
Err(value) => {
|
||||||
expect.push(Header::Field {
|
expect.push(Header::Field {
|
||||||
name: prev_name.as_ref().cloned().expect("previous header name"),
|
name: prev_name.as_ref().cloned().expect("previous header name"),
|
||||||
@@ -161,7 +160,6 @@ impl FuzzHpack {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut input = frame.headers.into_iter();
|
let mut input = frame.headers.into_iter();
|
||||||
@@ -193,7 +191,7 @@ impl FuzzHpack {
|
|||||||
.expect("partial decode");
|
.expect("partial decode");
|
||||||
|
|
||||||
buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
|
buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +222,7 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
|||||||
0 => {
|
0 => {
|
||||||
let value = gen_string(g, 4, 20);
|
let value = gen_string(g, 4, 20);
|
||||||
Header::Authority(to_shared(value))
|
Header::Authority(to_shared(value))
|
||||||
},
|
}
|
||||||
1 => {
|
1 => {
|
||||||
let method = match g.next_u32() % 6 {
|
let method = match g.next_u32() % 6 {
|
||||||
0 => Method::GET,
|
0 => Method::GET,
|
||||||
@@ -239,12 +237,12 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Method::from_bytes(&bytes).unwrap()
|
Method::from_bytes(&bytes).unwrap()
|
||||||
},
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Header::Method(method)
|
Header::Method(method)
|
||||||
},
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let value = match g.next_u32() % 2 {
|
let value = match g.next_u32() % 2 {
|
||||||
0 => "http",
|
0 => "http",
|
||||||
@@ -253,7 +251,7 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Header::Scheme(to_shared(value.to_string()))
|
Header::Scheme(to_shared(value.to_string()))
|
||||||
},
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let value = match g.next_u32() % 100 {
|
let value = match g.next_u32() % 100 {
|
||||||
0 => "/".to_string(),
|
0 => "/".to_string(),
|
||||||
@@ -262,12 +260,12 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Header::Path(to_shared(value))
|
Header::Path(to_shared(value))
|
||||||
},
|
}
|
||||||
4 => {
|
4 => {
|
||||||
let status = (g.gen::<u16>() % 500) + 100;
|
let status = (g.gen::<u16>() % 500) + 100;
|
||||||
|
|
||||||
Header::Status(StatusCode::from_u16(status).unwrap())
|
Header::Status(StatusCode::from_u16(status).unwrap())
|
||||||
},
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -282,10 +280,7 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
|||||||
value.set_sensitive(true);
|
value.set_sensitive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Header::Field {
|
Header::Field { name, value }
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,8 +363,9 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
|
|||||||
header::X_DNS_PREFETCH_CONTROL,
|
header::X_DNS_PREFETCH_CONTROL,
|
||||||
header::X_FRAME_OPTIONS,
|
header::X_FRAME_OPTIONS,
|
||||||
header::X_XSS_PROTECTION,
|
header::X_XSS_PROTECTION,
|
||||||
]).unwrap()
|
])
|
||||||
.clone()
|
.unwrap()
|
||||||
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
let value = gen_string(g, 1, 25);
|
let value = gen_string(g, 1, 25);
|
||||||
HeaderName::from_bytes(value.as_bytes()).unwrap()
|
HeaderName::from_bytes(value.as_bytes()).unwrap()
|
||||||
|
|||||||
@@ -96,11 +96,11 @@ where
|
|||||||
Connection {
|
Connection {
|
||||||
state: State::Open,
|
state: State::Open,
|
||||||
error: None,
|
error: None,
|
||||||
codec: codec,
|
codec,
|
||||||
go_away: GoAway::new(),
|
go_away: GoAway::new(),
|
||||||
ping_pong: PingPong::new(),
|
ping_pong: PingPong::new(),
|
||||||
settings: Settings::new(),
|
settings: Settings::new(),
|
||||||
streams: streams,
|
streams,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,11 +210,11 @@ where
|
|||||||
// This will also handle flushing `self.codec`
|
// This will also handle flushing `self.codec`
|
||||||
ready!(self.streams.poll_complete(cx, &mut self.codec))?;
|
ready!(self.streams.poll_complete(cx, &mut self.codec))?;
|
||||||
|
|
||||||
if self.error.is_some() || self.go_away.should_close_on_idle() {
|
if (self.error.is_some() || self.go_away.should_close_on_idle())
|
||||||
if !self.streams.has_streams() {
|
&& !self.streams.has_streams()
|
||||||
self.go_away_now(Reason::NO_ERROR);
|
{
|
||||||
continue;
|
self.go_away_now(Reason::NO_ERROR);
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@@ -289,25 +289,22 @@ where
|
|||||||
// The order here matters:
|
// The order here matters:
|
||||||
// - poll_go_away may buffer a graceful shutdown GOAWAY frame
|
// - poll_go_away may buffer a graceful shutdown GOAWAY frame
|
||||||
// - If it has, we've also added a PING to be sent in poll_ready
|
// - If it has, we've also added a PING to be sent in poll_ready
|
||||||
match ready!(self.poll_go_away(cx)?) {
|
if let Some(reason) = ready!(self.poll_go_away(cx)?) {
|
||||||
Some(reason) => {
|
if self.go_away.should_close_now() {
|
||||||
if self.go_away.should_close_now() {
|
if self.go_away.is_user_initiated() {
|
||||||
if self.go_away.is_user_initiated() {
|
// A user initiated abrupt shutdown shouldn't return
|
||||||
// A user initiated abrupt shutdown shouldn't return
|
// the same error back to the user.
|
||||||
// the same error back to the user.
|
return Poll::Ready(Ok(()));
|
||||||
return Poll::Ready(Ok(()));
|
} else {
|
||||||
} else {
|
return Poll::Ready(Err(RecvError::Connection(reason)));
|
||||||
return Poll::Ready(Err(RecvError::Connection(reason)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Only NO_ERROR should be waiting for idle
|
|
||||||
debug_assert_eq!(
|
|
||||||
reason,
|
|
||||||
Reason::NO_ERROR,
|
|
||||||
"graceful GOAWAY should be NO_ERROR"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => (),
|
// Only NO_ERROR should be waiting for idle
|
||||||
|
debug_assert_eq!(
|
||||||
|
reason,
|
||||||
|
Reason::NO_ERROR,
|
||||||
|
"graceful GOAWAY should be NO_ERROR"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ready!(self.poll_ready(cx))?;
|
ready!(self.poll_ready(cx))?;
|
||||||
|
|
||||||
@@ -364,7 +361,7 @@ where
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::trace!("codec closed");
|
log::trace!("codec closed");
|
||||||
self.streams.recv_eof(false).ok().expect("mutex poisoned");
|
self.streams.recv_eof(false).expect("mutex poisoned");
|
||||||
return Poll::Ready(Ok(()));
|
return Poll::Ready(Ok(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ impl GoAway {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let reason = frame.reason();
|
let reason = frame.reason();
|
||||||
dst.buffer(frame.into()).ok().expect("invalid GOAWAY frame");
|
dst.buffer(frame.into()).expect("invalid GOAWAY frame");
|
||||||
|
|
||||||
return Poll::Ready(Some(Ok(reason)));
|
return Poll::Ready(Some(Ok(reason)));
|
||||||
} else if self.should_close_now() {
|
} else if self.should_close_now() {
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ pub(crate) trait Peer {
|
|||||||
fn is_server() -> bool;
|
fn is_server() -> bool;
|
||||||
|
|
||||||
fn convert_poll_message(
|
fn convert_poll_message(
|
||||||
pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId
|
pseudo: Pseudo,
|
||||||
|
fields: HeaderMap,
|
||||||
|
stream_id: StreamId,
|
||||||
) -> Result<Self::Poll, RecvError>;
|
) -> Result<Self::Poll, RecvError>;
|
||||||
|
|
||||||
fn is_local_init(id: StreamId) -> bool {
|
fn is_local_init(id: StreamId) -> bool {
|
||||||
@@ -54,7 +56,10 @@ impl Dyn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_poll_message(
|
pub fn convert_poll_message(
|
||||||
&self, pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId
|
&self,
|
||||||
|
pseudo: Pseudo,
|
||||||
|
fields: HeaderMap,
|
||||||
|
stream_id: StreamId,
|
||||||
) -> Result<PollMessage, RecvError> {
|
) -> Result<PollMessage, RecvError> {
|
||||||
if self.is_server() {
|
if self.is_server() {
|
||||||
crate::server::Peer::convert_poll_message(pseudo, fields, stream_id)
|
crate::server::Peer::convert_poll_message(pseudo, fields, stream_id)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::codec::RecvError;
|
use crate::codec::RecvError;
|
||||||
use crate::frame;
|
use crate::frame;
|
||||||
use crate::proto::*;
|
use crate::proto::*;
|
||||||
use std::task::{Poll, Context};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Settings {
|
pub(crate) struct Settings {
|
||||||
@@ -13,9 +13,7 @@ pub(crate) struct Settings {
|
|||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Settings {
|
Settings { pending: None }
|
||||||
pending: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_settings(&mut self, frame: frame::Settings) {
|
pub fn recv_settings(&mut self, frame: frame::Settings) {
|
||||||
@@ -52,9 +50,7 @@ impl Settings {
|
|||||||
let frame = frame::Settings::ack();
|
let frame = frame::Settings::ack();
|
||||||
|
|
||||||
// Buffer the settings frame
|
// Buffer the settings frame
|
||||||
dst.buffer(frame.into())
|
dst.buffer(frame.into()).expect("invalid settings frame");
|
||||||
.ok()
|
|
||||||
.expect("invalid settings frame");
|
|
||||||
|
|
||||||
log::trace!("ACK sent; applying settings");
|
log::trace!("ACK sent; applying settings");
|
||||||
|
|
||||||
|
|||||||
@@ -27,17 +27,13 @@ struct Slot<T> {
|
|||||||
|
|
||||||
impl<T> Buffer<T> {
|
impl<T> Buffer<T> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Buffer {
|
Buffer { slab: Slab::new() }
|
||||||
slab: Slab::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deque {
|
impl Deque {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Deque {
|
Deque { indices: None }
|
||||||
indices: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
@@ -45,42 +41,36 @@ impl Deque {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_back<T>(&mut self, buf: &mut Buffer<T>, value: T) {
|
pub fn push_back<T>(&mut self, buf: &mut Buffer<T>, value: T) {
|
||||||
let key = buf.slab.insert(Slot {
|
let key = buf.slab.insert(Slot { value, next: None });
|
||||||
value,
|
|
||||||
next: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
match self.indices {
|
match self.indices {
|
||||||
Some(ref mut idxs) => {
|
Some(ref mut idxs) => {
|
||||||
buf.slab[idxs.tail].next = Some(key);
|
buf.slab[idxs.tail].next = Some(key);
|
||||||
idxs.tail = key;
|
idxs.tail = key;
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
self.indices = Some(Indices {
|
self.indices = Some(Indices {
|
||||||
head: key,
|
head: key,
|
||||||
tail: key,
|
tail: key,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_front<T>(&mut self, buf: &mut Buffer<T>, value: T) {
|
pub fn push_front<T>(&mut self, buf: &mut Buffer<T>, value: T) {
|
||||||
let key = buf.slab.insert(Slot {
|
let key = buf.slab.insert(Slot { value, next: None });
|
||||||
value,
|
|
||||||
next: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
match self.indices {
|
match self.indices {
|
||||||
Some(ref mut idxs) => {
|
Some(ref mut idxs) => {
|
||||||
buf.slab[key].next = Some(idxs.head);
|
buf.slab[key].next = Some(idxs.head);
|
||||||
idxs.head = key;
|
idxs.head = key;
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
self.indices = Some(Indices {
|
self.indices = Some(Indices {
|
||||||
head: key,
|
head: key,
|
||||||
tail: key,
|
tail: key,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +87,8 @@ impl Deque {
|
|||||||
self.indices = Some(idxs);
|
self.indices = Some(idxs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(slot.value);
|
Some(slot.value)
|
||||||
},
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,16 +133,18 @@ impl Counts {
|
|||||||
|
|
||||||
// TODO: move this to macro?
|
// TODO: move this to macro?
|
||||||
pub fn transition_after(&mut self, mut stream: store::Ptr, is_reset_counted: bool) {
|
pub fn transition_after(&mut self, mut stream: store::Ptr, is_reset_counted: bool) {
|
||||||
log::trace!("transition_after; stream={:?}; state={:?}; is_closed={:?}; \
|
log::trace!(
|
||||||
pending_send_empty={:?}; buffered_send_data={}; \
|
"transition_after; stream={:?}; state={:?}; is_closed={:?}; \
|
||||||
num_recv={}; num_send={}",
|
pending_send_empty={:?}; buffered_send_data={}; \
|
||||||
stream.id,
|
num_recv={}; num_send={}",
|
||||||
stream.state,
|
stream.id,
|
||||||
stream.is_closed(),
|
stream.state,
|
||||||
stream.pending_send.is_empty(),
|
stream.is_closed(),
|
||||||
stream.buffered_send_data,
|
stream.pending_send.is_empty(),
|
||||||
self.num_recv_streams,
|
stream.buffered_send_data,
|
||||||
self.num_send_streams);
|
self.num_recv_streams,
|
||||||
|
self.num_send_streams
|
||||||
|
);
|
||||||
|
|
||||||
if stream.is_closed() {
|
if stream.is_closed() {
|
||||||
if !stream.is_pending_reset_expiration() {
|
if !stream.is_pending_reset_expiration() {
|
||||||
|
|||||||
@@ -200,7 +200,6 @@ impl PartialEq<WindowSize> for Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl PartialEq<Window> for WindowSize {
|
impl PartialEq<Window> for WindowSize {
|
||||||
fn eq(&self, other: &Window) -> bool {
|
fn eq(&self, other: &Window) -> bool {
|
||||||
other.eq(self)
|
other.eq(self)
|
||||||
@@ -227,7 +226,6 @@ impl PartialOrd<Window> for WindowSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ::std::ops::SubAssign<WindowSize> for Window {
|
impl ::std::ops::SubAssign<WindowSize> for Window {
|
||||||
fn sub_assign(&mut self, other: WindowSize) {
|
fn sub_assign(&mut self, other: WindowSize) {
|
||||||
self.0 -= other as i32;
|
self.0 -= other as i32;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ mod streams;
|
|||||||
pub(crate) use self::prioritize::Prioritized;
|
pub(crate) use self::prioritize::Prioritized;
|
||||||
pub(crate) use self::recv::Open;
|
pub(crate) use self::recv::Open;
|
||||||
pub(crate) use self::send::PollReset;
|
pub(crate) use self::send::PollReset;
|
||||||
pub(crate) use self::streams::{StreamRef, OpaqueStreamRef, Streams};
|
pub(crate) use self::streams::{OpaqueStreamRef, StreamRef, Streams};
|
||||||
|
|
||||||
use self::buffer::Buffer;
|
use self::buffer::Buffer;
|
||||||
use self::counts::Counts;
|
use self::counts::Counts;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
|
||||||
use super::store::Resolve;
|
use super::store::Resolve;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
use crate::frame::{Reason, StreamId};
|
use crate::frame::{Reason, StreamId};
|
||||||
|
|
||||||
@@ -8,9 +8,9 @@ use crate::codec::UserError::*;
|
|||||||
|
|
||||||
use bytes::buf::Take;
|
use bytes::buf::Take;
|
||||||
use futures::ready;
|
use futures::ready;
|
||||||
use std::{cmp, fmt, mem};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::task::{Context, Poll, Waker};
|
use std::task::{Context, Poll, Waker};
|
||||||
|
use std::{cmp, fmt, mem};
|
||||||
|
|
||||||
/// # Warning
|
/// # Warning
|
||||||
///
|
///
|
||||||
@@ -81,7 +81,6 @@ impl Prioritize {
|
|||||||
let mut flow = FlowControl::new();
|
let mut flow = FlowControl::new();
|
||||||
|
|
||||||
flow.inc_window(config.remote_init_window_sz)
|
flow.inc_window(config.remote_init_window_sz)
|
||||||
.ok()
|
|
||||||
.expect("invalid initial window size");
|
.expect("invalid initial window size");
|
||||||
|
|
||||||
flow.assign_capacity(config.remote_init_window_sz);
|
flow.assign_capacity(config.remote_init_window_sz);
|
||||||
@@ -92,7 +91,7 @@ impl 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(),
|
pending_open: store::Queue::new(),
|
||||||
flow: flow,
|
flow,
|
||||||
last_opened_id: StreamId::ZERO,
|
last_opened_id: StreamId::ZERO,
|
||||||
in_flight_data_frame: InFlightData::Nothing,
|
in_flight_data_frame: InFlightData::Nothing,
|
||||||
}
|
}
|
||||||
@@ -203,9 +202,7 @@ impl Prioritize {
|
|||||||
// The stream has no capacity to send the frame now, save it but
|
// The stream has no capacity to send the frame now, save it but
|
||||||
// don't notify the connection task. Once additional capacity
|
// don't notify the connection task. Once additional capacity
|
||||||
// becomes available, the frame will be flushed.
|
// becomes available, the frame will be flushed.
|
||||||
stream
|
stream.pending_send.push_back(buffer, frame.into());
|
||||||
.pending_send
|
|
||||||
.push_back(buffer, frame.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -216,7 +213,8 @@ impl Prioritize {
|
|||||||
&mut self,
|
&mut self,
|
||||||
capacity: WindowSize,
|
capacity: WindowSize,
|
||||||
stream: &mut store::Ptr,
|
stream: &mut store::Ptr,
|
||||||
counts: &mut Counts) {
|
counts: &mut Counts,
|
||||||
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"reserve_capacity; stream={:?}; requested={:?}; effective={:?}; curr={:?}",
|
"reserve_capacity; stream={:?}; requested={:?}; effective={:?}; curr={:?}",
|
||||||
stream.id,
|
stream.id,
|
||||||
@@ -338,8 +336,8 @@ impl Prioritize {
|
|||||||
&mut self,
|
&mut self,
|
||||||
inc: WindowSize,
|
inc: WindowSize,
|
||||||
store: &mut R,
|
store: &mut R,
|
||||||
counts: &mut Counts)
|
counts: &mut Counts,
|
||||||
where
|
) where
|
||||||
R: Resolve,
|
R: Resolve,
|
||||||
{
|
{
|
||||||
log::trace!("assign_connection_capacity; inc={}", inc);
|
log::trace!("assign_connection_capacity; inc={}", inc);
|
||||||
@@ -419,11 +417,7 @@ impl Prioritize {
|
|||||||
// TODO: Should prioritization factor into this?
|
// TODO: Should prioritization factor into this?
|
||||||
let assign = cmp::min(conn_available, additional);
|
let assign = cmp::min(conn_available, additional);
|
||||||
|
|
||||||
log::trace!(
|
log::trace!(" assigning; stream={:?}, capacity={}", stream.id, assign,);
|
||||||
" assigning; stream={:?}, capacity={}",
|
|
||||||
stream.id,
|
|
||||||
assign,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assign the capacity to the stream
|
// Assign the capacity to the stream
|
||||||
stream.assign_capacity(assign);
|
stream.assign_capacity(assign);
|
||||||
@@ -440,16 +434,16 @@ impl Prioritize {
|
|||||||
stream.send_flow.has_unavailable()
|
stream.send_flow.has_unavailable()
|
||||||
);
|
);
|
||||||
|
|
||||||
if stream.send_flow.available() < stream.requested_send_capacity {
|
if stream.send_flow.available() < stream.requested_send_capacity
|
||||||
if stream.send_flow.has_unavailable() {
|
&& stream.send_flow.has_unavailable()
|
||||||
// The stream requires additional capacity and the stream's
|
{
|
||||||
// window has available capacity, but the connection window
|
// The stream requires additional capacity and the stream's
|
||||||
// does not.
|
// window has available capacity, but the connection window
|
||||||
//
|
// does not.
|
||||||
// In this case, the stream needs to be queued up for when the
|
//
|
||||||
// connection has more capacity.
|
// In this case, the stream needs to be queued up for when the
|
||||||
self.pending_capacity.push(stream);
|
// connection has more capacity.
|
||||||
}
|
self.pending_capacity.push(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If data is buffered and the stream is not pending open, then
|
// If data is buffered and the stream is not pending open, then
|
||||||
@@ -515,26 +509,26 @@ impl Prioritize {
|
|||||||
if let Frame::Data(ref frame) = frame {
|
if let Frame::Data(ref frame) = frame {
|
||||||
self.in_flight_data_frame = InFlightData::DataFrame(frame.payload().stream);
|
self.in_flight_data_frame = InFlightData::DataFrame(frame.payload().stream);
|
||||||
}
|
}
|
||||||
dst.buffer(frame).ok().expect("invalid frame");
|
dst.buffer(frame).expect("invalid frame");
|
||||||
|
|
||||||
// Ensure the codec is ready to try the loop again.
|
// Ensure the codec is ready to try the loop again.
|
||||||
ready!(dst.poll_ready(cx))?;
|
ready!(dst.poll_ready(cx))?;
|
||||||
|
|
||||||
// Because, always try to reclaim...
|
// Because, always try to reclaim...
|
||||||
self.reclaim_frame(buffer, store, dst);
|
self.reclaim_frame(buffer, store, dst);
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
// Try to flush the codec.
|
// Try to flush the codec.
|
||||||
ready!(dst.flush(cx))?;
|
ready!(dst.flush(cx))?;
|
||||||
|
|
||||||
// This might release a data frame...
|
// This might release a data frame...
|
||||||
if !self.reclaim_frame(buffer, store, dst) {
|
if !self.reclaim_frame(buffer, store, dst) {
|
||||||
return Poll::Ready(Ok(()))
|
return Poll::Ready(Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to poll ready as poll_complete() does this for
|
// No need to poll ready as poll_complete() does this for
|
||||||
// us...
|
// us...
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -603,11 +597,12 @@ impl Prioritize {
|
|||||||
|
|
||||||
/// Push the frame to the front of the stream's deque, scheduling the
|
/// Push the frame to the front of the stream's deque, scheduling the
|
||||||
/// stream if needed.
|
/// stream if needed.
|
||||||
fn push_back_frame<B>(&mut self,
|
fn push_back_frame<B>(
|
||||||
frame: Frame<B>,
|
&mut self,
|
||||||
buffer: &mut Buffer<Frame<B>>,
|
frame: Frame<B>,
|
||||||
stream: &mut store::Ptr)
|
buffer: &mut Buffer<Frame<B>>,
|
||||||
{
|
stream: &mut store::Ptr,
|
||||||
|
) {
|
||||||
// Push the frame to the front of the stream's deque
|
// Push the frame to the front of the stream's deque
|
||||||
stream.pending_send.push_front(buffer, frame);
|
stream.pending_send.push_front(buffer, frame);
|
||||||
|
|
||||||
@@ -665,8 +660,11 @@ impl Prioritize {
|
|||||||
loop {
|
loop {
|
||||||
match self.pending_send.pop(store) {
|
match self.pending_send.pop(store) {
|
||||||
Some(mut stream) => {
|
Some(mut stream) => {
|
||||||
log::trace!("pop_frame; stream={:?}; stream.state={:?}",
|
log::trace!(
|
||||||
stream.id, stream.state);
|
"pop_frame; stream={:?}; stream.state={:?}",
|
||||||
|
stream.id,
|
||||||
|
stream.state
|
||||||
|
);
|
||||||
|
|
||||||
// It's possible that this stream, besides having data to send,
|
// It's possible that this stream, besides having data to send,
|
||||||
// is also queued to send a reset, and thus is already in the queue
|
// is also queued to send a reset, and thus is already in the queue
|
||||||
@@ -675,8 +673,11 @@ impl Prioritize {
|
|||||||
// To be safe, we just always ask the stream.
|
// To be safe, we just always ask the stream.
|
||||||
let is_pending_reset = stream.is_pending_reset_expiration();
|
let is_pending_reset = stream.is_pending_reset_expiration();
|
||||||
|
|
||||||
log::trace!(" --> stream={:?}; is_pending_reset={:?};",
|
log::trace!(
|
||||||
stream.id, is_pending_reset);
|
" --> stream={:?}; is_pending_reset={:?};",
|
||||||
|
stream.id,
|
||||||
|
is_pending_reset
|
||||||
|
);
|
||||||
|
|
||||||
let frame = match stream.pending_send.pop_front(buffer) {
|
let frame = match stream.pending_send.pop_front(buffer) {
|
||||||
Some(Frame::Data(mut frame)) => {
|
Some(Frame::Data(mut frame)) => {
|
||||||
@@ -715,9 +716,7 @@ impl Prioritize {
|
|||||||
// happen if the remote reduced the stream
|
// happen if the remote reduced the stream
|
||||||
// window. In this case, we need to buffer the
|
// window. In this case, we need to buffer the
|
||||||
// frame and wait for a window update...
|
// frame and wait for a window update...
|
||||||
stream
|
stream.pending_send.push_front(buffer, frame.into());
|
||||||
.pending_send
|
|
||||||
.push_front(buffer, frame.into());
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -726,7 +725,8 @@ impl Prioritize {
|
|||||||
let len = cmp::min(sz, max_len);
|
let len = cmp::min(sz, max_len);
|
||||||
|
|
||||||
// Only send up to the stream's window capacity
|
// Only send up to the stream's window capacity
|
||||||
let len = cmp::min(len, stream_capacity.as_size() as usize) as WindowSize;
|
let len =
|
||||||
|
cmp::min(len, stream_capacity.as_size() as usize) as WindowSize;
|
||||||
|
|
||||||
// There *must* be be enough connection level
|
// There *must* be be enough connection level
|
||||||
// capacity at this point.
|
// capacity at this point.
|
||||||
@@ -761,20 +761,18 @@ impl Prioritize {
|
|||||||
frame.set_end_stream(false);
|
frame.set_end_stream(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::Data(frame.map(|buf| {
|
Frame::Data(frame.map(|buf| Prioritized {
|
||||||
Prioritized {
|
inner: buf.take(len),
|
||||||
inner: buf.take(len),
|
end_of_stream: eos,
|
||||||
end_of_stream: eos,
|
stream: stream.key(),
|
||||||
stream: stream.key(),
|
|
||||||
}
|
|
||||||
}))
|
}))
|
||||||
},
|
}
|
||||||
Some(frame) => frame.map(|_|
|
Some(frame) => frame.map(|_| {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"Frame::map closure will only be called \
|
"Frame::map closure will only be called \
|
||||||
on DATA frames."
|
on DATA frames."
|
||||||
)
|
)
|
||||||
),
|
}),
|
||||||
None => {
|
None => {
|
||||||
if let Some(reason) = stream.state.get_scheduled_reset() {
|
if let Some(reason) = stream.state.get_scheduled_reset() {
|
||||||
stream.state.set_reset(reason);
|
stream.state.set_reset(reason);
|
||||||
@@ -814,7 +812,7 @@ impl Prioritize {
|
|||||||
counts.transition_after(stream, is_pending_reset);
|
counts.transition_after(stream, is_pending_reset);
|
||||||
|
|
||||||
return Some(frame);
|
return Some(frame);
|
||||||
},
|
}
|
||||||
None => return None,
|
None => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::task::Context;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{frame, proto};
|
|
||||||
use crate::codec::{RecvError, UserError};
|
use crate::codec::{RecvError, UserError};
|
||||||
use crate::frame::{Reason, DEFAULT_INITIAL_WINDOW_SIZE};
|
use crate::frame::{Reason, DEFAULT_INITIAL_WINDOW_SIZE};
|
||||||
|
use crate::{frame, proto};
|
||||||
|
use std::task::Context;
|
||||||
|
|
||||||
use http::{HeaderMap, Response, Request, Method};
|
|
||||||
use futures::ready;
|
use futures::ready;
|
||||||
|
use http::{HeaderMap, Method, Request, Response};
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
use std::task::{Poll, Waker};
|
use std::task::{Poll, Waker};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Recv {
|
pub(super) struct Recv {
|
||||||
@@ -98,7 +98,7 @@ impl Recv {
|
|||||||
|
|
||||||
Recv {
|
Recv {
|
||||||
init_window_sz: config.local_init_window_sz,
|
init_window_sz: config.local_init_window_sz,
|
||||||
flow: flow,
|
flow,
|
||||||
in_flight_data: 0 as WindowSize,
|
in_flight_data: 0 as WindowSize,
|
||||||
next_stream_id: Ok(next_stream_id.into()),
|
next_stream_id: Ok(next_stream_id.into()),
|
||||||
pending_window_updates: store::Queue::new(),
|
pending_window_updates: store::Queue::new(),
|
||||||
@@ -186,8 +186,9 @@ impl Recv {
|
|||||||
return Err(RecvError::Stream {
|
return Err(RecvError::Stream {
|
||||||
id: stream.id,
|
id: stream.id,
|
||||||
reason: Reason::PROTOCOL_ERROR,
|
reason: Reason::PROTOCOL_ERROR,
|
||||||
}.into())
|
}
|
||||||
},
|
.into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
stream.content_length = ContentLength::Remaining(content_length);
|
stream.content_length = ContentLength::Remaining(content_length);
|
||||||
@@ -215,7 +216,7 @@ impl Recv {
|
|||||||
let mut res = frame::Headers::new(
|
let mut res = frame::Headers::new(
|
||||||
stream.id,
|
stream.id,
|
||||||
frame::Pseudo::response(::http::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE),
|
frame::Pseudo::response(::http::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE),
|
||||||
HeaderMap::new()
|
HeaderMap::new(),
|
||||||
);
|
);
|
||||||
res.set_end_stream();
|
res.set_end_stream();
|
||||||
Err(RecvHeaderBlockError::Oversize(Some(res)))
|
Err(RecvHeaderBlockError::Oversize(Some(res)))
|
||||||
@@ -226,7 +227,9 @@ impl Recv {
|
|||||||
|
|
||||||
let stream_id = frame.stream_id();
|
let stream_id = frame.stream_id();
|
||||||
let (pseudo, fields) = frame.into_parts();
|
let (pseudo, fields) = frame.into_parts();
|
||||||
let message = counts.peer().convert_poll_message(pseudo, fields, stream_id)?;
|
let message = counts
|
||||||
|
.peer()
|
||||||
|
.convert_poll_message(pseudo, fields, stream_id)?;
|
||||||
|
|
||||||
// Push the frame onto the stream's recv buffer
|
// Push the frame onto the stream's recv buffer
|
||||||
stream
|
stream
|
||||||
@@ -246,9 +249,7 @@ impl Recv {
|
|||||||
/// Called by the server to get the request
|
/// Called by the server to get the request
|
||||||
///
|
///
|
||||||
/// TODO: Should this fn return `Result`?
|
/// TODO: Should this fn return `Result`?
|
||||||
pub fn take_request(&mut self, stream: &mut store::Ptr)
|
pub fn take_request(&mut self, stream: &mut store::Ptr) -> Request<()> {
|
||||||
-> Request<()>
|
|
||||||
{
|
|
||||||
use super::peer::PollMessage::*;
|
use super::peer::PollMessage::*;
|
||||||
|
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
@@ -261,20 +262,19 @@ impl Recv {
|
|||||||
pub fn poll_pushed(
|
pub fn poll_pushed(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &Context,
|
cx: &Context,
|
||||||
stream: &mut store::Ptr
|
stream: &mut store::Ptr,
|
||||||
) -> Poll<Option<Result<(Request<()>, store::Key), proto::Error>>> {
|
) -> Poll<Option<Result<(Request<()>, store::Key), proto::Error>>> {
|
||||||
use super::peer::PollMessage::*;
|
use super::peer::PollMessage::*;
|
||||||
|
|
||||||
let mut ppp = stream.pending_push_promises.take();
|
let mut ppp = stream.pending_push_promises.take();
|
||||||
let pushed = ppp.pop(stream.store_mut()).map(
|
let pushed = ppp.pop(stream.store_mut()).map(|mut pushed| {
|
||||||
|mut pushed| match pushed.pending_recv.pop_front(&mut self.buffer) {
|
match pushed.pending_recv.pop_front(&mut self.buffer) {
|
||||||
Some(Event::Headers(Server(headers))) =>
|
Some(Event::Headers(Server(headers))) => (headers, pushed.key()),
|
||||||
(headers, pushed.key()),
|
|
||||||
// When frames are pushed into the queue, it is verified that
|
// When frames are pushed into the queue, it is verified that
|
||||||
// the first frame is a HEADERS frame.
|
// the first frame is a HEADERS frame.
|
||||||
_ => panic!("Headers not set on pushed stream")
|
_ => panic!("Headers not set on pushed stream"),
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
stream.pending_push_promises = ppp;
|
stream.pending_push_promises = ppp;
|
||||||
if let Some(p) = pushed {
|
if let Some(p) = pushed {
|
||||||
Poll::Ready(Some(Ok(p)))
|
Poll::Ready(Some(Ok(p)))
|
||||||
@@ -301,14 +301,14 @@ impl Recv {
|
|||||||
// If the buffer is not empty, then the first frame must be a HEADERS
|
// If the buffer is not empty, then the first frame must be a HEADERS
|
||||||
// frame or the user violated the contract.
|
// frame or the user violated the contract.
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
Some(Event::Headers(Client(response))) => Poll::Ready(Ok(response.into())),
|
Some(Event::Headers(Client(response))) => Poll::Ready(Ok(response)),
|
||||||
Some(_) => panic!("poll_response called after response returned"),
|
Some(_) => panic!("poll_response called after response returned"),
|
||||||
None => {
|
None => {
|
||||||
stream.state.ensure_recv_open()?;
|
stream.state.ensure_recv_open()?;
|
||||||
|
|
||||||
stream.recv_task = Some(cx.waker().clone());
|
stream.recv_task = Some(cx.waker().clone());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,11 +341,7 @@ impl Recv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Releases capacity of the connection
|
/// Releases capacity of the connection
|
||||||
pub fn release_connection_capacity(
|
pub fn release_connection_capacity(&mut self, capacity: WindowSize, task: &mut Option<Waker>) {
|
||||||
&mut self,
|
|
||||||
capacity: WindowSize,
|
|
||||||
task: &mut Option<Waker>,
|
|
||||||
) {
|
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"release_connection_capacity; size={}, connection in_flight_data={}",
|
"release_connection_capacity; size={}, connection in_flight_data={}",
|
||||||
capacity,
|
capacity,
|
||||||
@@ -386,7 +382,6 @@ impl Recv {
|
|||||||
// Assign capacity to stream
|
// Assign capacity to stream
|
||||||
stream.recv_flow.assign_capacity(capacity);
|
stream.recv_flow.assign_capacity(capacity);
|
||||||
|
|
||||||
|
|
||||||
if stream.recv_flow.unclaimed_capacity().is_some() {
|
if stream.recv_flow.unclaimed_capacity().is_some() {
|
||||||
// Queue the stream for sending the WINDOW_UPDATE frame.
|
// Queue the stream for sending the WINDOW_UPDATE frame.
|
||||||
self.pending_window_updates.push(stream);
|
self.pending_window_updates.push(stream);
|
||||||
@@ -400,11 +395,7 @@ impl Recv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Release any unclaimed capacity for a closed stream.
|
/// Release any unclaimed capacity for a closed stream.
|
||||||
pub fn release_closed_capacity(
|
pub fn release_closed_capacity(&mut self, stream: &mut store::Ptr, task: &mut Option<Waker>) {
|
||||||
&mut self,
|
|
||||||
stream: &mut store::Ptr,
|
|
||||||
task: &mut Option<Waker>,
|
|
||||||
) {
|
|
||||||
debug_assert_eq!(stream.ref_count, 0);
|
debug_assert_eq!(stream.ref_count, 0);
|
||||||
|
|
||||||
if stream.in_flight_recv_data == 0 {
|
if stream.in_flight_recv_data == 0 {
|
||||||
@@ -417,10 +408,7 @@ impl Recv {
|
|||||||
stream.in_flight_recv_data,
|
stream.in_flight_recv_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.release_connection_capacity(
|
self.release_connection_capacity(stream.in_flight_recv_data, task);
|
||||||
stream.in_flight_recv_data,
|
|
||||||
task,
|
|
||||||
);
|
|
||||||
stream.in_flight_recv_data = 0;
|
stream.in_flight_recv_data = 0;
|
||||||
|
|
||||||
self.clear_recv_buffer(stream);
|
self.clear_recv_buffer(stream);
|
||||||
@@ -485,9 +473,7 @@ impl Recv {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream
|
stream.pending_recv.is_empty()
|
||||||
.pending_recv
|
|
||||||
.is_empty()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_data(
|
pub fn recv_data(
|
||||||
@@ -522,7 +508,6 @@ impl Recv {
|
|||||||
stream.recv_flow.window_size()
|
stream.recv_flow.window_size()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
if is_ignoring_frame {
|
if is_ignoring_frame {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"recv_data; frame ignored on locally reset {:?} for some time",
|
"recv_data; frame ignored on locally reset {:?} for some time",
|
||||||
@@ -609,7 +594,7 @@ impl Recv {
|
|||||||
// the capacity as available to be reclaimed. When the available
|
// the capacity as available to be reclaimed. When the available
|
||||||
// capacity meets a threshold, a WINDOW_UPDATE is then sent.
|
// capacity meets a threshold, a WINDOW_UPDATE is then sent.
|
||||||
self.release_connection_capacity(sz, &mut None);
|
self.release_connection_capacity(sz, &mut None);
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consume_connection_window(&mut self, sz: WindowSize) -> Result<(), RecvError> {
|
pub fn consume_connection_window(&mut self, sz: WindowSize) -> Result<(), RecvError> {
|
||||||
@@ -670,7 +655,7 @@ impl Recv {
|
|||||||
// MUST reset the promised stream with a stream error"
|
// MUST reset the promised stream with a stream error"
|
||||||
if let Some(content_length) = req.headers().get(header::CONTENT_LENGTH) {
|
if let Some(content_length) = req.headers().get(header::CONTENT_LENGTH) {
|
||||||
match parse_u64(content_length.as_bytes()) {
|
match parse_u64(content_length.as_bytes()) {
|
||||||
Ok(0) => {},
|
Ok(0) => {}
|
||||||
otherwise => {
|
otherwise => {
|
||||||
proto_err!(stream:
|
proto_err!(stream:
|
||||||
"recv_push_promise; promised request has content-length {:?}; promised_id={:?}",
|
"recv_push_promise; promised request has content-length {:?}; promised_id={:?}",
|
||||||
@@ -681,7 +666,7 @@ impl Recv {
|
|||||||
id: promised_id,
|
id: promised_id,
|
||||||
reason: Reason::PROTOCOL_ERROR,
|
reason: Reason::PROTOCOL_ERROR,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// "The server MUST include a method in the :method pseudo-header field
|
// "The server MUST include a method in the :method pseudo-header field
|
||||||
@@ -699,7 +684,9 @@ impl Recv {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
use super::peer::PollMessage::*;
|
use super::peer::PollMessage::*;
|
||||||
stream.pending_recv.push_back(&mut self.buffer, Event::Headers(Server(req)));
|
stream
|
||||||
|
.pending_recv
|
||||||
|
.push_back(&mut self.buffer, Event::Headers(Server(req)));
|
||||||
stream.notify_recv();
|
stream.notify_recv();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -707,14 +694,17 @@ impl Recv {
|
|||||||
fn safe_and_cacheable(method: &Method) -> bool {
|
fn safe_and_cacheable(method: &Method) -> bool {
|
||||||
// Cacheable: https://httpwg.org/specs/rfc7231.html#cacheable.methods
|
// Cacheable: https://httpwg.org/specs/rfc7231.html#cacheable.methods
|
||||||
// Safe: https://httpwg.org/specs/rfc7231.html#safe.methods
|
// Safe: https://httpwg.org/specs/rfc7231.html#safe.methods
|
||||||
return method == Method::GET || method == Method::HEAD;
|
method == Method::GET || method == Method::HEAD
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that `id` is not in the `Idle` state.
|
/// Ensures that `id` is not in the `Idle` state.
|
||||||
pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> {
|
pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> {
|
||||||
if let Ok(next) = self.next_stream_id {
|
if let Ok(next) = self.next_stream_id {
|
||||||
if id >= next {
|
if id >= next {
|
||||||
log::debug!("stream ID implicitly closed, PROTOCOL_ERROR; stream={:?}", id);
|
log::debug!(
|
||||||
|
"stream ID implicitly closed, PROTOCOL_ERROR; stream={:?}",
|
||||||
|
id
|
||||||
|
);
|
||||||
return Err(Reason::PROTOCOL_ERROR);
|
return Err(Reason::PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -726,7 +716,9 @@ impl Recv {
|
|||||||
/// Handle remote sending an explicit RST_STREAM.
|
/// Handle remote sending an explicit RST_STREAM.
|
||||||
pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream) {
|
pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream) {
|
||||||
// Notify the stream
|
// Notify the stream
|
||||||
stream.state.recv_reset(frame.reason(), stream.is_pending_send);
|
stream
|
||||||
|
.state
|
||||||
|
.recv_reset(frame.reason(), stream.is_pending_send);
|
||||||
|
|
||||||
stream.notify_send();
|
stream.notify_send();
|
||||||
stream.notify_recv();
|
stream.notify_recv();
|
||||||
@@ -777,10 +769,7 @@ impl Recv {
|
|||||||
pub fn may_have_created_stream(&self, id: StreamId) -> bool {
|
pub fn may_have_created_stream(&self, id: StreamId) -> bool {
|
||||||
if let Ok(next_id) = self.next_stream_id {
|
if let Ok(next_id) = self.next_stream_id {
|
||||||
// Peer::is_local_init should have been called beforehand
|
// Peer::is_local_init should have been called beforehand
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(id.is_server_initiated(), next_id.is_server_initiated(),);
|
||||||
id.is_server_initiated(),
|
|
||||||
next_id.is_server_initiated(),
|
|
||||||
);
|
|
||||||
id < next_id
|
id < next_id
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@@ -788,9 +777,7 @@ impl Recv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the remote peer can reserve a stream with the given ID.
|
/// Returns true if the remote peer can reserve a stream with the given ID.
|
||||||
pub fn ensure_can_reserve(&self)
|
pub fn ensure_can_reserve(&self) -> Result<(), RecvError> {
|
||||||
-> Result<(), RecvError>
|
|
||||||
{
|
|
||||||
if !self.is_push_enabled {
|
if !self.is_push_enabled {
|
||||||
proto_err!(conn: "recv_push_promise: push is disabled");
|
proto_err!(conn: "recv_push_promise: push is disabled");
|
||||||
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
|
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
|
||||||
@@ -800,11 +787,7 @@ impl Recv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a locally reset stream to queue to be eventually reaped.
|
/// Add a locally reset stream to queue to be eventually reaped.
|
||||||
pub fn enqueue_reset_expiration(
|
pub fn enqueue_reset_expiration(&mut self, stream: &mut store::Ptr, counts: &mut Counts) {
|
||||||
&mut self,
|
|
||||||
stream: &mut store::Ptr,
|
|
||||||
counts: &mut Counts,
|
|
||||||
) {
|
|
||||||
if !stream.state.is_local_reset() || stream.is_pending_reset_expiration() {
|
if !stream.state.is_local_reset() || stream.is_pending_reset_expiration() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -843,9 +826,7 @@ impl Recv {
|
|||||||
let frame = frame::Reset::new(stream_id, Reason::REFUSED_STREAM);
|
let frame = frame::Reset::new(stream_id, Reason::REFUSED_STREAM);
|
||||||
|
|
||||||
// Buffer the frame
|
// Buffer the frame
|
||||||
dst.buffer(frame.into())
|
dst.buffer(frame.into()).expect("invalid RST_STREAM frame");
|
||||||
.ok()
|
|
||||||
.expect("invalid RST_STREAM frame");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.refused = None;
|
self.refused = None;
|
||||||
@@ -864,11 +845,12 @@ impl Recv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_queues(&mut self,
|
pub fn clear_queues(
|
||||||
clear_pending_accept: bool,
|
&mut self,
|
||||||
store: &mut Store,
|
clear_pending_accept: bool,
|
||||||
counts: &mut Counts)
|
store: &mut Store,
|
||||||
{
|
counts: &mut Counts,
|
||||||
|
) {
|
||||||
self.clear_stream_window_update_queue(store, counts);
|
self.clear_stream_window_update_queue(store, counts);
|
||||||
self.clear_all_reset_streams(store, counts);
|
self.clear_all_reset_streams(store, counts);
|
||||||
|
|
||||||
@@ -921,7 +903,7 @@ impl Recv {
|
|||||||
/// Send connection level window update
|
/// Send connection level window update
|
||||||
fn send_connection_window_update<T, B>(
|
fn send_connection_window_update<T, B>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut Context,
|
cx: &mut Context,
|
||||||
dst: &mut Codec<T, Prioritized<B>>,
|
dst: &mut Codec<T, Prioritized<B>>,
|
||||||
) -> Poll<io::Result<()>>
|
) -> Poll<io::Result<()>>
|
||||||
where
|
where
|
||||||
@@ -936,13 +918,11 @@ impl Recv {
|
|||||||
|
|
||||||
// Buffer the WINDOW_UPDATE frame
|
// Buffer the WINDOW_UPDATE frame
|
||||||
dst.buffer(frame.into())
|
dst.buffer(frame.into())
|
||||||
.ok()
|
|
||||||
.expect("invalid WINDOW_UPDATE frame");
|
.expect("invalid WINDOW_UPDATE frame");
|
||||||
|
|
||||||
// Update flow control
|
// Update flow control
|
||||||
self.flow
|
self.flow
|
||||||
.inc_window(incr)
|
.inc_window(incr)
|
||||||
.ok()
|
|
||||||
.expect("unexpected flow control state");
|
.expect("unexpected flow control state");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,14 +972,12 @@ impl Recv {
|
|||||||
|
|
||||||
// Buffer it
|
// Buffer it
|
||||||
dst.buffer(frame.into())
|
dst.buffer(frame.into())
|
||||||
.ok()
|
|
||||||
.expect("invalid WINDOW_UPDATE frame");
|
.expect("invalid WINDOW_UPDATE frame");
|
||||||
|
|
||||||
// Update flow control
|
// Update flow control
|
||||||
stream
|
stream
|
||||||
.recv_flow
|
.recv_flow
|
||||||
.inc_window(incr)
|
.inc_window(incr)
|
||||||
.ok()
|
|
||||||
.expect("unexpected flow control state");
|
.expect("unexpected flow control state");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1010,7 +988,11 @@ impl Recv {
|
|||||||
self.pending_accept.pop(store).map(|ptr| ptr.key())
|
self.pending_accept.pop(store).map(|ptr| ptr.key())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_data(&mut self, cx: &Context, stream: &mut Stream) -> Poll<Option<Result<Bytes, proto::Error>>> {
|
pub fn poll_data(
|
||||||
|
&mut self,
|
||||||
|
cx: &Context,
|
||||||
|
stream: &mut Stream,
|
||||||
|
) -> Poll<Option<Result<Bytes, proto::Error>>> {
|
||||||
// TODO: Return error when the stream is reset
|
// TODO: Return error when the stream is reset
|
||||||
match stream.pending_recv.pop_front(&mut self.buffer) {
|
match stream.pending_recv.pop_front(&mut self.buffer) {
|
||||||
Some(Event::Data(payload)) => Poll::Ready(Some(Ok(payload))),
|
Some(Event::Data(payload)) => Poll::Ready(Some(Ok(payload))),
|
||||||
@@ -1030,7 +1012,7 @@ impl Recv {
|
|||||||
|
|
||||||
// No more data frames
|
// No more data frames
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
},
|
}
|
||||||
None => self.schedule_recv(cx, stream),
|
None => self.schedule_recv(cx, stream),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1047,12 +1029,16 @@ impl Recv {
|
|||||||
stream.pending_recv.push_front(&mut self.buffer, event);
|
stream.pending_recv.push_front(&mut self.buffer, event);
|
||||||
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
},
|
}
|
||||||
None => self.schedule_recv(cx, stream),
|
None => self.schedule_recv(cx, stream),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_recv<T>(&mut self, cx: &Context, stream: &mut Stream) -> Poll<Option<Result<T, proto::Error>>> {
|
fn schedule_recv<T>(
|
||||||
|
&mut self,
|
||||||
|
cx: &Context,
|
||||||
|
stream: &mut Stream,
|
||||||
|
) -> Poll<Option<Result<T, proto::Error>>> {
|
||||||
if stream.state.ensure_recv_open()? {
|
if stream.state.ensure_recv_open()? {
|
||||||
// Request to get notified once more frames arrive
|
// Request to get notified once more frames arrive
|
||||||
stream.recv_task = Some(cx.waker().clone());
|
stream.recv_task = Some(cx.waker().clone());
|
||||||
@@ -1112,7 +1098,7 @@ fn parse_u64(src: &[u8]) -> Result<u64, ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret *= 10;
|
ret *= 10;
|
||||||
ret += (d - b'0') as u64;
|
ret += u64::from(d - b'0');
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
|
|||||||
@@ -325,13 +325,7 @@ impl Send {
|
|||||||
if let Err(e) = self.prioritize.recv_stream_window_update(sz, stream) {
|
if let Err(e) = self.prioritize.recv_stream_window_update(sz, stream) {
|
||||||
log::debug!("recv_stream_window_update !!; err={:?}", e);
|
log::debug!("recv_stream_window_update !!; err={:?}", e);
|
||||||
|
|
||||||
self.send_reset(
|
self.send_reset(Reason::FLOW_CONTROL_ERROR, buffer, stream, counts, task);
|
||||||
Reason::FLOW_CONTROL_ERROR.into(),
|
|
||||||
buffer,
|
|
||||||
stream,
|
|
||||||
counts,
|
|
||||||
task,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use crate::codec::{RecvError, UserError};
|
|
||||||
use crate::codec::UserError::*;
|
use crate::codec::UserError::*;
|
||||||
|
use crate::codec::{RecvError, UserError};
|
||||||
use crate::frame::Reason;
|
use crate::frame::Reason;
|
||||||
use crate::proto::{self, PollReset};
|
use crate::proto::{self, PollReset};
|
||||||
|
|
||||||
@@ -94,37 +94,40 @@ impl State {
|
|||||||
let local = Streaming;
|
let local = Streaming;
|
||||||
|
|
||||||
self.inner = match self.inner {
|
self.inner = match self.inner {
|
||||||
Idle => if eos {
|
Idle => {
|
||||||
HalfClosedLocal(AwaitingHeaders)
|
if eos {
|
||||||
} else {
|
HalfClosedLocal(AwaitingHeaders)
|
||||||
Open {
|
} else {
|
||||||
local,
|
Open {
|
||||||
remote: AwaitingHeaders,
|
local,
|
||||||
|
remote: AwaitingHeaders,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Open {
|
Open {
|
||||||
local: AwaitingHeaders,
|
local: AwaitingHeaders,
|
||||||
remote,
|
remote,
|
||||||
} => if eos {
|
} => {
|
||||||
HalfClosedLocal(remote)
|
if eos {
|
||||||
} else {
|
HalfClosedLocal(remote)
|
||||||
Open {
|
} else {
|
||||||
local,
|
Open { local, remote }
|
||||||
remote,
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
HalfClosedRemote(AwaitingHeaders) => if eos {
|
HalfClosedRemote(AwaitingHeaders) => {
|
||||||
Closed(Cause::EndStream)
|
if eos {
|
||||||
} else {
|
Closed(Cause::EndStream)
|
||||||
HalfClosedRemote(local)
|
} else {
|
||||||
},
|
HalfClosedRemote(local)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// All other transitions result in a protocol error
|
// All other transitions result in a protocol error
|
||||||
return Err(UnexpectedFrameType);
|
return Err(UnexpectedFrameType);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens the receive-half of the stream when a HEADERS frame is received.
|
/// Opens the receive-half of the stream when a HEADERS frame is received.
|
||||||
@@ -146,7 +149,7 @@ impl State {
|
|||||||
remote,
|
remote,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ReservedRemote => {
|
ReservedRemote => {
|
||||||
initial = true;
|
initial = true;
|
||||||
|
|
||||||
@@ -155,31 +158,32 @@ impl State {
|
|||||||
} else {
|
} else {
|
||||||
HalfClosedLocal(Streaming)
|
HalfClosedLocal(Streaming)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Open {
|
Open {
|
||||||
local,
|
local,
|
||||||
remote: AwaitingHeaders,
|
remote: AwaitingHeaders,
|
||||||
} => if eos {
|
} => {
|
||||||
HalfClosedRemote(local)
|
if eos {
|
||||||
} else {
|
HalfClosedRemote(local)
|
||||||
Open {
|
} else {
|
||||||
local,
|
Open { local, remote }
|
||||||
remote,
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
HalfClosedLocal(AwaitingHeaders) => if eos {
|
HalfClosedLocal(AwaitingHeaders) => {
|
||||||
Closed(Cause::EndStream)
|
if eos {
|
||||||
} else {
|
Closed(Cause::EndStream)
|
||||||
HalfClosedLocal(remote)
|
} else {
|
||||||
},
|
HalfClosedLocal(remote)
|
||||||
|
}
|
||||||
|
}
|
||||||
state => {
|
state => {
|
||||||
// All other transitions result in a protocol error
|
// All other transitions result in a protocol error
|
||||||
proto_err!(conn: "recv_open: in unexpected state {:?}", state);
|
proto_err!(conn: "recv_open: in unexpected state {:?}", state);
|
||||||
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
|
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(initial);
|
Ok(initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transition from Idle -> ReservedRemote
|
/// Transition from Idle -> ReservedRemote
|
||||||
@@ -188,7 +192,7 @@ impl State {
|
|||||||
Idle => {
|
Idle => {
|
||||||
self.inner = ReservedRemote;
|
self.inner = ReservedRemote;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
state => {
|
state => {
|
||||||
proto_err!(conn: "reserve_remote: in unexpected state {:?}", state);
|
proto_err!(conn: "reserve_remote: in unexpected state {:?}", state);
|
||||||
Err(RecvError::Connection(Reason::PROTOCOL_ERROR))
|
Err(RecvError::Connection(Reason::PROTOCOL_ERROR))
|
||||||
@@ -199,19 +203,17 @@ 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<(), RecvError> {
|
pub fn recv_close(&mut self) -> Result<(), RecvError> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open {
|
Open { local, .. } => {
|
||||||
local, ..
|
|
||||||
} => {
|
|
||||||
// The remote side will continue to receive data.
|
// The remote side will continue to receive data.
|
||||||
log::trace!("recv_close: Open => HalfClosedRemote({:?})", local);
|
log::trace!("recv_close: Open => HalfClosedRemote({:?})", local);
|
||||||
self.inner = HalfClosedRemote(local);
|
self.inner = HalfClosedRemote(local);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
HalfClosedLocal(..) => {
|
HalfClosedLocal(..) => {
|
||||||
log::trace!("recv_close: HalfClosedLocal => Closed");
|
log::trace!("recv_close: HalfClosedLocal => Closed");
|
||||||
self.inner = Closed(Cause::EndStream);
|
self.inner = Closed(Cause::EndStream);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
state => {
|
state => {
|
||||||
proto_err!(conn: "recv_close: in unexpected state {:?}", state);
|
proto_err!(conn: "recv_close: in unexpected state {:?}", state);
|
||||||
Err(RecvError::Connection(Reason::PROTOCOL_ERROR))
|
Err(RecvError::Connection(Reason::PROTOCOL_ERROR))
|
||||||
@@ -228,7 +230,7 @@ impl State {
|
|||||||
match self.inner {
|
match self.inner {
|
||||||
// If the stream is already in a `Closed` state, do nothing,
|
// If the stream is already in a `Closed` state, do nothing,
|
||||||
// provided that there are no frames still in the send queue.
|
// provided that there are no frames still in the send queue.
|
||||||
Closed(..) if !queued => {},
|
Closed(..) if !queued => {}
|
||||||
// A notionally `Closed` stream may still have queued frames in
|
// A notionally `Closed` stream may still have queued frames in
|
||||||
// the following cases:
|
// the following cases:
|
||||||
//
|
//
|
||||||
@@ -246,11 +248,12 @@ impl State {
|
|||||||
state => {
|
state => {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"recv_reset; reason={:?}; state={:?}; queued={:?}",
|
"recv_reset; reason={:?}; state={:?}; queued={:?}",
|
||||||
reason, state, queued
|
reason,
|
||||||
|
state,
|
||||||
|
queued
|
||||||
);
|
);
|
||||||
self.inner = Closed(Cause::Proto(reason));
|
self.inner = Closed(Cause::Proto(reason));
|
||||||
},
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,20 +262,20 @@ impl State {
|
|||||||
use crate::proto::Error::*;
|
use crate::proto::Error::*;
|
||||||
|
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Closed(..) => {},
|
Closed(..) => {}
|
||||||
_ => {
|
_ => {
|
||||||
log::trace!("recv_err; err={:?}", err);
|
log::trace!("recv_err; err={:?}", err);
|
||||||
self.inner = Closed(match *err {
|
self.inner = Closed(match *err {
|
||||||
Proto(reason) => Cause::LocallyReset(reason),
|
Proto(reason) => Cause::LocallyReset(reason),
|
||||||
Io(..) => Cause::Io,
|
Io(..) => Cause::Io,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_eof(&mut self) {
|
pub fn recv_eof(&mut self) {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Closed(..) => {},
|
Closed(..) => {}
|
||||||
s => {
|
s => {
|
||||||
log::trace!("recv_eof; state={:?}", s);
|
log::trace!("recv_eof; state={:?}", s);
|
||||||
self.inner = Closed(Cause::Io);
|
self.inner = Closed(Cause::Io);
|
||||||
@@ -283,17 +286,15 @@ impl State {
|
|||||||
/// Indicates that the local side will not send more data to the local.
|
/// Indicates that the local side will not send more data to the local.
|
||||||
pub fn send_close(&mut self) {
|
pub fn send_close(&mut self) {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open {
|
Open { remote, .. } => {
|
||||||
remote, ..
|
|
||||||
} => {
|
|
||||||
// The remote side will continue to receive data.
|
// The remote side will continue to receive data.
|
||||||
log::trace!("send_close: Open => HalfClosedLocal({:?})", remote);
|
log::trace!("send_close: Open => HalfClosedLocal({:?})", remote);
|
||||||
self.inner = HalfClosedLocal(remote);
|
self.inner = HalfClosedLocal(remote);
|
||||||
},
|
}
|
||||||
HalfClosedRemote(..) => {
|
HalfClosedRemote(..) => {
|
||||||
log::trace!("send_close: HalfClosedRemote => Closed");
|
log::trace!("send_close: HalfClosedRemote => Closed");
|
||||||
self.inner = Closed(Cause::EndStream);
|
self.inner = Closed(Cause::EndStream);
|
||||||
},
|
}
|
||||||
state => panic!("send_close: unexpected state {:?}", state),
|
state => panic!("send_close: unexpected state {:?}", state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,8 +344,7 @@ impl State {
|
|||||||
pub fn is_send_streaming(&self) -> bool {
|
pub fn is_send_streaming(&self) -> bool {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open {
|
Open {
|
||||||
local: Streaming,
|
local: Streaming, ..
|
||||||
..
|
|
||||||
} => true,
|
} => true,
|
||||||
HalfClosedRemote(Streaming) => true,
|
HalfClosedRemote(Streaming) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -368,8 +368,7 @@ impl State {
|
|||||||
pub fn is_recv_streaming(&self) -> bool {
|
pub fn is_recv_streaming(&self) -> bool {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Open {
|
Open {
|
||||||
remote: Streaming,
|
remote: Streaming, ..
|
||||||
..
|
|
||||||
} => true,
|
} => true,
|
||||||
HalfClosedLocal(Streaming) => true,
|
HalfClosedLocal(Streaming) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -407,12 +406,11 @@ impl State {
|
|||||||
pub fn ensure_recv_open(&self) -> Result<bool, proto::Error> {
|
pub fn ensure_recv_open(&self) -> Result<bool, proto::Error> {
|
||||||
// TODO: Is this correct?
|
// TODO: Is this correct?
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Closed(Cause::Proto(reason)) |
|
Closed(Cause::Proto(reason))
|
||||||
Closed(Cause::LocallyReset(reason)) |
|
| Closed(Cause::LocallyReset(reason))
|
||||||
Closed(Cause::Scheduled(reason)) => Err(proto::Error::Proto(reason)),
|
| Closed(Cause::Scheduled(reason)) => Err(proto::Error::Proto(reason)),
|
||||||
Closed(Cause::Io) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())),
|
Closed(Cause::Io) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())),
|
||||||
Closed(Cause::EndStream) |
|
Closed(Cause::EndStream) | HalfClosedRemote(..) => Ok(false),
|
||||||
HalfClosedRemote(..) => Ok(false),
|
|
||||||
_ => Ok(true),
|
_ => Ok(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,15 +418,15 @@ impl State {
|
|||||||
/// Returns a reason if the stream has been reset.
|
/// Returns a reason if the stream has been reset.
|
||||||
pub(super) fn ensure_reason(&self, mode: PollReset) -> Result<Option<Reason>, crate::Error> {
|
pub(super) fn ensure_reason(&self, mode: PollReset) -> Result<Option<Reason>, crate::Error> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Closed(Cause::Proto(reason)) |
|
Closed(Cause::Proto(reason))
|
||||||
Closed(Cause::LocallyReset(reason)) |
|
| Closed(Cause::LocallyReset(reason))
|
||||||
Closed(Cause::Scheduled(reason)) => Ok(Some(reason)),
|
| Closed(Cause::Scheduled(reason)) => Ok(Some(reason)),
|
||||||
Closed(Cause::Io) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into()).into()),
|
Closed(Cause::Io) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into()).into()),
|
||||||
Open { local: Streaming, .. } |
|
Open {
|
||||||
HalfClosedRemote(Streaming) => match mode {
|
local: Streaming, ..
|
||||||
PollReset::AwaitingHeaders => {
|
}
|
||||||
Err(UserError::PollResetAfterSendResponse.into())
|
| HalfClosedRemote(Streaming) => match mode {
|
||||||
},
|
PollReset::AwaitingHeaders => Err(UserError::PollResetAfterSendResponse.into()),
|
||||||
PollReset::Streaming => Ok(None),
|
PollReset::Streaming => Ok(None),
|
||||||
},
|
},
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
@@ -438,9 +436,7 @@ impl State {
|
|||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> State {
|
fn default() -> State {
|
||||||
State {
|
State { inner: Inner::Idle }
|
||||||
inner: Inner::Idle,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,9 +118,7 @@ impl Store {
|
|||||||
use self::indexmap::map::Entry::*;
|
use self::indexmap::map::Entry::*;
|
||||||
|
|
||||||
match self.ids.entry(id) {
|
match self.ids.entry(id) {
|
||||||
Occupied(e) => Entry::Occupied(OccupiedEntry {
|
Occupied(e) => Entry::Occupied(OccupiedEntry { ids: e }),
|
||||||
ids: e,
|
|
||||||
}),
|
|
||||||
Vacant(e) => Entry::Vacant(VacantEntry {
|
Vacant(e) => Entry::Vacant(VacantEntry {
|
||||||
ids: e,
|
ids: e,
|
||||||
slab: &mut self.slab,
|
slab: &mut self.slab,
|
||||||
@@ -143,10 +141,7 @@ impl Store {
|
|||||||
};
|
};
|
||||||
|
|
||||||
f(Ptr {
|
f(Ptr {
|
||||||
key: Key {
|
key: Key { index, stream_id },
|
||||||
index,
|
|
||||||
stream_id,
|
|
||||||
},
|
|
||||||
store: self,
|
store: self,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -167,10 +162,7 @@ impl Store {
|
|||||||
|
|
||||||
impl Resolve for Store {
|
impl Resolve for Store {
|
||||||
fn resolve(&mut self, key: Key) -> Ptr {
|
fn resolve(&mut self, key: Key) -> Ptr {
|
||||||
Ptr {
|
Ptr { key, store: self }
|
||||||
key: key,
|
|
||||||
store: self,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,14 +259,14 @@ where
|
|||||||
|
|
||||||
// Update the tail pointer
|
// Update the tail pointer
|
||||||
idxs.tail = stream.key();
|
idxs.tail = stream.key();
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
log::trace!(" -> first entry");
|
log::trace!(" -> first entry");
|
||||||
self.indices = Some(store::Indices {
|
self.indices = Some(store::Indices {
|
||||||
head: stream.key(),
|
head: stream.key(),
|
||||||
tail: stream.key(),
|
tail: stream.key(),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -356,7 +348,7 @@ impl<'a> Ptr<'a> {
|
|||||||
impl<'a> Resolve for Ptr<'a> {
|
impl<'a> Resolve for Ptr<'a> {
|
||||||
fn resolve(&mut self, key: Key) -> Ptr {
|
fn resolve(&mut self, key: Key) -> Ptr {
|
||||||
Ptr {
|
Ptr {
|
||||||
key: key,
|
key,
|
||||||
store: &mut *self.store,
|
store: &mut *self.store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,10 +380,7 @@ impl<'a> OccupiedEntry<'a> {
|
|||||||
pub fn key(&self) -> Key {
|
pub fn key(&self) -> Key {
|
||||||
let stream_id = *self.ids.key();
|
let stream_id = *self.ids.key();
|
||||||
let index = *self.ids.get();
|
let index = *self.ids.get();
|
||||||
Key {
|
Key { index, stream_id }
|
||||||
index,
|
|
||||||
stream_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,9 +395,6 @@ impl<'a> VacantEntry<'a> {
|
|||||||
// Insert the handle in the ID map
|
// Insert the handle in the ID map
|
||||||
self.ids.insert(index);
|
self.ids.insert(index);
|
||||||
|
|
||||||
Key {
|
Key { index, stream_id }
|
||||||
index,
|
|
||||||
stream_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use std::task::{Context, Waker};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
use std::task::{Context, Waker};
|
|
||||||
|
|
||||||
/// Tracks Stream related state
|
/// Tracks Stream related state
|
||||||
///
|
///
|
||||||
@@ -133,23 +133,17 @@ pub(super) struct NextOpen;
|
|||||||
pub(super) struct NextResetExpire;
|
pub(super) struct NextResetExpire;
|
||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
pub fn new(
|
pub fn new(id: StreamId, init_send_window: WindowSize, init_recv_window: WindowSize) -> Stream {
|
||||||
id: StreamId,
|
|
||||||
init_send_window: WindowSize,
|
|
||||||
init_recv_window: WindowSize,
|
|
||||||
) -> Stream {
|
|
||||||
let mut send_flow = FlowControl::new();
|
let mut send_flow = FlowControl::new();
|
||||||
let mut recv_flow = FlowControl::new();
|
let mut recv_flow = FlowControl::new();
|
||||||
|
|
||||||
recv_flow
|
recv_flow
|
||||||
.inc_window(init_recv_window)
|
.inc_window(init_recv_window)
|
||||||
.ok()
|
|
||||||
.expect("invalid initial receive window");
|
.expect("invalid initial receive window");
|
||||||
recv_flow.assign_capacity(init_recv_window);
|
recv_flow.assign_capacity(init_recv_window);
|
||||||
|
|
||||||
send_flow
|
send_flow
|
||||||
.inc_window(init_send_window)
|
.inc_window(init_send_window)
|
||||||
.ok()
|
|
||||||
.expect("invalid initial send window size");
|
.expect("invalid initial send window size");
|
||||||
|
|
||||||
Stream {
|
Stream {
|
||||||
@@ -161,7 +155,7 @@ impl Stream {
|
|||||||
// ===== Fields related to sending =====
|
// ===== Fields related to sending =====
|
||||||
next_pending_send: None,
|
next_pending_send: None,
|
||||||
is_pending_send: false,
|
is_pending_send: false,
|
||||||
send_flow: send_flow,
|
send_flow,
|
||||||
requested_send_capacity: 0,
|
requested_send_capacity: 0,
|
||||||
buffered_send_data: 0,
|
buffered_send_data: 0,
|
||||||
send_task: None,
|
send_task: None,
|
||||||
@@ -175,7 +169,7 @@ impl Stream {
|
|||||||
// ===== Fields related to receiving =====
|
// ===== Fields related to receiving =====
|
||||||
next_pending_accept: None,
|
next_pending_accept: None,
|
||||||
is_pending_accept: false,
|
is_pending_accept: false,
|
||||||
recv_flow: recv_flow,
|
recv_flow,
|
||||||
in_flight_recv_data: 0,
|
in_flight_recv_data: 0,
|
||||||
next_window_update: None,
|
next_window_update: None,
|
||||||
is_pending_window_update: false,
|
is_pending_window_update: false,
|
||||||
@@ -247,8 +241,12 @@ impl Stream {
|
|||||||
self.send_capacity_inc = true;
|
self.send_capacity_inc = true;
|
||||||
self.send_flow.assign_capacity(capacity);
|
self.send_flow.assign_capacity(capacity);
|
||||||
|
|
||||||
log::trace!(" assigned capacity to stream; available={}; buffered={}; id={:?}",
|
log::trace!(
|
||||||
self.send_flow.available(), self.buffered_send_data, self.id);
|
" assigned capacity to stream; available={}; buffered={}; id={:?}",
|
||||||
|
self.send_flow.available(),
|
||||||
|
self.buffered_send_data,
|
||||||
|
self.id
|
||||||
|
);
|
||||||
|
|
||||||
// Only notify if the capacity exceeds the amount of buffered data
|
// Only notify if the capacity exceeds the amount of buffered data
|
||||||
if self.send_flow.available() > self.buffered_send_data {
|
if self.send_flow.available() > self.buffered_send_data {
|
||||||
@@ -265,7 +263,7 @@ impl Stream {
|
|||||||
None => return Err(()),
|
None => return Err(()),
|
||||||
},
|
},
|
||||||
ContentLength::Head => return Err(()),
|
ContentLength::Head => return Err(()),
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -465,13 +465,10 @@ where
|
|||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
// Always try to advance the internal state. Getting Pending also is
|
// Always try to advance the internal state. Getting Pending also is
|
||||||
// needed to allow this function to return Pending.
|
// needed to allow this function to return Pending.
|
||||||
match self.poll_close(cx)? {
|
if let Poll::Ready(_) = self.poll_close(cx)? {
|
||||||
Poll::Ready(_) => {
|
// If the socket is closed, don't return anything
|
||||||
// If the socket is closed, don't return anything
|
// TODO: drop any pending streams
|
||||||
// TODO: drop any pending streams
|
return Poll::Ready(None);
|
||||||
return Poll::Ready(None);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(inner) = self.connection.next_incoming() {
|
if let Some(inner) = self.connection.next_incoming() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bytes::IntoBuf;
|
use bytes::IntoBuf;
|
||||||
use http::Request;
|
|
||||||
use h2::client::{ResponseFuture, SendRequest};
|
use h2::client::{ResponseFuture, SendRequest};
|
||||||
|
use http::Request;
|
||||||
|
|
||||||
/// Extend the `h2::client::SendRequest` type with convenience methods.
|
/// Extend the `h2::client::SendRequest` type with convenience methods.
|
||||||
pub trait SendRequestExt {
|
pub trait SendRequestExt {
|
||||||
@@ -22,7 +22,7 @@ where
|
|||||||
.expect("valid uri");
|
.expect("valid uri");
|
||||||
|
|
||||||
let (fut, _tx) = self
|
let (fut, _tx) = self
|
||||||
.send_request(req, /*eos =*/true)
|
.send_request(req, /*eos =*/ true)
|
||||||
.expect("send_request");
|
.expect("send_request");
|
||||||
|
|
||||||
fut
|
fut
|
||||||
|
|||||||
@@ -137,8 +137,7 @@ impl Mock<frame::Headers> {
|
|||||||
Mock(frame)
|
Mock(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scheme(self, value: &str) -> Self
|
pub fn scheme(self, value: &str) -> Self {
|
||||||
{
|
|
||||||
let (id, mut pseudo, fields) = self.into_parts();
|
let (id, mut pseudo, fields) = self.into_parts();
|
||||||
let value = value.parse().unwrap();
|
let value = value.parse().unwrap();
|
||||||
|
|
||||||
@@ -206,7 +205,6 @@ impl From<Mock<frame::Data>> for SendFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PushPromise helpers
|
// PushPromise helpers
|
||||||
|
|
||||||
impl Mock<frame::PushPromise> {
|
impl Mock<frame::PushPromise> {
|
||||||
@@ -240,7 +238,6 @@ impl Mock<frame::PushPromise> {
|
|||||||
Mock(frame)
|
Mock(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn into_parts(self) -> (StreamId, StreamId, frame::Pseudo, HeaderMap) {
|
fn into_parts(self) -> (StreamId, StreamId, frame::Pseudo, HeaderMap) {
|
||||||
assert!(self.0.is_end_headers(), "unset eoh will be lost");
|
assert!(self.0.is_end_headers(), "unset eoh will be lost");
|
||||||
let id = self.0.stream_id();
|
let id = self.0.stream_id();
|
||||||
@@ -280,10 +277,7 @@ impl Mock<frame::GoAway> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reason(self, reason: frame::Reason) -> Self {
|
pub fn reason(self, reason: frame::Reason) -> Self {
|
||||||
Mock(frame::GoAway::new(
|
Mock(frame::GoAway::new(self.0.last_stream_id(), reason))
|
||||||
self.0.last_stream_id(),
|
|
||||||
reason,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<_> = env::args().collect();
|
let args: Vec<_> = env::args().collect();
|
||||||
@@ -30,7 +30,9 @@ fn main() {
|
|||||||
// Now, split that into the group and the name
|
// Now, split that into the group and the name
|
||||||
let module = fixture_path.split("/").next().unwrap();
|
let module = fixture_path.split("/").next().unwrap();
|
||||||
|
|
||||||
tests.entry(module.to_string()).or_insert(vec![])
|
tests
|
||||||
|
.entry(module.to_string())
|
||||||
|
.or_insert(vec![])
|
||||||
.push(fixture_path.to_string());
|
.push(fixture_path.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +51,7 @@ fn main() {
|
|||||||
println!(" {} => {{", module);
|
println!(" {} => {{", module);
|
||||||
|
|
||||||
for test in tests {
|
for test in tests {
|
||||||
let ident = test
|
let ident = test.split("/").nth(1).unwrap().split(".").next().unwrap();
|
||||||
.split("/").nth(1).unwrap()
|
|
||||||
.split(".").next().unwrap();
|
|
||||||
|
|
||||||
println!(" ({}, {:?});", ident, test);
|
println!(" ({}, {:?});", ident, test);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,18 +98,17 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_transition(&self,
|
fn compute_transition(
|
||||||
byte: Option<usize>,
|
&self,
|
||||||
start: &Node,
|
byte: Option<usize>,
|
||||||
root: &Node,
|
start: &Node,
|
||||||
steps_remaining: usize)
|
root: &Node,
|
||||||
{
|
steps_remaining: usize,
|
||||||
|
) {
|
||||||
if steps_remaining == 0 {
|
if steps_remaining == 0 {
|
||||||
let (byte, target) = match byte {
|
let (byte, target) = match byte {
|
||||||
Some(256) => (None, None),
|
Some(256) => (None, None),
|
||||||
_ => {
|
_ => (byte, Some(self.id.unwrap_or(0))),
|
||||||
(byte, Some(self.id.unwrap_or(0)))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
start.transitions.borrow_mut().push(Transition {
|
start.transitions.borrow_mut().push(Transition {
|
||||||
@@ -257,8 +256,6 @@ pub fn main() {
|
|||||||
println!("];");
|
println!("];");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const TABLE: &'static str = r##"
|
const TABLE: &'static str = r##"
|
||||||
( 0) |11111111|11000 1ff8 [13]
|
( 0) |11111111|11000 1ff8 [13]
|
||||||
( 1) |11111111|11111111|1011000 7fffd8 [23]
|
( 1) |11111111|11111111|1011000 7fffd8 [23]
|
||||||
|
|||||||
Reference in New Issue
Block a user