Bunch of work
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
use frame::{util, Head, Error, StreamId};
|
use frame::{util, Head, Error, StreamId, Kind};
|
||||||
use bytes::Bytes;
|
use bytes::{BufMut, Bytes};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
data: Bytes,
|
data: Bytes,
|
||||||
@@ -33,6 +34,23 @@ impl Data {
|
|||||||
pad_len: pad_len,
|
pad_len: pad_len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode<T: BufMut>(&self, dst: &mut T) {
|
||||||
|
self.head().encode(self.len(), dst);
|
||||||
|
dst.put(&self.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head(&self) -> Head {
|
||||||
|
Head::new(Kind::Data, self.flags.into(), self.stream_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_payload(self) -> Bytes {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -57,3 +75,9 @@ impl DataFlag {
|
|||||||
self.0 & PADDED == PADDED
|
self.0 & PADDED == PADDED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DataFlag> for u8 {
|
||||||
|
fn from(src: DataFlag) -> u8 {
|
||||||
|
src.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl Head {
|
|||||||
super::HEADER_LEN
|
super::HEADER_LEN
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode<T: BufMut>(&self, payload_len: usize, dst: &mut T) -> Result<(), Error> {
|
pub fn encode<T: BufMut>(&self, payload_len: usize, dst: &mut T) {
|
||||||
debug_assert_eq!(self.encode_len(), dst.remaining_mut());
|
debug_assert_eq!(self.encode_len(), dst.remaining_mut());
|
||||||
debug_assert!(self.stream_id & STREAM_ID_MASK == 0);
|
debug_assert!(self.stream_id & STREAM_ID_MASK == 0);
|
||||||
|
|
||||||
@@ -73,7 +73,6 @@ impl Head {
|
|||||||
dst.put_u8(self.kind as u8);
|
dst.put_u8(self.kind as u8);
|
||||||
dst.put_u8(self.flag);
|
dst.put_u8(self.flag);
|
||||||
dst.put_u32::<BigEndian>(self.stream_id);
|
dst.put_u32::<BigEndian>(self.stream_id);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,79 @@
|
|||||||
|
use super::StreamId;
|
||||||
|
use util::byte_str::ByteStr;
|
||||||
|
|
||||||
|
use http::{Method, StatusCode};
|
||||||
|
use http::header::{self, HeaderMap, HeaderValue};
|
||||||
|
|
||||||
/// Header frame
|
/// Header frame
|
||||||
///
|
///
|
||||||
/// This could be either a request or a response.
|
/// This could be either a request or a response.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Headers {
|
pub struct Headers {
|
||||||
/// The ID of the stream with which this frame is associated.
|
/// The ID of the stream with which this frame is associated.
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
|
|
||||||
/// The stream dependency information, if any.
|
/// The stream dependency information, if any.
|
||||||
stream_dep: Option<StreamDependency>,
|
stream_dep: Option<StreamDependency>,
|
||||||
|
|
||||||
/// The decoded headers
|
/// The decoded headers
|
||||||
headers: HeaderMap,
|
headers: HeaderMap<HeaderValue>,
|
||||||
|
|
||||||
|
/// Pseudo headers, these are broken out as they must be sent as part of the
|
||||||
|
/// headers frame.
|
||||||
pseudo: Pseudo,
|
pseudo: Pseudo,
|
||||||
flags: HeaderFlag,
|
|
||||||
|
/// The associated flags
|
||||||
|
flags: HeadersFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
pub struct HeadersFlag(u8);
|
pub struct HeadersFlag(u8);
|
||||||
|
|
||||||
pub struct PushPromise;
|
#[derive(Debug)]
|
||||||
|
pub struct PushPromise {
|
||||||
|
/// The ID of the stream with which this frame is associated.
|
||||||
|
stream_id: StreamId,
|
||||||
|
|
||||||
|
/// The ID of the stream being reserved by this PushPromise.
|
||||||
|
promised_id: StreamId,
|
||||||
|
|
||||||
|
/// The associated flags
|
||||||
|
flags: HeadersFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct StreamDependency {
|
pub struct StreamDependency {
|
||||||
/// The ID of the stream dependency target
|
/// The ID of the stream dependency target
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
|
|
||||||
/// The weight for the stream. The value exposed (and set) here is always in
|
/// The weight for the stream. The value exposed (and set) here is always in
|
||||||
/// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.)
|
/// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.)
|
||||||
/// so that the value fits into a `u8`.
|
/// so that the value fits into a `u8`.
|
||||||
weight: u8,
|
weight: u8,
|
||||||
|
|
||||||
/// True if the stream dependency is exclusive.
|
/// True if the stream dependency is exclusive.
|
||||||
is_exclusive: bool,
|
is_exclusive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Pseudo {
|
pub struct Pseudo {
|
||||||
// Request
|
// Request
|
||||||
method: Option<()>,
|
method: Option<Method>,
|
||||||
scheme: Option<()>,
|
scheme: Option<ByteStr>,
|
||||||
authority: Option<()>,
|
authority: Option<ByteStr>,
|
||||||
path: Option<()>,
|
path: Option<ByteStr>,
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
status: Option<()>,
|
status: Option<StatusCode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Iter {
|
||||||
|
/// Pseudo headers
|
||||||
|
pseudo: Option<Pseudo>,
|
||||||
|
|
||||||
|
/// Headers
|
||||||
|
headers: header::IntoIter<HeaderValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const END_STREAM: u8 = 0x1;
|
const END_STREAM: u8 = 0x1;
|
||||||
@@ -52,7 +88,7 @@ const ALL: u8 = END_STREAM
|
|||||||
// ===== impl HeadersFlag =====
|
// ===== impl HeadersFlag =====
|
||||||
|
|
||||||
impl HeadersFlag {
|
impl HeadersFlag {
|
||||||
pub empty() -> HeadersFlag {
|
pub fn empty() -> HeadersFlag {
|
||||||
HeadersFlag(0)
|
HeadersFlag(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,31 +26,29 @@ macro_rules! unpack_octets_4 {
|
|||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
mod head;
|
mod head;
|
||||||
|
mod headers;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod unknown;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use self::data::Data;
|
pub use self::data::Data;
|
||||||
pub use self::head::{Head, Kind, StreamId};
|
pub use self::head::{Head, Kind, StreamId};
|
||||||
|
pub use self::headers::{Headers, PushPromise};
|
||||||
pub use self::settings::{Settings, SettingSet};
|
pub use self::settings::{Settings, SettingSet};
|
||||||
pub use self::unknown::Unknown;
|
|
||||||
|
// Re-export some constants
|
||||||
|
pub use self::settings::{
|
||||||
|
DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
|
||||||
|
DEFAULT_MAX_FRAME_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
pub const HEADER_LEN: usize = 9;
|
pub const HEADER_LEN: usize = 9;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug /*, Clone, PartialEq */)]
|
||||||
pub enum Frame {
|
pub enum Frame {
|
||||||
/*
|
Data(Data),
|
||||||
Data(DataFrame<'a>),
|
Headers(Headers),
|
||||||
HeadersFrame(HeadersFrame<'a>),
|
PushPromise(PushPromise),
|
||||||
RstStreamFrame(RstStreamFrame),
|
|
||||||
SettingsFrame(SettingsFrame),
|
|
||||||
PingFrame(PingFrame),
|
|
||||||
GoawayFrame(GoawayFrame<'a>),
|
|
||||||
WindowUpdateFrame(WindowUpdateFrame),
|
|
||||||
UnknownFrame(RawFrame<'a>),
|
|
||||||
*/
|
|
||||||
Settings(Settings),
|
Settings(Settings),
|
||||||
Unknown(Unknown),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur during parsing an HTTP/2 frame.
|
/// Errors that can occur during parsing an HTTP/2 frame.
|
||||||
@@ -99,40 +97,6 @@ pub enum Error {
|
|||||||
// ===== impl Frame ======
|
// ===== impl Frame ======
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn load(mut frame: Bytes) -> Result<Frame, Error> {
|
|
||||||
let head = Head::parse(&frame);
|
|
||||||
|
|
||||||
// Extract the payload from the frame
|
|
||||||
let _ = frame.drain_to(HEADER_LEN);
|
|
||||||
|
|
||||||
match head.kind() {
|
|
||||||
Kind::Unknown => {
|
|
||||||
let unknown = Unknown::new(head, frame);
|
|
||||||
Ok(Frame::Unknown(unknown))
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encode_len(&self) -> usize {
|
|
||||||
use self::Frame::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
Settings(ref frame) => frame.encode_len(),
|
|
||||||
Unknown(ref frame) => frame.encode_len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encode(&self, dst: &mut BytesMut) -> Result<(), Error> {
|
|
||||||
use self::Frame::*;
|
|
||||||
|
|
||||||
debug_assert!(dst.remaining_mut() >= self.encode_len());
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
Settings(ref frame) => frame.encode(dst),
|
|
||||||
Unknown(ref frame) => frame.encode(dst),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl Error =====
|
// ===== impl Error =====
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ pub struct SettingsFlag(u8);
|
|||||||
const ACK: u8 = 0x1;
|
const ACK: u8 = 0x1;
|
||||||
const ALL: u8 = ACK;
|
const ALL: u8 = ACK;
|
||||||
|
|
||||||
|
pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
|
||||||
|
pub const DEFAULT_MAX_FRAME_SIZE: usize = 16_384;
|
||||||
|
|
||||||
// ===== impl Settings =====
|
// ===== impl Settings =====
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
@@ -111,27 +114,21 @@ impl Settings {
|
|||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_len(&self) -> usize {
|
|
||||||
super::HEADER_LEN + self.payload_len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn payload_len(&self) -> usize {
|
fn payload_len(&self) -> usize {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
self.for_each(|_| len += 6);
|
self.for_each(|_| len += 6);
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self, dst: &mut BytesMut) -> Result<(), Error> {
|
pub fn encode(&self, dst: &mut BytesMut) {
|
||||||
// Create & encode an appropriate frame head
|
// Create & encode an appropriate frame head
|
||||||
let head = Head::new(Kind::Settings, self.flag.into(), 0);
|
let head = Head::new(Kind::Settings, self.flag.into(), 0);
|
||||||
let payload_len = self.payload_len();
|
let payload_len = self.payload_len();
|
||||||
|
|
||||||
try!(head.encode(payload_len, dst));
|
head.encode(payload_len, dst);
|
||||||
|
|
||||||
// Encode the settings
|
// Encode the settings
|
||||||
self.for_each(|setting| setting.encode(dst));
|
self.for_each(|setting| setting.encode(dst));
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
|
fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
|
||||||
|
|||||||
@@ -4,16 +4,21 @@ use super::table::{Table, Index};
|
|||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use bytes::{BytesMut, BufMut};
|
use bytes::{BytesMut, BufMut};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Encoder {
|
pub struct Encoder {
|
||||||
table: Table,
|
table: Table,
|
||||||
size_update: Option<SizeUpdate>,
|
size_update: Option<SizeUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Encode {
|
pub enum Encode {
|
||||||
Full,
|
Full,
|
||||||
Partial(Index),
|
Partial(EncodeState),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EncodeState(Index);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum EncoderError {
|
pub enum EncoderError {
|
||||||
BufferOverflow,
|
BufferOverflow,
|
||||||
@@ -67,7 +72,7 @@ impl Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encode a set of headers into the provide buffer
|
/// Encode a set of headers into the provide buffer
|
||||||
pub fn encode<I>(&mut self, resume: Option<Index>, headers: &mut I, dst: &mut BytesMut)
|
pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut)
|
||||||
-> Result<Encode, EncoderError>
|
-> Result<Encode, EncoderError>
|
||||||
where I: Iterator<Item=Header>,
|
where I: Iterator<Item=Header>,
|
||||||
{
|
{
|
||||||
@@ -81,13 +86,13 @@ impl Encoder {
|
|||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(index) = resume {
|
if let Some(resume) = resume {
|
||||||
let len = dst.len();
|
let len = dst.len();
|
||||||
|
|
||||||
match self.encode_header(&index, dst) {
|
match self.encode_header(&resume.0, dst) {
|
||||||
Err(EncoderError::BufferOverflow) => {
|
Err(EncoderError::BufferOverflow) => {
|
||||||
dst.truncate(len);
|
dst.truncate(len);
|
||||||
return Ok(Encode::Partial(index));
|
return Ok(Encode::Partial(resume));
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
@@ -101,7 +106,7 @@ impl Encoder {
|
|||||||
match self.encode_header(&index, dst) {
|
match self.encode_header(&index, dst) {
|
||||||
Err(EncoderError::BufferOverflow) => {
|
Err(EncoderError::BufferOverflow) => {
|
||||||
dst.truncate(len);
|
dst.truncate(len);
|
||||||
return Ok(Encode::Partial(index));
|
return Ok(Encode::Partial(EncodeState(index)));
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ mod table;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
pub use self::encoder::{Encoder, Encode, EncoderError};
|
pub use self::encoder::{Encoder, Encode, EncoderError, EncodeState};
|
||||||
pub use self::header::Header;
|
pub use self::header::Header;
|
||||||
pub use self::decoder::{Decoder, DecoderError};
|
pub use self::decoder::{Decoder, DecoderError};
|
||||||
pub use self::table::Index;
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::collections::VecDeque;
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
/// HPACK encoder table
|
/// HPACK encoder table
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
mask: usize,
|
mask: usize,
|
||||||
indices: Vec<Option<Pos>>,
|
indices: Vec<Option<Pos>>,
|
||||||
@@ -37,6 +38,7 @@ pub enum Index {
|
|||||||
NotIndexed(Header),
|
NotIndexed(Header),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Slot {
|
struct Slot {
|
||||||
hash: HashValue,
|
hash: HashValue,
|
||||||
header: Header,
|
header: Header,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use ConnectionError;
|
use {hpack, ConnectionError};
|
||||||
use frame::{self, Frame, Kind};
|
use frame::{self, Frame, Kind};
|
||||||
|
use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
|
||||||
|
|
||||||
use tokio_io::AsyncWrite;
|
use tokio_io::AsyncWrite;
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ pub struct FramedRead<T> {
|
|||||||
inner: T,
|
inner: T,
|
||||||
|
|
||||||
// hpack decoder state
|
// hpack decoder state
|
||||||
// hpack: hpack::Decoder,
|
hpack: hpack::Decoder,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ impl<T> FramedRead<T>
|
|||||||
pub fn new(inner: T) -> FramedRead<T> {
|
pub fn new(inner: T) -> FramedRead<T> {
|
||||||
FramedRead {
|
FramedRead {
|
||||||
inner: inner,
|
inner: inner,
|
||||||
|
hpack: hpack::Decoder::new(DEFAULT_SETTINGS_HEADER_TABLE_SIZE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,10 +48,7 @@ impl<T> FramedRead<T> {
|
|||||||
Kind::GoAway => unimplemented!(),
|
Kind::GoAway => unimplemented!(),
|
||||||
Kind::WindowUpdate => unimplemented!(),
|
Kind::WindowUpdate => unimplemented!(),
|
||||||
Kind::Continuation => unimplemented!(),
|
Kind::Continuation => unimplemented!(),
|
||||||
Kind::Unknown => {
|
Kind::Unknown => return Ok(None),
|
||||||
let _ = bytes.split_to(frame::HEADER_LEN);
|
|
||||||
frame::Unknown::new(head, bytes).into()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(frame))
|
Ok(Some(frame))
|
||||||
|
|||||||
@@ -1,33 +1,86 @@
|
|||||||
use {ConnectionError, Reason};
|
use {ConnectionError, Reason};
|
||||||
use frame::{Frame, Error};
|
use frame::{self, Data, Frame, Error, Headers, PushPromise, Settings};
|
||||||
|
use hpack;
|
||||||
|
|
||||||
use tokio_io::AsyncWrite;
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use bytes::{BytesMut, Buf, BufMut};
|
use tokio_io::AsyncWrite;
|
||||||
|
use bytes::{Bytes, BytesMut, Buf, BufMut};
|
||||||
|
use http::header::{self, HeaderValue};
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
use std::io::{self, Cursor};
|
use std::io::{self, Cursor};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FramedWrite<T> {
|
pub struct FramedWrite<T> {
|
||||||
|
/// Upstream `AsyncWrite`
|
||||||
inner: T,
|
inner: T,
|
||||||
buf: Cursor<BytesMut>,
|
|
||||||
|
/// HPACK encoder
|
||||||
|
hpack: hpack::Encoder,
|
||||||
|
|
||||||
|
/// Write buffer
|
||||||
|
buf: BytesMut,
|
||||||
|
|
||||||
|
/// Position in the frame
|
||||||
|
pos: usize,
|
||||||
|
|
||||||
|
/// Next frame to encode
|
||||||
|
next: Option<Next>,
|
||||||
|
|
||||||
|
/// Max frame size, this is specified by the peer
|
||||||
|
max_frame_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_BUFFER_CAPACITY: usize = 8 * 1_024;
|
#[derive(Debug)]
|
||||||
const MAX_BUFFER_CAPACITY: usize = 16 * 1_024;
|
enum Next {
|
||||||
|
Data {
|
||||||
|
/// Length of the current frame being written
|
||||||
|
frame_len: usize,
|
||||||
|
|
||||||
|
/// Data frame to encode
|
||||||
|
data: frame::Data
|
||||||
|
},
|
||||||
|
Continuation {
|
||||||
|
/// Stream ID of continuation frame
|
||||||
|
stream_id: frame::StreamId,
|
||||||
|
|
||||||
|
/// Argument to pass to the HPACK encoder to resume encoding
|
||||||
|
resume: hpack::EncodeState,
|
||||||
|
|
||||||
|
/// remaining headers to encode
|
||||||
|
rem: header::IntoIter<HeaderValue>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialze the connection with this amount of write buffer.
|
||||||
|
const DEFAULT_BUFFER_CAPACITY: usize = 4 * 1_024;
|
||||||
|
|
||||||
|
/// Min buffer required to attempt to write a frame
|
||||||
|
const MIN_BUFFER_CAPACITY: usize = frame::HEADER_LEN + CHAIN_THRESHOLD;
|
||||||
|
|
||||||
|
/// Chain payloads bigger than this. The remote will never advertise a max frame
|
||||||
|
/// size less than this (well, the spec says the max frame size can't be less
|
||||||
|
/// than 16kb, so not even close).
|
||||||
|
const CHAIN_THRESHOLD: usize = 256;
|
||||||
|
|
||||||
impl<T: AsyncWrite> FramedWrite<T> {
|
impl<T: AsyncWrite> FramedWrite<T> {
|
||||||
pub fn new(inner: T) -> FramedWrite<T> {
|
pub fn new(inner: T) -> FramedWrite<T> {
|
||||||
let buf = BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY);
|
|
||||||
|
|
||||||
FramedWrite {
|
FramedWrite {
|
||||||
inner: inner,
|
inner: inner,
|
||||||
buf: Cursor::new(buf),
|
hpack: hpack::Encoder::default(),
|
||||||
|
buf: BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY),
|
||||||
|
pos: 0,
|
||||||
|
next: None,
|
||||||
|
max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_buf(&mut self) -> &mut BytesMut {
|
fn has_capacity(&self) -> bool {
|
||||||
self.buf.get_mut()
|
self.next.is_none() && self.buf.remaining_mut() >= MIN_BUFFER_CAPACITY
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame_len(&self, data: &Data) -> usize {
|
||||||
|
cmp::min(self.max_frame_size, data.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,50 +89,49 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
|||||||
type SinkError = ConnectionError;
|
type SinkError = ConnectionError;
|
||||||
|
|
||||||
fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> {
|
fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> {
|
||||||
let len = item.encode_len();
|
if self.has_capacity() {
|
||||||
|
// Try flushing
|
||||||
if len > MAX_BUFFER_CAPACITY {
|
|
||||||
// This case should never happen. Large frames should be chunked at
|
|
||||||
// a higher level, so this is an internal error.
|
|
||||||
return Err(ConnectionError::Proto(Reason::InternalError));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.write_buf().remaining_mut() <= len {
|
|
||||||
// Try flushing the buffer
|
|
||||||
try!(self.poll_complete());
|
try!(self.poll_complete());
|
||||||
|
|
||||||
let rem = self.write_buf().remaining_mut();
|
if self.has_capacity() {
|
||||||
let additional = len - rem;
|
|
||||||
|
|
||||||
if self.write_buf().capacity() + additional > MAX_BUFFER_CAPACITY {
|
|
||||||
return Ok(AsyncSink::NotReady(item));
|
return Ok(AsyncSink::NotReady(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grow the buffer
|
|
||||||
self.write_buf().reserve(additional);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, the buffer contains enough space
|
match item {
|
||||||
item.encode(self.write_buf());
|
Frame::Data(v) => {
|
||||||
|
if v.len() >= CHAIN_THRESHOLD {
|
||||||
|
let head = v.head();
|
||||||
|
let len = self.frame_len(&v);
|
||||||
|
|
||||||
|
// Encode the frame head to the buffer
|
||||||
|
head.encode(len, &mut self.buf);
|
||||||
|
|
||||||
|
// Save the data frame
|
||||||
|
self.next = Some(Next::Data {
|
||||||
|
frame_len: len,
|
||||||
|
data: v,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
v.encode(&mut self.buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Frame::Headers(v) => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
Frame::PushPromise(v) => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
Frame::Settings(v) => {
|
||||||
|
v.encode(&mut self.buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(AsyncSink::Ready)
|
Ok(AsyncSink::Ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
|
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
|
||||||
while self.buf.has_remaining() {
|
unimplemented!();
|
||||||
try_ready!(self.inner.write_buf(&mut self.buf));
|
|
||||||
|
|
||||||
if !self.buf.has_remaining() {
|
|
||||||
// Reset the buffer
|
|
||||||
self.write_buf().clear();
|
|
||||||
self.buf.set_position(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try flushing the underlying IO
|
|
||||||
try_nb!(self.inner.flush());
|
|
||||||
|
|
||||||
return Ok(Async::Ready(()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self) -> Poll<(), ConnectionError> {
|
fn close(&mut self) -> Poll<(), ConnectionError> {
|
||||||
|
|||||||
Reference in New Issue
Block a user