Use rustfmt to enforce consistent formatting

This change adds a .rustfmt.toml that includes ALL supported settings,
12 of which we have overridden to attempt to cater to our own
proclivities.

rustfmt is checked in the rust-nightly CI job.
This commit is contained in:
Oliver Gould
2017-09-08 17:20:41 +00:00
parent 93925e6d1f
commit 897bf84163
60 changed files with 2087 additions and 1620 deletions

84
.rustfmt.toml Normal file
View File

@@ -0,0 +1,84 @@
# https://github.com/rust-lang-nursery/rustfmt/blob/master/Configurations.md
verbose = false
disable_all_formatting = false
skip_children = false
max_width = 100
error_on_line_overflow = false
error_on_line_overflow_comments = false
tab_spaces = 4
fn_call_width = 60
struct_lit_width = 18
struct_variant_width = 35
force_explicit_abi = true
newline_style = "Unix"
fn_brace_style = "SameLineWhere"
item_brace_style = "SameLineWhere"
control_style = "Rfc"
control_brace_style = "AlwaysSameLine"
impl_empty_single_line = true
trailing_comma = "Vertical"
trailing_semicolon = true
fn_empty_single_line = true
fn_single_line = false
fn_return_indent = "WithArgs"
fn_args_paren_newline = false
fn_args_density = "Tall"
fn_args_layout = "Block"
array_layout = "Block"
array_width = 60
array_horizontal_layout_threshold = 0
type_punctuation_density = "Wide"
where_style = "Rfc"
where_density = "CompressedIfEmpty"
where_layout = "Vertical"
where_pred_indent = "Visual"
generics_indent = "Block"
struct_lit_style = "Block"
struct_lit_multiline_style = "ForceMulti"
fn_call_style = "Visual"
report_todo = "Never"
report_fixme = "Never"
chain_indent = "Block"
chain_one_line_max = 60
chain_split_single_child = false
imports_indent = "Block"
imports_layout = "HorizontalVertical"
reorder_extern_crates = true
reorder_extern_crates_in_group = true
reorder_imports = true
reorder_imports_in_group = true
reorder_imported_names = true
single_line_if_else_max_width = 50
format_strings = true
force_format_strings = false
take_source_hints = false
hard_tabs = false
wrap_comments = false
comment_width = 80
normalize_comments = false
wrap_match_arms = true
match_block_trailing_comma = false
indent_match_arms = true
match_pattern_separator_break_point = "Back"
closure_block_indent_threshold = 0
space_before_type_annotation = false
space_after_type_annotation_colon = true
space_before_struct_lit_field_colon = false
space_after_struct_lit_field_colon = true
space_before_bound = false
space_after_bound_colon = true
spaces_around_ranges = false
spaces_within_angle_brackets = false
spaces_within_square_brackets = false
spaces_within_parens = false
use_try_shorthand = true
write_mode = "Overwrite"
condense_wildcard_suffixes = false
combine_control_expr = true
struct_field_align_threshold = 0
remove_blank_lines_at_start_or_end_of_block = true
attributes_on_same_line_as_field = true
attributes_on_same_line_as_variant = true
multiline_closure_forces_block = false
multiline_match_arm_forces_block = false
merge_derives = true

View File

@@ -16,8 +16,12 @@ matrix:
- rust: stable
- rust: beta
- rust: nightly
before_script:
install:
- pip install --user travis-cargo codecov && export PATH=$HOME/.local/bin:$PATH
- if ! cargo fmt --help >/dev/null 2>&1 ; then cargo install rustfmt-nightly ; fi
after_script:
# Check formatting
- cargo fmt -- --write-mode=diff
after_success:
- travis-cargo doc-upload

95
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,95 @@
# Contributing to _h2_ #
:balloon: Thanks for your help improving the project!
## Getting Help ##
If you have a question about the h2 library or have encountered problems using it, you may
[file an issue][issue] or ask ask a question on the [Tokio Gitter][gitter].
## Submitting a Pull Request ##
Do you have an improvement?
1. Submit an [issue][issue] describing your proposed change.
2. We will try to respond to your issue promptly.
3. Fork this repo, develop and test your code changes. See the project's [README](README.md) for further information about working in this repository.
4. Submit a pull request against this repo's `master` branch.
6. Your branch may be merged once all configured checks pass, including:
- Code review has been completed.
- The branch has passed tests in CI.
## Code Style ##
[`rustfmt-nightly`][rustfmt] is used to enforce a consistent style (as configured by
[`.rustfmt.toml`](./.rustfmt.toml)). Style is checked by CI, so be sure to apply rustfmt
before committing your work. For example:
```
$ rustup run nightly cargo install --force rustfmt-nightly
Updating registry `https://github.com/rust-lang/crates.io-index`
Installing rustfmt-nightly v0.2.5
...
$ rustup run nightly cargo fmt
```
## Committing ##
We prefer squash or rebase commits so that all changes from a branch are
committed to master as a single commit. All pull requests are squashed when
merged, but rebasing prior to merge gives you better control over the commit
message.
### Commit messages ###
Finalized commit messages should be in the following format:
```
Subject
Problem
Solution
Validation
```
#### Subject ####
- one line, <= 50 characters
- describe what is done; not the result
- use the active voice
- capitalize first word and proper nouns
- do not end in a period — this is a title/subject
- reference the github issue by number
##### Examples #####
```
bad: server disconnects should cause dst client disconnects.
good: Propagate disconnects from source to destination
```
```
bad: support tls servers
good: Introduce support for server-side TLS (#347)
```
#### Problem ####
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
#### Solution ####
Describe the modifications you've made.
#### Validation ####
Describe the testing you've done to validate your change. Performance-related
changes should include before- and after- benchmark results.
[issue]: https://github.com/carllerche/h2/issues/new
[gitter]: https://gitter.im/tokio-rs/tokio
[rustfmt]: https://github.com/rust-lang-nursery/rustfmt

View File

@@ -1,20 +1,20 @@
extern crate env_logger;
extern crate futures;
extern crate h2;
extern crate http;
extern crate futures;
extern crate io_dump;
extern crate rustls;
extern crate tokio_core;
extern crate tokio_rustls;
extern crate webpki_roots;
extern crate io_dump;
extern crate env_logger;
use h2::client::Client;
use http::{Request, Method};
use futures::*;
use http::{Method, Request};
use tokio_core::reactor;
use tokio_core::net::TcpStream;
use tokio_core::reactor;
use rustls::Session;
use tokio_rustls::ClientConfigExt;
@@ -27,26 +27,30 @@ pub fn main() {
let _ = env_logger::init();
let tls_client_config = std::sync::Arc::new({
let mut c = rustls::ClientConfig::new();
c.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
c.alpn_protocols.push(ALPN_H2.to_owned());
c
});
let mut c = rustls::ClientConfig::new();
c.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
c.alpn_protocols.push(ALPN_H2.to_owned());
c
});
// Sync DNS resolution.
let addr = "http2.akamai.com:443".to_socket_addrs()
.unwrap().next().unwrap();
let addr = "http2.akamai.com:443"
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
println!("ADDR: {:?}", addr);
let mut core = reactor::Core::new().unwrap();;
let mut core = reactor::Core::new().unwrap();
let handle = core.handle();
let tcp = TcpStream::connect(&addr, &handle);
let tcp = tcp.then(|res| {
let tcp = res.unwrap();
tls_client_config.connect_async("http2.akamai.com", tcp)
tls_client_config
.connect_async("http2.akamai.com", tcp)
.then(|res| {
let tls = res.unwrap();
let negotiated_protcol = {
@@ -67,7 +71,8 @@ pub fn main() {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let stream = h2.request(request, true).unwrap();

View File

@@ -1,19 +1,19 @@
extern crate bytes;
extern crate env_logger;
extern crate futures;
extern crate h2;
extern crate http;
extern crate bytes;
extern crate futures;
extern crate tokio_core;
extern crate io_dump;
extern crate env_logger;
extern crate tokio_core;
use h2::client::{Client, Body};
use h2::client::{Body, Client};
use http::*;
use futures::*;
use bytes::*;
use futures::*;
use http::*;
use tokio_core::reactor;
use tokio_core::net::TcpStream;
use tokio_core::reactor;
struct Process {
body: Body<Bytes>,
@@ -49,52 +49,51 @@ impl Future for Process {
pub fn main() {
let _ = env_logger::init();
let mut core = reactor::Core::new().unwrap();;
let mut core = reactor::Core::new().unwrap();
let handle = core.handle();
let tcp = TcpStream::connect(
&"127.0.0.1:5928".parse().unwrap(),
&handle);
let tcp = TcpStream::connect(&"127.0.0.1:5928".parse().unwrap(), &handle);
let tcp = tcp.then(|res| {
let tcp = io_dump::Dump::to_stdout(res.unwrap());
Client::handshake(tcp)
})
.then(|res| {
let mut client = res.unwrap();
}).then(|res| {
let mut client = res.unwrap();
println!("sending request");
println!("sending request");
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
let mut trailers = HeaderMap::new();
trailers.insert("zomg", "hello".parse().unwrap());
let mut trailers = HeaderMap::new();
trailers.insert("zomg", "hello".parse().unwrap());
let mut stream = client.request(request, false).unwrap();
let mut stream = client.request(request, false).unwrap();
// send trailers
stream.send_trailers(trailers).unwrap();
// send trailers
stream.send_trailers(trailers).unwrap();
// Spawn a task to run the client...
handle.spawn(client.map_err(|e| println!("GOT ERR={:?}", e)));
// Spawn a task to run the client...
handle.spawn(client.map_err(|e| println!("GOT ERR={:?}", e)));
stream.and_then(|response| {
println!("GOT RESPONSE: {:?}", response);
stream
.and_then(|response| {
println!("GOT RESPONSE: {:?}", response);
// Get the body
let (_, body) = response.into_parts();
// Get the body
let (_, body) = response.into_parts();
Process {
body,
trailers: false,
}
}).map_err(|e| {
println!("GOT ERR={:?}", e);
})
})
;
Process {
body,
trailers: false,
}
})
.map_err(|e| {
println!("GOT ERR={:?}", e);
})
});
core.run(tcp).unwrap();
}

View File

@@ -1,28 +1,27 @@
extern crate bytes;
extern crate env_logger;
extern crate futures;
extern crate h2;
extern crate http;
extern crate bytes;
extern crate futures;
extern crate tokio_core;
extern crate env_logger;
use h2::server::Server;
use http::*;
use bytes::*;
use futures::*;
use http::*;
use tokio_core::reactor;
use tokio_core::net::TcpListener;
use tokio_core::reactor;
pub fn main() {
let _ = env_logger::init();
let mut core = reactor::Core::new().unwrap();;
let mut core = reactor::Core::new().unwrap();
let handle = core.handle();
let listener = TcpListener::bind(
&"127.0.0.1:5928".parse().unwrap(),
&handle).unwrap();
let listener = TcpListener::bind(&"127.0.0.1:5928".parse().unwrap(), &handle).unwrap();
println!("listening on {:?}", listener.local_addr());
@@ -37,9 +36,7 @@ pub fn main() {
conn.for_each(|(request, mut stream)| {
println!("GOT request: {:?}", request);
let response = Response::builder()
.status(StatusCode::OK)
.body(()).unwrap();
let response = Response::builder().status(StatusCode::OK).body(()).unwrap();
if let Err(e) = stream.send_response(response, false) {
println!(" error responding; err={:?}", e);
@@ -60,9 +57,10 @@ pub fn main() {
Ok(())
}).and_then(|_| {
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! ~~~~~~~~~~~");
Ok(())
})
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! \
~~~~~~~~~~~");
Ok(())
})
})
.then(|res| {
if let Err(e) = res {
@@ -70,8 +68,7 @@ pub fn main() {
}
Ok(())
})
;
});
handle.spawn(connection);
Ok(())

View File

@@ -1,28 +1,27 @@
extern crate bytes;
extern crate env_logger;
extern crate futures;
extern crate h2;
extern crate http;
extern crate bytes;
extern crate futures;
extern crate tokio_core;
extern crate env_logger;
use h2::server::Server;
use http::*;
use bytes::*;
use futures::*;
use http::*;
use tokio_core::reactor;
use tokio_core::net::TcpListener;
use tokio_core::reactor;
pub fn main() {
let _ = env_logger::init();
let mut core = reactor::Core::new().unwrap();;
let mut core = reactor::Core::new().unwrap();
let handle = core.handle();
let listener = TcpListener::bind(
&"127.0.0.1:5928".parse().unwrap(),
&handle).unwrap();
let listener = TcpListener::bind(&"127.0.0.1:5928".parse().unwrap(), &handle).unwrap();
println!("listening on {:?}", listener.local_addr());
@@ -37,9 +36,7 @@ pub fn main() {
conn.for_each(|(request, mut stream)| {
println!("GOT request: {:?}", request);
let response = Response::builder()
.status(StatusCode::OK)
.body(()).unwrap();
let response = Response::builder().status(StatusCode::OK).body(()).unwrap();
if let Err(e) = stream.send_response(response, false) {
println!(" error responding; err={:?}", e);
@@ -52,9 +49,10 @@ pub fn main() {
Ok(())
}).and_then(|_| {
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! ~~~~~~~~~~~");
Ok(())
})
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~ H2 connection CLOSE !!!!!! \
~~~~~~~~~~~");
Ok(())
})
})
.then(|res| {
if let Err(e) = res {
@@ -62,8 +60,7 @@ pub fn main() {
}
Ok(())
})
;
});
handle.spawn(connection);
Ok(())

View File

@@ -1,26 +1,24 @@
use frame::{StreamId, Headers, Pseudo, Settings};
use frame::Reason::*;
use codec::{Codec, RecvError};
use frame::{Headers, Pseudo, Settings, StreamId};
use frame::Reason::*;
use proto::{self, Connection, WindowSize};
use http::{Request, Response, HeaderMap};
use futures::{Future, Poll, Sink, Async, AsyncSink, AndThen, MapErr};
use bytes::{Bytes, IntoBuf};
use futures::{AndThen, Async, AsyncSink, Future, MapErr, Poll, Sink};
use http::{HeaderMap, Request, Response};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::WriteAll;
use bytes::{Bytes, IntoBuf};
use std::fmt;
use std::io::Error as IoError;
/// In progress H2 connection binding
pub struct Handshake<T: AsyncRead + AsyncWrite, B: IntoBuf = Bytes> {
inner:
AndThen<
MapErr<WriteAll<T, &'static [u8]>, fn(IoError) -> ::Error>,
Result<Client<T, B>, ::Error>,
fn((T, &'static [u8])) -> Result<Client<T, B>, ::Error>
>
inner: AndThen<
MapErr<WriteAll<T, &'static [u8]>, fn(IoError) -> ::Error>,
Result<Client<T, B>, ::Error>,
fn((T, &'static [u8])) -> Result<Client<T, B>, ::Error>,
>,
}
/// Marker type indicating a client peer
@@ -42,7 +40,8 @@ pub struct Body<B: IntoBuf> {
pub(crate) struct Peer;
impl<T> Client<T, Bytes>
where T: AsyncRead + AsyncWrite,
where
T: AsyncRead + AsyncWrite,
{
pub fn handshake(io: T) -> Handshake<T, Bytes> {
Client::handshake2(io)
@@ -50,8 +49,9 @@ impl<T> Client<T, Bytes>
}
impl<T, B> Client<T, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Bind an H2 client connection.
///
@@ -66,35 +66,36 @@ impl<T, B> Client<T, B>
debug!("binding client connection");
let bind: fn((T, &'static [u8]))
-> Result<Client<T, B>, ::Error> =
|(io, _)| {
debug!("client connection bound");
-> Result<Client<T, B>, ::Error> = |(io, _)| {
debug!("client connection bound");
// Create the codec
let mut codec = Codec::new(io);
// Create the codec
let mut codec = Codec::new(io);
// Create the initial SETTINGS frame
let settings = Settings::default();
// Create the initial SETTINGS frame
let settings = Settings::default();
// Send initial settings frame
match codec.start_send(settings.into()) {
Ok(AsyncSink::Ready) => {
let connection = Connection::new(codec);
Ok(Client { connection })
}
Ok(_) => unreachable!(),
Err(e) => Err(::Error::from(e)),
// Send initial settings frame
match codec.start_send(settings.into()) {
Ok(AsyncSink::Ready) => {
let connection = Connection::new(codec);
Ok(Client {
connection,
})
}
};
Ok(_) => unreachable!(),
Err(e) => Err(::Error::from(e)),
}
};
let msg: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
let msg: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
let handshake = io::write_all(io, msg)
.map_err(::Error::from as
fn(IoError) -> ::Error
)
.map_err(::Error::from as fn(IoError) -> ::Error)
.and_then(bind);
Handshake { inner: handshake }
Handshake {
inner: handshake,
}
}
/// Returns `Ready` when the connection can initialize a new HTTP 2.0
@@ -104,36 +105,41 @@ impl<T, B> Client<T, B>
}
/// Send a request on a new HTTP 2.0 stream
pub fn request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<Stream<B>, ::Error>
{
self.connection.send_request(request, end_of_stream)
pub fn request(
&mut self,
request: Request<()>,
end_of_stream: bool,
) -> Result<Stream<B>, ::Error> {
self.connection
.send_request(request, end_of_stream)
.map_err(Into::into)
.map(|stream| Stream {
inner: stream,
.map(|stream| {
Stream {
inner: stream,
}
})
}
}
impl<T, B> Future for Client<T, B>
// TODO: Get rid of 'static
where T: AsyncRead + AsyncWrite,
B: IntoBuf,
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<(), ::Error> {
self.connection.poll()
.map_err(Into::into)
self.connection.poll().map_err(Into::into)
}
}
impl<T, B> fmt::Debug for Client<T, B>
where T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
where
T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Client")
@@ -144,8 +150,9 @@ impl<T, B> fmt::Debug for Client<T, B>
#[cfg(feature = "unstable")]
impl<T, B> Client<T, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Returns the number of active streams.
///
@@ -168,7 +175,9 @@ impl<T, B> Client<T, B>
// ===== impl Handshake =====
impl<T, B: IntoBuf> Future for Handshake<T, B>
where T: AsyncRead + AsyncWrite {
where
T: AsyncRead + AsyncWrite,
{
type Item = Client<T, B>;
type Error = ::Error;
@@ -178,10 +187,11 @@ where T: AsyncRead + AsyncWrite {
}
impl<T, B> fmt::Debug for Handshake<T, B>
where T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug + IntoBuf,
where
T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug + IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "client::Handshake")
@@ -194,7 +204,9 @@ impl<B: IntoBuf> Stream<B> {
/// Receive the HTTP/2.0 response, if it is ready.
pub fn poll_response(&mut self) -> Poll<Response<Body<B>>, ::Error> {
let (parts, _) = try_ready!(self.inner.poll_response()).into_parts();
let body = Body { inner: self.inner.clone() };
let body = Body {
inner: self.inner.clone(),
};
Ok(Response::from_parts(parts, body).into())
}
@@ -217,19 +229,15 @@ impl<B: IntoBuf> Stream<B> {
}
/// Send data
pub fn send_data(&mut self, data: B, end_of_stream: bool)
-> Result<(), ::Error>
{
self.inner.send_data(data.into_buf(), end_of_stream)
pub fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), ::Error> {
self.inner
.send_data(data.into_buf(), end_of_stream)
.map_err(Into::into)
}
/// Send trailers
pub fn send_trailers(&mut self, trailers: HeaderMap)
-> Result<(), ::Error>
{
self.inner.send_trailers(trailers)
.map_err(Into::into)
pub fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), ::Error> {
self.inner.send_trailers(trailers).map_err(Into::into)
}
}
@@ -251,7 +259,8 @@ impl<B: IntoBuf> Body<B> {
}
pub fn release_capacity(&mut self, sz: usize) -> Result<(), ::Error> {
self.inner.release_capacity(sz as proto::WindowSize)
self.inner
.release_capacity(sz as proto::WindowSize)
.map_err(Into::into)
}
@@ -259,8 +268,7 @@ impl<B: IntoBuf> Body<B> {
///
/// This function **must** not be called until `Body::poll` returns `None`.
pub fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, ::Error> {
self.inner.poll_trailers()
.map_err(Into::into)
self.inner.poll_trailers().map_err(Into::into)
}
}
@@ -269,8 +277,7 @@ impl<B: IntoBuf> ::futures::Stream for Body<B> {
type Error = ::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll_data()
.map_err(Into::into)
self.inner.poll_data().map_err(Into::into)
}
}
@@ -284,14 +291,16 @@ impl proto::Peer for Peer {
false
}
fn convert_send_message(
id: StreamId,
request: Self::Send,
end_of_stream: bool) -> Headers
{
fn convert_send_message(id: StreamId, request: Self::Send, end_of_stream: bool) -> Headers {
use http::request::Parts;
let (Parts { method, uri, headers, .. }, _) = request.into_parts();
let (Parts {
method,
uri,
headers,
..
},
_) = request.into_parts();
// Build the set pseudo header set. All requests will include `method`
// and `path`.
@@ -323,9 +332,9 @@ impl proto::Peer for Peer {
// TODO: Should there be more specialized handling for different
// kinds of errors
return Err(RecvError::Stream {
id: stream_id,
reason: ProtocolError,
});
id: stream_id,
reason: ProtocolError,
});
}
};

View File

@@ -6,10 +6,7 @@ use std::{error, fmt, io};
#[derive(Debug)]
pub enum RecvError {
Connection(Reason),
Stream {
id: StreamId,
reason: Reason,
},
Stream { id: StreamId, reason: Reason },
Io(io::Error),
}
@@ -56,7 +53,9 @@ impl error::Error for RecvError {
match *self {
Connection(ref reason) => reason.description(),
Stream { ref reason, .. } => reason.description(),
Stream {
ref reason, ..
} => reason.description(),
Io(ref e) => e.description(),
}
}

View File

@@ -101,9 +101,9 @@ impl<T> FramedRead<T> {
// treat this as a stream error (Section 5.4.2) of type
// `PROTOCOL_ERROR`.
return Err(Stream {
id: head.stream_id(),
reason: ProtocolError,
});
id: head.stream_id(),
reason: ProtocolError,
});
}
_ => return Err(Connection(ProtocolError)),
};
@@ -114,9 +114,9 @@ impl<T> FramedRead<T> {
Ok(_) => {}
Err(frame::Error::MalformedMessage) => {
return Err(Stream {
id: head.stream_id(),
reason: ProtocolError,
});
id: head.stream_id(),
reason: ProtocolError,
});
}
Err(_) => return Err(Connection(ProtocolError)),
}
@@ -125,9 +125,9 @@ impl<T> FramedRead<T> {
} else {
// Defer loading the frame
self.partial = Some(Partial {
frame: Continuable::Headers(headers),
buf: payload,
});
frame: Continuable::Headers(headers),
buf: payload,
});
return Ok(None);
}
@@ -157,9 +157,9 @@ impl<T> FramedRead<T> {
// treat this as a stream error (Section 5.4.2) of type
// `PROTOCOL_ERROR`.
return Err(Stream {
id: head.stream_id(),
reason: ProtocolError,
});
id: head.stream_id(),
reason: ProtocolError,
});
}
Err(_) => return Err(Connection(ProtocolError)),
}
@@ -192,9 +192,9 @@ impl<T> FramedRead<T> {
Ok(_) => {}
Err(frame::Error::MalformedMessage) => {
return Err(Stream {
id: head.stream_id(),
reason: ProtocolError,
});
id: head.stream_id(),
reason: ProtocolError,
});
}
Err(_) => return Err(Connection(ProtocolError)),
}
@@ -234,7 +234,8 @@ impl<T> FramedRead<T> {
}
impl<T> Stream for FramedRead<T>
where T: AsyncRead,
where
T: AsyncRead,
{
type Item = Frame;
type Error = RecvError;
@@ -248,7 +249,7 @@ impl<T> Stream for FramedRead<T>
};
trace!("poll; bytes={}B", bytes.len());
if let Some(frame) = try!(self.decode_frame(bytes)) {
if let Some(frame) = self.decode_frame(bytes)? {
debug!("received; frame={:?}", frame);
return Ok(Async::Ready(Some(frame)));
}

View File

@@ -3,9 +3,9 @@ use codec::UserError::*;
use frame::{self, Frame, FrameSize};
use hpack;
use bytes::{Buf, BufMut, BytesMut};
use futures::*;
use tokio_io::{AsyncRead, AsyncWrite};
use bytes::{BytesMut, Buf, BufMut};
use std::io::{self, Cursor};
@@ -51,8 +51,9 @@ const CHAIN_THRESHOLD: usize = 256;
// TODO: Make generic
impl<T, B> FramedWrite<T, B>
where T: AsyncWrite,
B: Buf,
where
T: AsyncWrite,
B: Buf,
{
pub fn new(inner: T) -> FramedWrite<T, B> {
FramedWrite {
@@ -72,7 +73,7 @@ impl<T, B> FramedWrite<T, B>
pub fn poll_ready(&mut self) -> Poll<(), io::Error> {
if !self.has_capacity() {
// Try flushing
try!(self.flush());
self.flush()?;
if !self.has_capacity() {
return Ok(Async::NotReady);
@@ -248,7 +249,8 @@ impl<T: io::Read, B> io::Read for FramedWrite<T, B> {
impl<T: AsyncRead, B> AsyncRead for FramedWrite<T, B> {
fn read_buf<B2: BufMut>(&mut self, buf: &mut B2) -> Poll<usize, io::Error>
where Self: Sized,
where
Self: Sized,
{
self.inner.read_buf(buf)
}

View File

@@ -2,12 +2,12 @@ mod error;
mod framed_read;
mod framed_write;
pub use self::error::{SendError, RecvError, UserError};
pub use self::error::{RecvError, SendError, UserError};
use self::framed_read::FramedRead;
use self::framed_write::FramedWrite;
use frame::{self, Frame, Data};
use frame::{self, Data, Frame};
use futures::*;
@@ -24,16 +24,14 @@ pub struct Codec<T, B> {
}
impl<T, B> Codec<T, B>
where T: AsyncRead + AsyncWrite,
B: Buf,
where
T: AsyncRead + AsyncWrite,
B: Buf,
{
/// Returns a new `Codec` with the default max frame size
#[inline]
pub fn new(io: T) -> Self {
Self::with_max_recv_frame_size(
io,
frame::DEFAULT_MAX_FRAME_SIZE as usize
)
Self::with_max_recv_frame_size(io, frame::DEFAULT_MAX_FRAME_SIZE as usize)
}
/// Returns a new `Codec` with the given maximum frame size
@@ -52,12 +50,13 @@ impl<T, B> Codec<T, B>
let inner = FramedRead::new(delimited);
Codec { inner }
Codec {
inner,
}
}
}
impl<T, B> Codec<T, B> {
/// Updates the max received frame size.
///
/// The change takes effect the next time a frame is decoded. In other
@@ -68,7 +67,6 @@ impl<T, B> Codec<T, B> {
pub fn set_max_recv_frame_size(&mut self, val: usize) {
// TODO: should probably make some assertions about max frame size...
self.inner.set_max_frame_size(val)
}
/// Returns the current max received frame size setting.
@@ -112,8 +110,9 @@ impl<T, B> Codec<T, B> {
}
impl<T, B> Codec<T, B>
where T: AsyncWrite,
B: Buf,
where
T: AsyncWrite,
B: Buf,
{
/// Returns `Ready` when the codec can buffer a frame
pub fn poll_ready(&mut self) -> Poll<(), io::Error> {
@@ -126,8 +125,7 @@ impl<T, B> Codec<T, B>
/// accepted.
///
/// TODO: Rename this to avoid conflicts with Sink::buffer
pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError>
{
pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
self.framed_write().buffer(item)
}
@@ -143,7 +141,8 @@ impl<T, B> Codec<T, B>
}
impl<T, B> Stream for Codec<T, B>
where T: AsyncRead,
where
T: AsyncRead,
{
type Item = Frame;
type Error = RecvError;
@@ -154,8 +153,9 @@ impl<T, B> Stream for Codec<T, B>
}
impl<T, B> Sink for Codec<T, B>
where T: AsyncWrite,
B: Buf,
where
T: AsyncWrite,
B: Buf,
{
type SinkItem = Frame<B>;
type SinkError = SendError;
@@ -182,7 +182,8 @@ impl<T, B> Sink for Codec<T, B>
// TODO: remove (or improve) this
impl<T> From<T> for Codec<T, ::std::io::Cursor<::bytes::Bytes>>
where T: AsyncRead + AsyncWrite,
where
T: AsyncRead + AsyncWrite,
{
fn from(src: T) -> Self {
Self::new(src)

View File

@@ -44,13 +44,17 @@ impl From<proto::Error> for Error {
impl From<io::Error> for Error {
fn from(src: io::Error) -> Error {
Error { kind: Kind::Io(src) }
Error {
kind: Kind::Io(src),
}
}
}
impl From<Reason> for Error {
fn from(src: Reason) -> Error {
Error { kind: Kind::Proto(src) }
Error {
kind: Kind::Proto(src),
}
}
}
@@ -65,7 +69,9 @@ impl From<SendError> for Error {
impl From<UserError> for Error {
fn from(src: UserError) -> Error {
Error { kind: Kind::User(src) }
Error {
kind: Kind::User(src),
}
}
}

View File

@@ -1,5 +1,5 @@
use frame::{util, Frame, Head, Error, StreamId, Kind};
use bytes::{BufMut, Bytes, Buf};
use bytes::{Buf, BufMut, Bytes};
use frame::{util, Error, Frame, Head, Kind, StreamId};
use std::fmt;
@@ -92,7 +92,8 @@ impl<T> Data<T> {
}
pub(crate) fn map<F, U>(self, f: F) -> Data<U>
where F: FnOnce(T) -> U,
where
F: FnOnce(T) -> U,
{
Data {
stream_id: self.stream_id,
@@ -120,11 +121,11 @@ impl Data<Bytes> {
};
Ok(Data {
stream_id: head.stream_id(),
data: payload,
flags: flags,
pad_len: pad_len,
})
stream_id: head.stream_id(),
data: payload,
flags: flags,
pad_len: pad_len,
})
}
}

View File

@@ -1,6 +1,6 @@
use frame::{self, Head, Error, Kind, StreamId, Reason};
use frame::{self, Error, Head, Kind, Reason, StreamId};
use bytes::{BufMut, BigEndian};
use bytes::{BigEndian, BufMut};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct GoAway {
@@ -35,9 +35,9 @@ impl GoAway {
let error_code = unpack_octets_4!(payload, 4, u32);
Ok(GoAway {
last_stream_id: last_stream_id,
error_code: error_code,
})
last_stream_id: last_stream_id,
error_code: error_code,
})
}
pub fn encode<B: BufMut>(&self, dst: &mut B) {

View File

@@ -1,6 +1,6 @@
use super::StreamId;
use bytes::{BufMut, BigEndian};
use bytes::{BigEndian, BufMut};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Head {

View File

@@ -1,12 +1,12 @@
use super::{StreamId, StreamDependency};
use super::{StreamDependency, StreamId};
use frame::{self, Error, Frame, Head, Kind};
use hpack;
use frame::{self, Frame, Head, Kind, Error};
use http::{uri, Method, StatusCode, Uri, HeaderMap};
use http::{uri, HeaderMap, Method, StatusCode, Uri};
use http::header::{self, HeaderName, HeaderValue};
use bytes::{BytesMut, Bytes};
use byteorder::{BigEndian, ByteOrder};
use bytes::{Bytes, BytesMut};
use string::String;
use std::fmt;
@@ -89,10 +89,7 @@ const END_STREAM: u8 = 0x1;
const END_HEADERS: u8 = 0x4;
const PADDED: u8 = 0x8;
const PRIORITY: u8 = 0x20;
const ALL: u8 = END_STREAM
| END_HEADERS
| PADDED
| PRIORITY;
const ALL: u8 = END_STREAM | END_HEADERS | PADDED | PRIORITY;
// ===== impl Headers =====
@@ -124,9 +121,7 @@ impl Headers {
/// Loads the header frame but doesn't actually do HPACK decoding.
///
/// HPACK decoding is done in the `load_hpack` step.
pub fn load(head: Head, mut src: BytesMut)
-> Result<(Self, BytesMut), Error>
{
pub fn load(head: Head, mut src: BytesMut) -> Result<(Self, BytesMut), Error> {
let flags = HeadersFlag(head.flag());
let mut pad = 0;
@@ -177,11 +172,7 @@ impl Headers {
Ok((headers, src))
}
pub fn load_hpack(&mut self,
src: BytesMut,
decoder: &mut hpack::Decoder)
-> Result<(), Error>
{
pub fn load_hpack(&mut self, src: BytesMut, decoder: &mut hpack::Decoder) -> Result<(), Error> {
let mut reg = false;
let mut malformed = false;
@@ -210,7 +201,10 @@ impl Headers {
use hpack::Header::*;
match header {
Field { name, value } => {
Field {
name,
value,
} => {
// Connection level header fields are not supported and must
// result in a protocol error.
@@ -274,9 +268,7 @@ impl Headers {
self.fields
}
pub fn encode(self, encoder: &mut hpack::Encoder, dst: &mut BytesMut)
-> Option<Continuation>
{
pub fn encode(self, encoder: &mut hpack::Encoder, dst: &mut BytesMut) -> Option<Continuation> {
let head = self.head();
let pos = dst.len();
@@ -295,10 +287,10 @@ impl Headers {
hpack::Encode::Full => None,
hpack::Encode::Partial(state) => {
Some(Continuation {
stream_id: self.stream_id,
hpack: state,
headers: headers,
})
stream_id: self.stream_id,
hpack: state,
headers: headers,
})
}
};
@@ -306,7 +298,7 @@ impl Headers {
let len = (dst.len() - pos) - frame::HEADER_LEN;
// Write the frame length
BigEndian::write_uint(&mut dst[pos..pos+3], len as u64, 3);
BigEndian::write_uint(&mut dst[pos..pos + 3], len as u64, 3);
ret
}
@@ -336,9 +328,7 @@ impl fmt::Debug for Headers {
// ===== impl PushPromise =====
impl PushPromise {
pub fn load(head: Head, payload: &[u8])
-> Result<Self, Error>
{
pub fn load(head: Head, payload: &[u8]) -> Result<Self, Error> {
let flags = PushPromiseFlag(head.flag());
// TODO: Handle padding
@@ -346,10 +336,10 @@ impl PushPromise {
let (promised_id, _) = StreamId::parse(&payload[..4]);
Ok(PushPromise {
stream_id: head.stream_id(),
promised_id: promised_id,
flags: flags,
})
stream_id: head.stream_id(),
promised_id: promised_id,
flags: flags,
})
}
pub fn stream_id(&self) -> StreamId {
@@ -377,7 +367,8 @@ impl Pseudo {
unsafe { String::from_utf8_unchecked(src) }
}
let path = parts.path_and_query
let path = parts
.path_and_query
.map(|v| v.into())
.unwrap_or_else(|| Bytes::from_static(b"/"));
@@ -456,10 +447,12 @@ impl Iterator for Iter {
self.pseudo = None;
self.fields.next()
.map(|(name, value)| {
Field { name: name, value: value}
})
self.fields.next().map(|(name, value)| {
Field {
name: name,
value: value,
}
})
}
}

View File

@@ -42,7 +42,7 @@ mod window_update;
pub use self::data::Data;
pub use self::go_away::GoAway;
pub use self::head::{Head, Kind};
pub use self::headers::{Headers, PushPromise, Continuation, Pseudo};
pub use self::headers::{Continuation, Headers, Pseudo, PushPromise};
pub use self::ping::Ping;
pub use self::priority::{Priority, StreamDependency};
pub use self::reason::Reason;
@@ -52,10 +52,11 @@ pub use self::stream_id::StreamId;
pub use self::window_update::WindowUpdate;
// Re-export some constants
pub use self::settings::{
DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
DEFAULT_INITIAL_WINDOW_SIZE,
DEFAULT_MAX_FRAME_SIZE,
DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
MAX_INITIAL_WINDOW_SIZE,
MAX_MAX_FRAME_SIZE,
};
@@ -74,12 +75,13 @@ pub enum Frame<T = Bytes> {
Ping(Ping),
GoAway(GoAway),
WindowUpdate(WindowUpdate),
Reset(Reset)
Reset(Reset),
}
impl<T> Frame<T> {
pub fn map<F, U>(self, f: F) -> Frame<U>
where F: FnOnce(T) -> U
where
F: FnOnce(T) -> U,
{
use self::Frame::*;

View File

@@ -1,5 +1,5 @@
use bytes::{Buf, BufMut, IntoBuf};
use frame::{Frame, Head, Kind, Error, StreamId};
use frame::{Error, Frame, Head, Kind, StreamId};
const ACK_FLAG: u8 = 0x1;
@@ -21,7 +21,10 @@ impl Ping {
}
pub fn pong(payload: Payload) -> Ping {
Ping { ack: true, payload }
Ping {
ack: true,
payload,
}
}
pub fn is_ack(&self) -> bool {
@@ -65,7 +68,10 @@ impl Ping {
// endpoint MUST NOT respond to PING frames containing this flag.
let ack = head.flag() & ACK_FLAG != 0;
Ok(Ping { ack, payload })
Ok(Ping {
ack,
payload,
})
}
pub fn encode<B: BufMut>(&self, dst: &mut B) {

View File

@@ -29,9 +29,9 @@ impl Priority {
}
Ok(Priority {
stream_id: head.stream_id(),
dependency: dependency,
})
stream_id: head.stream_id(),
dependency: dependency,
})
}
}
@@ -63,10 +63,7 @@ impl StreamDependency {
// Read the weight
let weight = src[4];
Ok(StreamDependency::new(
dependency_id,
weight,
is_exclusive))
Ok(StreamDependency::new(dependency_id, weight, is_exclusive))
}
pub fn dependency_id(&self) -> StreamId {

View File

@@ -37,7 +37,10 @@ impl Reason {
RefusedStream => "refused stream before processing any application logic",
Cancel => "stream no longer needed",
CompressionError => "unable to maintain the header compression context",
ConnectError => "connection established in response to a CONNECT request was reset or abnormally closed",
ConnectError => {
"connection established in response to a CONNECT request \
was reset or abnormally closed"
}
EnhanceYourCalm => "detected excessive load generating behavior",
InadequateSecurity => "security properties do not meet minimum requirements",
Http11Required => "endpoint requires HTTP/1.1",

View File

@@ -1,6 +1,6 @@
use frame::{self, Head, Error, Kind, StreamId, Reason};
use frame::{self, Error, Head, Kind, Reason, StreamId};
use bytes::{BufMut, BigEndian};
use bytes::{BigEndian, BufMut};
#[derive(Debug, Eq, PartialEq)]
pub struct Reset {
@@ -32,13 +32,15 @@ impl Reset {
let error_code = unpack_octets_4!(payload, 0, u32);
Ok(Reset {
stream_id: head.stream_id(),
error_code: error_code,
})
stream_id: head.stream_id(),
error_code: error_code,
})
}
pub fn encode<B: BufMut>(&self, dst: &mut B) {
trace!("encoding RESET; id={:?} code={}", self.stream_id, self.error_code);
trace!("encoding RESET; id={:?} code={}",
self.stream_id,
self.error_code);
let head = Head::new(Kind::Reset, 0, self.stream_id);
head.encode(4, dst);
dst.put_u32::<BigEndian>(self.error_code);

View File

@@ -1,5 +1,5 @@
use frame::{Frame, FrameSize, Error, Head, Kind, StreamId};
use bytes::{BytesMut, BufMut, BigEndian};
use bytes::{BigEndian, BufMut, BytesMut};
use frame::{Error, Frame, FrameSize, Head, Kind, StreamId};
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct Settings {
@@ -54,7 +54,7 @@ impl Settings {
pub fn ack() -> Settings {
Settings {
flags: SettingsFlags::ack(),
.. Settings::default()
..Settings::default()
}
}

View File

@@ -1,6 +1,6 @@
use frame::{self, Head, Kind, Error, StreamId};
use frame::{self, Error, Head, Kind, StreamId};
use bytes::{BufMut, BigEndian};
use bytes::{BigEndian, BufMut};
const SIZE_INCREMENT_MASK: u32 = 1 << 31;
@@ -42,9 +42,9 @@ impl WindowUpdate {
}
Ok(WindowUpdate {
stream_id: head.stream_id(),
size_increment,
})
stream_id: head.stream_id(),
size_increment,
})
}
pub fn encode<B: BufMut>(&self, dst: &mut B) {

View File

@@ -1,15 +1,15 @@
use super::{huffman, Header};
use frame;
use http::{header};
use bytes::{Buf, Bytes, BytesMut};
use http::header;
use http::method::{self, Method};
use http::status::{self, StatusCode};
use bytes::{Buf, Bytes, BytesMut};
use string::String;
use std::cmp;
use std::io::Cursor;
use std::collections::VecDeque;
use std::io::Cursor;
use std::str::Utf8Error;
/// Decodes headers using HPACK
@@ -164,7 +164,8 @@ impl Decoder {
/// Decodes the headers found in the given buffer.
pub fn decode<F>(&mut self, src: &mut Cursor<Bytes>, mut f: F) -> Result<(), DecoderError>
where F: FnMut(Header)
where
F: FnMut(Header),
{
use self::Representation::*;
@@ -180,16 +181,16 @@ impl Decoder {
// At this point we are always at the beginning of the next block
// within the HPACK data. The type of the block can always be
// determined from the first byte.
match try!(Representation::load(peek_u8(src))) {
match Representation::load(peek_u8(src))? {
Indexed => {
trace!(" Indexed; rem={:?}", src.remaining());
can_resize = false;
f(try!(self.decode_indexed(src)));
f(self.decode_indexed(src)?);
}
LiteralWithIndexing => {
trace!(" LiteralWithIndexing; rem={:?}", src.remaining());
can_resize = false;
let entry = try!(self.decode_literal(src, true));
let entry = self.decode_literal(src, true)?;
// Insert the header into the table
self.table.insert(entry.clone());
@@ -199,13 +200,13 @@ impl Decoder {
LiteralWithoutIndexing => {
trace!(" LiteralWithoutIndexing; rem={:?}", src.remaining());
can_resize = false;
let entry = try!(self.decode_literal(src, false));
let entry = self.decode_literal(src, false)?;
f(entry);
}
LiteralNeverIndexed => {
trace!(" LiteralNeverIndexed; rem={:?}", src.remaining());
can_resize = false;
let entry = try!(self.decode_literal(src, false));
let entry = self.decode_literal(src, false)?;
// TODO: Track that this should never be indexed
@@ -218,7 +219,7 @@ impl Decoder {
}
// Handle the dynamic table size update
try!(self.process_size_update(src));
self.process_size_update(src)?;
}
}
}
@@ -226,52 +227,47 @@ impl Decoder {
Ok(())
}
fn process_size_update(&mut self, buf: &mut Cursor<Bytes>)
-> Result<(), DecoderError>
{
let new_size = try!(decode_int(buf, 5));
fn process_size_update(&mut self, buf: &mut Cursor<Bytes>) -> Result<(), DecoderError> {
let new_size = decode_int(buf, 5)?;
if new_size > self.last_max_update {
return Err(DecoderError::InvalidMaxDynamicSize);
}
debug!("Decoder changed max table size from {} to {}",
self.table.size(), new_size);
self.table.size(),
new_size);
self.table.set_max_size(new_size);
Ok(())
}
fn decode_indexed(&self, buf: &mut Cursor<Bytes>)
-> Result<Header, DecoderError>
{
let index = try!(decode_int(buf, 7));
fn decode_indexed(&self, buf: &mut Cursor<Bytes>) -> Result<Header, DecoderError> {
let index = decode_int(buf, 7)?;
self.table.get(index)
}
fn decode_literal(&mut self, buf: &mut Cursor<Bytes>, index: bool)
-> Result<Header, DecoderError>
{
let prefix = if index {
6
} else {
4
};
fn decode_literal(
&mut self,
buf: &mut Cursor<Bytes>,
index: bool,
) -> Result<Header, DecoderError> {
let prefix = if index { 6 } else { 4 };
// Extract the table index for the name, or 0 if not indexed
let table_idx = try!(decode_int(buf, prefix));
let table_idx = decode_int(buf, prefix)?;
// First, read the header name
if table_idx == 0 {
// Read the name as a literal
let name = try!(self.decode_string(buf));
let value = try!(self.decode_string(buf));
let name = self.decode_string(buf)?;
let value = self.decode_string(buf)?;
Header::new(name, value)
} else {
let e = try!(self.table.get(table_idx));
let value = try!(self.decode_string(buf));
let e = self.table.get(table_idx)?;
let value = self.decode_string(buf)?;
e.name().into_entry(value)
}
@@ -288,10 +284,12 @@ impl Decoder {
let huff = peek_u8(buf) & HUFF_FLAG == HUFF_FLAG;
// Decode the string length using 7 bit prefix
let len = try!(decode_int(buf, 7));
let len = decode_int(buf, 7)?;
if len > buf.remaining() {
trace!("decode_string underflow; len={}; remaining={}", len, buf.remaining());
trace!("decode_string underflow; len={}; remaining={}",
len,
buf.remaining());
return Err(DecoderError::StringUnderflow);
}
@@ -319,12 +317,12 @@ impl Default for Decoder {
impl Representation {
pub fn load(byte: u8) -> Result<Representation, DecoderError> {
const INDEXED: u8 = 0b10000000;
const LITERAL_WITH_INDEXING: u8 = 0b01000000;
const INDEXED: u8 = 0b10000000;
const LITERAL_WITH_INDEXING: u8 = 0b01000000;
const LITERAL_WITHOUT_INDEXING: u8 = 0b11110000;
const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
const SIZE_UPDATE_MASK: u8 = 0b11100000;
const SIZE_UPDATE: u8 = 0b00100000;
const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
const SIZE_UPDATE_MASK: u8 = 0b11100000;
const SIZE_UPDATE: u8 = 0b00100000;
// TODO: What did I even write here?
@@ -474,7 +472,8 @@ impl Table {
debug_assert!(size <= self.max_size);
while self.size + size > self.max_size {
let last = self.entries.pop_back()
let last = self.entries
.pop_back()
.expect("size of table != 0, but no headers left!");
self.size -= last.len();
@@ -564,194 +563,288 @@ pub fn get_static(idx: usize) -> Header {
12 => Header::Status(StatusCode::BAD_REQUEST),
13 => Header::Status(StatusCode::NOT_FOUND),
14 => Header::Status(StatusCode::INTERNAL_SERVER_ERROR),
15 => Header::Field {
name: header::ACCEPT_CHARSET,
value: HeaderValue::from_static(""),
},
16 => Header::Field {
name: header::ACCEPT_ENCODING,
value: HeaderValue::from_static("gzip, deflate"),
},
17 => Header::Field {
name: header::ACCEPT_LANGUAGE,
value: HeaderValue::from_static(""),
},
18 => Header::Field {
name: header::ACCEPT_RANGES,
value: HeaderValue::from_static(""),
},
19 => Header::Field {
name: header::ACCEPT,
value: HeaderValue::from_static(""),
},
20 => Header::Field {
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
value: HeaderValue::from_static(""),
},
21 => Header::Field {
name: header::AGE,
value: HeaderValue::from_static(""),
},
22 => Header::Field {
name: header::ALLOW,
value: HeaderValue::from_static(""),
},
23 => Header::Field {
name: header::AUTHORIZATION,
value: HeaderValue::from_static(""),
},
24 => Header::Field {
name: header::CACHE_CONTROL,
value: HeaderValue::from_static(""),
},
25 => Header::Field {
name: header::CONTENT_DISPOSITION,
value: HeaderValue::from_static(""),
},
26 => Header::Field {
name: header::CONTENT_ENCODING,
value: HeaderValue::from_static(""),
},
27 => Header::Field {
name: header::CONTENT_LANGUAGE,
value: HeaderValue::from_static(""),
},
28 => Header::Field {
name: header::CONTENT_LENGTH,
value: HeaderValue::from_static(""),
},
29 => Header::Field {
name: header::CONTENT_LOCATION,
value: HeaderValue::from_static(""),
},
30 => Header::Field {
name: header::CONTENT_RANGE,
value: HeaderValue::from_static(""),
},
31 => Header::Field {
name: header::CONTENT_TYPE,
value: HeaderValue::from_static(""),
},
32 => Header::Field {
name: header::COOKIE,
value: HeaderValue::from_static(""),
},
33 => Header::Field {
name: header::DATE,
value: HeaderValue::from_static(""),
},
34 => Header::Field {
name: header::ETAG,
value: HeaderValue::from_static(""),
},
35 => Header::Field {
name: header::EXPECT,
value: HeaderValue::from_static(""),
},
36 => Header::Field {
name: header::EXPIRES,
value: HeaderValue::from_static(""),
},
37 => Header::Field {
name: header::FROM,
value: HeaderValue::from_static(""),
},
38 => Header::Field {
name: header::HOST,
value: HeaderValue::from_static(""),
},
39 => Header::Field {
name: header::IF_MATCH,
value: HeaderValue::from_static(""),
},
40 => Header::Field {
name: header::IF_MODIFIED_SINCE,
value: HeaderValue::from_static(""),
},
41 => Header::Field {
name: header::IF_NONE_MATCH,
value: HeaderValue::from_static(""),
},
42 => Header::Field {
name: header::IF_RANGE,
value: HeaderValue::from_static(""),
},
43 => Header::Field {
name: header::IF_UNMODIFIED_SINCE,
value: HeaderValue::from_static(""),
},
44 => Header::Field {
name: header::LAST_MODIFIED,
value: HeaderValue::from_static(""),
},
45 => Header::Field {
name: header::LINK,
value: HeaderValue::from_static(""),
},
46 => Header::Field {
name: header::LOCATION,
value: HeaderValue::from_static(""),
},
47 => Header::Field {
name: header::MAX_FORWARDS,
value: HeaderValue::from_static(""),
},
48 => Header::Field {
name: header::PROXY_AUTHENTICATE,
value: HeaderValue::from_static(""),
},
49 => Header::Field {
name: header::PROXY_AUTHORIZATION,
value: HeaderValue::from_static(""),
},
50 => Header::Field {
name: header::RANGE,
value: HeaderValue::from_static(""),
},
51 => Header::Field {
name: header::REFERER,
value: HeaderValue::from_static(""),
},
52 => Header::Field {
name: header::REFRESH,
value: HeaderValue::from_static(""),
},
53 => Header::Field {
name: header::RETRY_AFTER,
value: HeaderValue::from_static(""),
},
54 => Header::Field {
name: header::SERVER,
value: HeaderValue::from_static(""),
},
55 => Header::Field {
name: header::SET_COOKIE,
value: HeaderValue::from_static(""),
},
56 => Header::Field {
name: header::STRICT_TRANSPORT_SECURITY,
value: HeaderValue::from_static(""),
},
57 => Header::Field {
name: header::TRANSFER_ENCODING,
value: HeaderValue::from_static(""),
},
58 => Header::Field {
name: header::USER_AGENT,
value: HeaderValue::from_static(""),
},
59 => Header::Field {
name: header::VARY,
value: HeaderValue::from_static(""),
},
60 => Header::Field {
name: header::VIA,
value: HeaderValue::from_static(""),
},
61 => Header::Field {
name: header::WWW_AUTHENTICATE,
value: HeaderValue::from_static(""),
},
15 => {
Header::Field {
name: header::ACCEPT_CHARSET,
value: HeaderValue::from_static(""),
}
}
16 => {
Header::Field {
name: header::ACCEPT_ENCODING,
value: HeaderValue::from_static("gzip, deflate"),
}
}
17 => {
Header::Field {
name: header::ACCEPT_LANGUAGE,
value: HeaderValue::from_static(""),
}
}
18 => {
Header::Field {
name: header::ACCEPT_RANGES,
value: HeaderValue::from_static(""),
}
}
19 => {
Header::Field {
name: header::ACCEPT,
value: HeaderValue::from_static(""),
}
}
20 => {
Header::Field {
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
value: HeaderValue::from_static(""),
}
}
21 => {
Header::Field {
name: header::AGE,
value: HeaderValue::from_static(""),
}
}
22 => {
Header::Field {
name: header::ALLOW,
value: HeaderValue::from_static(""),
}
}
23 => {
Header::Field {
name: header::AUTHORIZATION,
value: HeaderValue::from_static(""),
}
}
24 => {
Header::Field {
name: header::CACHE_CONTROL,
value: HeaderValue::from_static(""),
}
}
25 => {
Header::Field {
name: header::CONTENT_DISPOSITION,
value: HeaderValue::from_static(""),
}
}
26 => {
Header::Field {
name: header::CONTENT_ENCODING,
value: HeaderValue::from_static(""),
}
}
27 => {
Header::Field {
name: header::CONTENT_LANGUAGE,
value: HeaderValue::from_static(""),
}
}
28 => {
Header::Field {
name: header::CONTENT_LENGTH,
value: HeaderValue::from_static(""),
}
}
29 => {
Header::Field {
name: header::CONTENT_LOCATION,
value: HeaderValue::from_static(""),
}
}
30 => {
Header::Field {
name: header::CONTENT_RANGE,
value: HeaderValue::from_static(""),
}
}
31 => {
Header::Field {
name: header::CONTENT_TYPE,
value: HeaderValue::from_static(""),
}
}
32 => {
Header::Field {
name: header::COOKIE,
value: HeaderValue::from_static(""),
}
}
33 => {
Header::Field {
name: header::DATE,
value: HeaderValue::from_static(""),
}
}
34 => {
Header::Field {
name: header::ETAG,
value: HeaderValue::from_static(""),
}
}
35 => {
Header::Field {
name: header::EXPECT,
value: HeaderValue::from_static(""),
}
}
36 => {
Header::Field {
name: header::EXPIRES,
value: HeaderValue::from_static(""),
}
}
37 => {
Header::Field {
name: header::FROM,
value: HeaderValue::from_static(""),
}
}
38 => {
Header::Field {
name: header::HOST,
value: HeaderValue::from_static(""),
}
}
39 => {
Header::Field {
name: header::IF_MATCH,
value: HeaderValue::from_static(""),
}
}
40 => {
Header::Field {
name: header::IF_MODIFIED_SINCE,
value: HeaderValue::from_static(""),
}
}
41 => {
Header::Field {
name: header::IF_NONE_MATCH,
value: HeaderValue::from_static(""),
}
}
42 => {
Header::Field {
name: header::IF_RANGE,
value: HeaderValue::from_static(""),
}
}
43 => {
Header::Field {
name: header::IF_UNMODIFIED_SINCE,
value: HeaderValue::from_static(""),
}
}
44 => {
Header::Field {
name: header::LAST_MODIFIED,
value: HeaderValue::from_static(""),
}
}
45 => {
Header::Field {
name: header::LINK,
value: HeaderValue::from_static(""),
}
}
46 => {
Header::Field {
name: header::LOCATION,
value: HeaderValue::from_static(""),
}
}
47 => {
Header::Field {
name: header::MAX_FORWARDS,
value: HeaderValue::from_static(""),
}
}
48 => {
Header::Field {
name: header::PROXY_AUTHENTICATE,
value: HeaderValue::from_static(""),
}
}
49 => {
Header::Field {
name: header::PROXY_AUTHORIZATION,
value: HeaderValue::from_static(""),
}
}
50 => {
Header::Field {
name: header::RANGE,
value: HeaderValue::from_static(""),
}
}
51 => {
Header::Field {
name: header::REFERER,
value: HeaderValue::from_static(""),
}
}
52 => {
Header::Field {
name: header::REFRESH,
value: HeaderValue::from_static(""),
}
}
53 => {
Header::Field {
name: header::RETRY_AFTER,
value: HeaderValue::from_static(""),
}
}
54 => {
Header::Field {
name: header::SERVER,
value: HeaderValue::from_static(""),
}
}
55 => {
Header::Field {
name: header::SET_COOKIE,
value: HeaderValue::from_static(""),
}
}
56 => {
Header::Field {
name: header::STRICT_TRANSPORT_SECURITY,
value: HeaderValue::from_static(""),
}
}
57 => {
Header::Field {
name: header::TRANSFER_ENCODING,
value: HeaderValue::from_static(""),
}
}
58 => {
Header::Field {
name: header::USER_AGENT,
value: HeaderValue::from_static(""),
}
}
59 => {
Header::Field {
name: header::VARY,
value: HeaderValue::from_static(""),
}
}
60 => {
Header::Field {
name: header::VIA,
value: HeaderValue::from_static(""),
}
}
61 => {
Header::Field {
name: header::WWW_AUTHENTICATE,
value: HeaderValue::from_static(""),
}
}
_ => unreachable!(),
}
}

View File

@@ -1,8 +1,8 @@
use super::{huffman, Header};
use super::table::{Table, Index};
use super::table::{Index, Table};
use bytes::{BufMut, BytesMut};
use http::header::{HeaderName, HeaderValue};
use bytes::{BytesMut, BufMut};
#[derive(Debug)]
pub struct Encoder {
@@ -76,9 +76,14 @@ impl Encoder {
}
/// Encode a set of headers into the provide buffer
pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut)
-> Encode
where I: Iterator<Item=Header<Option<HeaderName>>>,
pub fn encode<I>(
&mut self,
resume: Option<EncodeState>,
headers: &mut I,
dst: &mut BytesMut,
) -> Encode
where
I: Iterator<Item = Header<Option<HeaderName>>>,
{
let len = dst.len();
@@ -94,15 +99,8 @@ impl Encoder {
let len = dst.len();
let res = match resume.value {
Some(ref value) => {
self.encode_header_without_name(
&resume.index,
value,
dst)
}
None => {
self.encode_header(&resume.index, dst)
}
Some(ref value) => self.encode_header_without_name(&resume.index, value, dst),
None => self.encode_header(&resume.index, dst),
};
if res.is_err() {
@@ -126,9 +124,9 @@ impl Encoder {
if res.is_err() {
dst.truncate(len);
return Encode::Partial(EncodeState {
index: index,
value: None,
});
index: index,
value: None,
});
}
last_index = Some(index);
@@ -138,17 +136,15 @@ impl Encoder {
// which case, we skip table lookup and just use the same index
// as the previous entry.
Err(value) => {
let res = self.encode_header_without_name(
last_index.as_ref().unwrap(),
&value,
dst);
let res =
self.encode_header_without_name(last_index.as_ref().unwrap(), &value, dst);
if res.is_err() {
dst.truncate(len);
return Encode::Partial(EncodeState {
index: last_index.unwrap(),
value: Some(value),
});
index: last_index.unwrap(),
value: Some(value),
});
}
}
};
@@ -161,13 +157,13 @@ impl Encoder {
match self.size_update.take() {
Some(SizeUpdate::One(val)) => {
self.table.resize(val);
try!(encode_size_update(val, dst));
encode_size_update(val, dst)?;
}
Some(SizeUpdate::Two(min, max)) => {
self.table.resize(min);
self.table.resize(max);
try!(encode_size_update(min, dst));
try!(encode_size_update(max, dst));
encode_size_update(min, dst)?;
encode_size_update(max, dst)?;
}
None => {}
}
@@ -175,21 +171,15 @@ impl Encoder {
Ok(())
}
fn encode_header(&mut self, index: &Index, dst: &mut BytesMut)
-> Result<(), EncoderError>
{
fn encode_header(&mut self, index: &Index, dst: &mut BytesMut) -> Result<(), EncoderError> {
match *index {
Index::Indexed(idx, _) => {
try!(encode_int(idx, 7, 0x80, dst));
encode_int(idx, 7, 0x80, dst)?;
}
Index::Name(idx, _) => {
let header = self.table.resolve(&index);
try!(encode_not_indexed(
idx,
header.value_slice(),
header.is_sensitive(),
dst));
encode_not_indexed(idx, header.value_slice(), header.is_sensitive(), dst)?;
}
Index::Inserted(_) => {
let header = self.table.resolve(&index);
@@ -202,57 +192,52 @@ impl Encoder {
dst.put_u8(0b01000000);
try!(encode_str(header.name().as_slice(), dst));
try!(encode_str(header.value_slice(), dst));
encode_str(header.name().as_slice(), dst)?;
encode_str(header.value_slice(), dst)?;
}
Index::InsertedValue(idx, _) => {
let header = self.table.resolve(&index);
assert!(!header.is_sensitive());
try!(encode_int(idx, 6, 0b01000000, dst));
try!(encode_str(header.value_slice(), dst));
encode_int(idx, 6, 0b01000000, dst)?;
encode_str(header.value_slice(), dst)?;
}
Index::NotIndexed(_) => {
let header = self.table.resolve(&index);
try!(encode_not_indexed2(
header.name().as_slice(),
header.value_slice(),
header.is_sensitive(),
dst));
encode_not_indexed2(header.name().as_slice(),
header.value_slice(),
header.is_sensitive(),
dst)?;
}
}
Ok(())
}
fn encode_header_without_name(&mut self, last: &Index,
value: &HeaderValue, dst: &mut BytesMut)
-> Result<(), EncoderError>
{
fn encode_header_without_name(
&mut self,
last: &Index,
value: &HeaderValue,
dst: &mut BytesMut,
) -> Result<(), EncoderError> {
match *last {
Index::Indexed(..) |
Index::Name(..) |
Index::Inserted(..) |
Index::InsertedValue(..) =>
{
Index::Name(..) |
Index::Inserted(..) |
Index::InsertedValue(..) => {
let idx = self.table.resolve_idx(last);
try!(encode_not_indexed(
idx,
value.as_ref(),
value.is_sensitive(),
dst));
encode_not_indexed(idx, value.as_ref(), value.is_sensitive(), dst)?;
}
Index::NotIndexed(_) => {
let last = self.table.resolve(last);
try!(encode_not_indexed2(
last.name().as_slice(),
value.as_ref(),
value.is_sensitive(),
dst));
encode_not_indexed2(last.name().as_slice(),
value.as_ref(),
value.is_sensitive(),
dst)?;
}
}
@@ -270,24 +255,28 @@ fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderE
encode_int(val, 5, 0b00100000, dst)
}
fn encode_not_indexed(name: usize, value: &[u8],
sensitive: bool, dst: &mut BytesMut)
-> Result<(), EncoderError>
{
fn encode_not_indexed(
name: usize,
value: &[u8],
sensitive: bool,
dst: &mut BytesMut,
) -> Result<(), EncoderError> {
if sensitive {
try!(encode_int(name, 4, 0b10000, dst));
encode_int(name, 4, 0b10000, dst)?;
} else {
try!(encode_int(name, 4, 0, dst));
encode_int(name, 4, 0, dst)?;
}
try!(encode_str(value, dst));
encode_str(value, dst)?;
Ok(())
}
fn encode_not_indexed2(name: &[u8], value: &[u8],
sensitive: bool, dst: &mut BytesMut)
-> Result<(), EncoderError>
{
fn encode_not_indexed2(
name: &[u8],
value: &[u8],
sensitive: bool,
dst: &mut BytesMut,
) -> Result<(), EncoderError> {
if !dst.has_remaining_mut() {
return Err(EncoderError::BufferOverflow);
}
@@ -298,8 +287,8 @@ fn encode_not_indexed2(name: &[u8], value: &[u8],
dst.put_u8(0);
}
try!(encode_str(name, dst));
try!(encode_str(value, dst));
encode_str(name, dst)?;
encode_str(value, dst)?;
Ok(())
}
@@ -317,7 +306,7 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
dst.put_u8(0);
// Encode with huffman
try!(huffman::encode(val, dst));
huffman::encode(val, dst)?;
let huff_len = dst.len() - (idx + 1);
@@ -330,7 +319,7 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
let head_len = {
let mut head_dst = Cursor::new(&mut buf);
try!(encode_int(huff_len, 7, 0x80, &mut head_dst));
encode_int(huff_len, 7, 0x80, &mut head_dst)?;
head_dst.position() as usize
};
@@ -343,8 +332,8 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
// Shift the header forward
for i in 0..huff_len {
let src_i = idx + 1 + (huff_len - (i+1));
let dst_i = idx + head_len + (huff_len - (i+1));
let src_i = idx + 1 + (huff_len - (i + 1));
let dst_i = idx + head_len + (huff_len - (i + 1));
dst[dst_i] = dst[src_i];
}
@@ -366,9 +355,8 @@ fn encode_int<B: BufMut>(
mut value: usize, // The integer to encode
prefix_bits: usize, // The number of bits in the prefix
first_byte: u8, // The base upon which to start encoding the int
dst: &mut B) // The destination buffer
-> Result<(), EncoderError>
{
dst: &mut B,
) -> Result<(), EncoderError> {
let mut rem = dst.remaining_mut();
if rem == 0 {
@@ -444,7 +432,7 @@ mod test {
let res = encode(&mut encoder, vec![method("PATCH")]);
assert_eq!(res[0], 0b01000000 | 2); // Incremental indexing w/ name pulled from table
assert_eq!(res[1], 0x80 | 5); // header value w/ huffman coding
assert_eq!(res[1], 0x80 | 5); // header value w/ huffman coding
assert_eq!("PATCH", huff_decode(&res[2..7]));
assert_eq!(encoder.table.len(), 1);
@@ -522,7 +510,7 @@ mod test {
for i in 1..65 {
let key = format!("x-hello-world-{:02}", i);
let res = encode(&mut encoder, vec![header(&key, &key)]);
assert_eq!(0x80 | (61 + (65-i)), res[0]);
assert_eq!(0x80 | (61 + (65 - i)), res[0]);
}
}
@@ -547,7 +535,10 @@ mod test {
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value };
let header = Header::Field {
name: Some(name),
value: value,
};
// Now, try to encode the sensitive header
@@ -564,7 +555,10 @@ mod test {
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value };
let header = Header::Field {
name: Some(name),
value: value,
};
let mut encoder = Encoder::default();
let res = encode(&mut encoder, vec![header]);
@@ -576,13 +570,17 @@ mod test {
// Using the name component of a previously indexed header (without
// sensitive flag set)
let _ = encode(&mut encoder, vec![self::header("my-password", "not-so-secret")]);
let _ = encode(&mut encoder,
vec![self::header("my-password", "not-so-secret")]);
let name = "my-password".parse().unwrap();
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value };
let header = Header::Field {
name: Some(name),
value: value,
};
let res = encode(&mut encoder, vec![header]);
assert_eq!(&[0b11111, 47], &res[..2]);
@@ -743,16 +741,19 @@ mod test {
fn test_nameless_header() {
let mut encoder = Encoder::default();
let res = encode(&mut encoder, vec![
Header::Field {
name: Some("hello".parse().unwrap()),
value: HeaderValue::from_bytes(b"world").unwrap(),
},
Header::Field {
name: None,
value: HeaderValue::from_bytes(b"zomg").unwrap(),
},
]);
let res = encode(
&mut encoder,
vec![
Header::Field {
name: Some("hello".parse().unwrap()),
value: HeaderValue::from_bytes(b"world").unwrap(),
},
Header::Field {
name: None,
value: HeaderValue::from_bytes(b"zomg").unwrap(),
},
],
);
assert_eq!(&[0x40, 0x80 | 4], &res[0..2]);
assert_eq!("hello", huff_decode(&res[2..6]));
@@ -824,7 +825,10 @@ mod test {
let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
let value = HeaderValue::from_bytes(val.as_bytes()).unwrap();
Header::Field { name: Some(name), value: value }
Header::Field {
name: Some(name),
value: value,
}
}
fn huff_decode(src: &[u8]) -> BytesMut {

View File

@@ -1,17 +1,14 @@
use super::DecoderError;
use bytes::Bytes;
use http::{Method, StatusCode};
use http::header::{HeaderName, HeaderValue};
use bytes::Bytes;
use string::{String, TryFrom};
/// HTTP/2.0 Header
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Header<T = HeaderName> {
Field {
name: T,
value: HeaderValue,
},
Field { name: T, value: HeaderValue },
// TODO: Change these types to `http::uri` types.
Authority(String<Bytes>),
Method(Method),
@@ -41,14 +38,25 @@ impl Header<Option<HeaderName>> {
use self::Header::*;
Ok(match self {
Field { name: Some(n), value } => Field { name: n, value: value },
Field { name: None, value } => return Err(value),
Authority(v) => Authority(v),
Method(v) => Method(v),
Scheme(v) => Scheme(v),
Path(v) => Path(v),
Status(v) => Status(v),
})
Field {
name: Some(n),
value,
} => {
Field {
name: n,
value: value,
}
}
Field {
name: None,
value,
} => return Err(value),
Authority(v) => Authority(v),
Method(v) => Method(v),
Scheme(v) => Scheme(v),
Path(v) => Path(v),
Status(v) => Status(v),
})
}
}
@@ -57,65 +65,59 @@ impl Header {
if name[0] == b':' {
match &name[1..] {
b"authority" => {
let value = try!(String::try_from(value));
let value = String::try_from(value)?;
Ok(Header::Authority(value))
}
b"method" => {
let method = try!(Method::from_bytes(&value));
let method = Method::from_bytes(&value)?;
Ok(Header::Method(method))
}
b"scheme" => {
let value = try!(String::try_from(value));
let value = String::try_from(value)?;
Ok(Header::Scheme(value))
}
b"path" => {
let value = try!(String::try_from(value));
let value = String::try_from(value)?;
Ok(Header::Path(value))
}
b"status" => {
let status = try!(StatusCode::from_bytes(&value));
let status = StatusCode::from_bytes(&value)?;
Ok(Header::Status(status))
}
_ => {
Err(DecoderError::InvalidPseudoheader)
}
_ => Err(DecoderError::InvalidPseudoheader),
}
} else {
// HTTP/2 requires lower case header names
let name = try!(HeaderName::from_lowercase(&name));
let value = try!(HeaderValue::from_bytes(&value));
let name = HeaderName::from_lowercase(&name)?;
let value = HeaderValue::from_bytes(&value)?;
Ok(Header::Field { name: name, value: value })
Ok(Header::Field {
name: name,
value: value,
})
}
}
pub fn len(&self) -> usize {
match *self {
Header::Field { ref name, ref value } => {
len(name, value)
}
Header::Authority(ref v) => {
32 + 10 + v.len()
}
Header::Method(ref v) => {
32 + 7 + v.as_ref().len()
}
Header::Scheme(ref v) => {
32 + 7 + v.len()
}
Header::Path(ref v) => {
32 + 5 + v.len()
}
Header::Status(_) => {
32 + 7 + 3
}
Header::Field {
ref name,
ref value,
} => len(name, value),
Header::Authority(ref v) => 32 + 10 + v.len(),
Header::Method(ref v) => 32 + 7 + v.as_ref().len(),
Header::Scheme(ref v) => 32 + 7 + v.len(),
Header::Path(ref v) => 32 + 5 + v.len(),
Header::Status(_) => 32 + 7 + 3,
}
}
/// Returns the header name
pub fn name(&self) -> Name {
match *self {
Header::Field { ref name, .. } => Name::Field(name),
Header::Field {
ref name, ..
} => Name::Field(name),
Header::Authority(..) => Name::Authority,
Header::Method(..) => Name::Method,
Header::Scheme(..) => Name::Scheme,
@@ -126,7 +128,9 @@ impl Header {
pub fn value_slice(&self) -> &[u8] {
match *self {
Header::Field { ref value, .. } => value.as_ref(),
Header::Field {
ref value, ..
} => value.as_ref(),
Header::Authority(ref v) => v.as_ref(),
Header::Method(ref v) => v.as_ref().as_ref(),
Header::Scheme(ref v) => v.as_ref(),
@@ -137,10 +141,14 @@ impl Header {
pub fn value_eq(&self, other: &Header) -> bool {
match *self {
Header::Field { ref value, .. } => {
Header::Field {
ref value, ..
} => {
let a = value;
match *other {
Header::Field { ref value, .. } => a == value,
Header::Field {
ref value, ..
} => a == value,
_ => false,
}
}
@@ -179,7 +187,9 @@ impl Header {
pub fn is_sensitive(&self) -> bool {
match *self {
Header::Field { ref value, .. } => value.is_sensitive(),
Header::Field {
ref value, ..
} => value.is_sensitive(),
// TODO: Technically these other header values can be sensitive too.
_ => false,
}
@@ -189,17 +199,19 @@ impl Header {
use http::header;
match *self {
Header::Field { ref name, .. } => {
Header::Field {
ref name, ..
} => {
match *name {
header::AGE |
header::AUTHORIZATION |
header::CONTENT_LENGTH |
header::ETAG |
header::IF_MODIFIED_SINCE |
header::IF_NONE_MATCH |
header::LOCATION |
header::COOKIE |
header::SET_COOKIE => true,
header::AUTHORIZATION |
header::CONTENT_LENGTH |
header::ETAG |
header::IF_MODIFIED_SINCE |
header::IF_NONE_MATCH |
header::LOCATION |
header::COOKIE |
header::SET_COOKIE => true,
_ => false,
}
}
@@ -213,7 +225,15 @@ impl Header {
impl From<Header> for Header<Option<HeaderName>> {
fn from(src: Header) -> Self {
match src {
Header::Field { name, value } => Header::Field { name: Some(name), value },
Header::Field {
name,
value,
} => {
Header::Field {
name: Some(name),
value,
}
}
Header::Authority(v) => Header::Authority(v),
Header::Method(v) => Header::Method(v),
Header::Scheme(v) => Header::Scheme(v),
@@ -228,22 +248,14 @@ impl<'a> Name<'a> {
match self {
Name::Field(name) => {
Ok(Header::Field {
name: name.clone(),
value: try!(HeaderValue::from_bytes(&*value)),
})
}
Name::Authority => {
Ok(Header::Authority(try!(String::try_from(value))))
}
Name::Method => {
Ok(Header::Method(try!(Method::from_bytes(&*value))))
}
Name::Scheme => {
Ok(Header::Scheme(try!(String::try_from(value))))
}
Name::Path => {
Ok(Header::Path(try!(String::try_from(value))))
name: name.clone(),
value: HeaderValue::from_bytes(&*value)?,
})
}
Name::Authority => Ok(Header::Authority(String::try_from(value)?)),
Name::Method => Ok(Header::Method(Method::from_bytes(&*value)?)),
Name::Scheme => Ok(Header::Scheme(String::try_from(value)?)),
Name::Path => Ok(Header::Path(String::try_from(value)?)),
Name::Status => {
match StatusCode::from_bytes(&value) {
Ok(status) => Ok(Header::Status(status)),

View File

@@ -1,9 +1,9 @@
mod table;
use self::table::{ENCODE_TABLE, DECODE_TABLE};
use self::table::{DECODE_TABLE, ENCODE_TABLE};
use hpack::{DecoderError, EncoderError};
use bytes::{BytesMut, BufMut};
use bytes::{BufMut, BytesMut};
// Constructed in the generated `table.rs` file
struct Decoder {
@@ -24,11 +24,11 @@ pub fn decode(src: &[u8], buf: &mut BytesMut) -> Result<BytesMut, DecoderError>
buf.reserve(src.len() << 1);
for b in src {
if let Some(b) = try!(decoder.decode4(b >> 4)) {
if let Some(b) = decoder.decode4(b >> 4)? {
buf.put_u8(b);
}
if let Some(b) = try!(decoder.decode4(b & 0xf)) {
if let Some(b) = decoder.decode4(b & 0xf)? {
buf.put_u8(b);
}
}
@@ -161,10 +161,27 @@ mod test {
#[test]
fn encode_decode_str() {
const DATA: &'static [&'static str] = &[
"hello world", ":method", ":scheme", ":authority", "yahoo.co.jp", "GET", "http", ":path", "/images/top/sp2/cmn/logo-ns-130528.png",
"example.com", "hpack-test", "xxxxxxx1", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
"accept", "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "cookie", "B=76j09a189a6h4&b=3&s=0b",
"TE", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi non bibendum libero. Etiam ultrices lorem ut",
"hello world",
":method",
":scheme",
":authority",
"yahoo.co.jp",
"GET",
"http",
":path",
"/images/top/sp2/cmn/logo-ns-130528.png",
"example.com",
"hpack-test",
"xxxxxxx1",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
"accept",
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"cookie",
"B=76j09a189a6h4&b=3&s=0b",
"TE",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi non bibendum libero. \
Etiam ultrices lorem ut.",
];
for s in DATA {
@@ -180,9 +197,8 @@ mod test {
#[test]
fn encode_decode_u8() {
const DATA: &'static [&'static [u8]] = &[
b"\0", b"\0\0\0", b"\0\x01\x02\x03\x04\x05", b"\xFF\xF8",
];
const DATA: &'static [&'static [u8]] =
&[b"\0", b"\0\0\0", b"\0\x01\x02\x03\x04\x05", b"\xFF\xF8"];
for s in DATA {
let mut dst = Vec::with_capacity(s.len());

View File

@@ -7,6 +7,6 @@ mod table;
#[cfg(test)]
mod test;
pub use self::encoder::{Encoder, Encode, EncoderError, EncodeState};
pub use self::header::Header;
pub use self::decoder::{Decoder, DecoderError};
pub use self::encoder::{Encode, EncodeState, Encoder, EncoderError};
pub use self::header::Header;

View File

@@ -83,9 +83,7 @@ impl Table {
max_size: max_size,
}
} 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);
Table {
mask: capacity.wrapping_sub(1),
@@ -203,12 +201,7 @@ impl Table {
});
}
fn index_occupied(&mut self,
header: Header,
hash: HashValue,
mut index: usize)
-> Index
{
fn index_occupied(&mut self, header: Header, hash: HashValue, mut index: usize) -> Index {
debug_assert!(self.assert_valid_state("top"));
// There already is a match for the given header name. Check if a value
@@ -256,14 +249,14 @@ impl Table {
}
}
fn index_vacant(&mut self,
header: Header,
hash: HashValue,
mut dist: usize,
mut probe: usize,
statik: Option<(usize, bool)>)
-> Index
{
fn index_vacant(
&mut self,
header: Header,
hash: HashValue,
mut dist: usize,
mut probe: usize,
statik: Option<(usize, bool)>,
) -> Index {
if header.is_sensitive() {
return Index::new(statik, header);
}
@@ -299,10 +292,11 @@ impl Table {
let pos_idx = 0usize.wrapping_sub(self.inserted);
let prev = mem::replace(&mut self.indices[probe], Some(Pos {
index: pos_idx,
hash: hash,
}));
let prev = mem::replace(&mut self.indices[probe],
Some(Pos {
index: pos_idx,
hash: hash,
}));
if let Some(mut prev) = prev {
// Shift forward
@@ -331,10 +325,10 @@ impl Table {
self.inserted = self.inserted.wrapping_add(1);
self.slots.push_front(Slot {
hash: hash,
header: header,
next: None,
});
hash: hash,
header: header,
next: None,
});
}
pub fn resize(&mut self, size: usize) {
@@ -383,11 +377,12 @@ impl Table {
// Update the size
self.size -= slot.header.len();
debug_assert_eq!(
self.indices.iter().filter_map(|p| *p)
.filter(|p| p.index == pos_idx)
.count(),
1);
debug_assert_eq!(self.indices
.iter()
.filter_map(|p| *p)
.filter(|p| p.index == pos_idx)
.count(),
1);
// Find the associated position
probe_loop!(probe < self.indices.len(), {
@@ -500,12 +495,12 @@ impl Table {
}
debug_assert!({
let them = self.indices[probe].unwrap();
let their_distance = probe_distance(self.mask, them.hash, probe);
let our_distance = probe_distance(self.mask, pos.hash, probe);
let them = self.indices[probe].unwrap();
let their_distance = probe_distance(self.mask, them.hash, probe);
let our_distance = probe_distance(self.mask, pos.hash, probe);
their_distance >= our_distance
});
their_distance >= our_distance
});
});
}
}
@@ -584,8 +579,10 @@ impl Table {
}
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);
"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;
});
@@ -661,7 +658,10 @@ fn hash_header(header: &Header) -> HashValue {
/// boolean representing if the value matched as well.
fn index_static(header: &Header) -> Option<(usize, bool)> {
match *header {
Header::Field { ref name, ref value } => {
Header::Field {
ref name,
ref value,
} => {
match *name {
header::ACCEPT_CHARSET => Some((15, false)),
header::ACCEPT_ENCODING => {

View File

@@ -2,15 +2,15 @@ extern crate bytes;
extern crate hex;
extern crate serde_json;
use hpack::{Header, Decoder, Encoder};
use hpack::{Decoder, Encoder, Header};
use self::bytes::BytesMut;
use self::hex::FromHex;
use self::serde_json::Value;
use std::fs::File;
use std::io::prelude::*;
use std::io::Cursor;
use std::io::prelude::*;
use std::path::Path;
use std::str;
@@ -27,7 +27,10 @@ fn test_story(story: Value) {
let story = story.as_object().unwrap();
if let Some(cases) = story.get("cases") {
let mut cases: Vec<_> = cases.as_array().unwrap().iter()
let mut cases: Vec<_> = cases
.as_array()
.unwrap()
.iter()
.map(|case| {
let case = case.as_object().unwrap();
@@ -37,8 +40,11 @@ fn test_story(story: Value) {
let wire = case.get("wire").unwrap().as_str().unwrap();
let wire: Vec<u8> = FromHex::from_hex(wire.as_bytes()).unwrap();
let expect: Vec<_> = case.get("headers").unwrap()
.as_array().unwrap().iter()
let expect: Vec<_> = case.get("headers")
.unwrap()
.as_array()
.unwrap()
.iter()
.map(|h| {
let h = h.as_object().unwrap();
let (name, val) = h.iter().next().unwrap();
@@ -67,11 +73,13 @@ fn test_story(story: Value) {
decoder.queue_size_update(size);
}
decoder.decode(&mut Cursor::new(case.wire.clone().into()), |e| {
let (name, value) = expect.remove(0);
assert_eq!(name, key_str(&e));
assert_eq!(value, value_str(&e));
}).unwrap();
decoder
.decode(&mut Cursor::new(case.wire.clone().into()), |e| {
let (name, value) = expect.remove(0);
assert_eq!(name, key_str(&e));
assert_eq!(value, value_str(&e));
})
.unwrap();
assert_eq!(0, expect.len());
}
@@ -88,15 +96,22 @@ fn test_story(story: Value) {
decoder.queue_size_update(size);
}
let mut input: Vec<_> = case.expect.iter().map(|&(ref name, ref value)| {
Header::new(name.clone().into(), value.clone().into()).unwrap().into()
}).collect();
let mut input: Vec<_> = case.expect
.iter()
.map(|&(ref name, ref value)| {
Header::new(name.clone().into(), value.clone().into())
.unwrap()
.into()
})
.collect();
encoder.encode(None, &mut input.clone().into_iter(), &mut buf);
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, input.remove(0).reify().unwrap());
}).unwrap();
decoder
.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, input.remove(0).reify().unwrap());
})
.unwrap();
assert_eq!(0, input.len());
}
@@ -112,7 +127,9 @@ struct Case {
fn key_str(e: &Header) -> &str {
match *e {
Header::Field { ref name, .. } => name.as_str(),
Header::Field {
ref name, ..
} => name.as_str(),
Header::Authority(..) => ":authority",
Header::Method(..) => ":method",
Header::Scheme(..) => ":scheme",
@@ -123,7 +140,9 @@ fn key_str(e: &Header) -> &str {
fn value_str(e: &Header) -> &str {
match *e {
Header::Field { ref value, .. } => value.to_str().unwrap(),
Header::Field {
ref value, ..
} => value.to_str().unwrap(),
Header::Authority(ref v) => &**v,
Header::Method(ref m) => m.as_str(),
Header::Scheme(ref v) => &**v,

View File

@@ -2,13 +2,13 @@ extern crate bytes;
extern crate quickcheck;
extern crate rand;
use hpack::{Header, Decoder, Encoder, Encode};
use hpack::{Decoder, Encode, Encoder, Header};
use http::header::{HeaderName, HeaderValue};
use self::bytes::{BytesMut, Bytes};
use self::quickcheck::{QuickCheck, Arbitrary, Gen, TestResult};
use self::rand::{StdRng, Rng, SeedableRng};
use self::bytes::{Bytes, BytesMut};
use self::quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
use self::rand::{Rng, SeedableRng, StdRng};
use std::io::Cursor;
@@ -130,8 +130,7 @@ impl FuzzHpack {
let mut index = None;
let mut input = frame.headers.into_iter();
let mut buf = BytesMut::with_capacity(
chunks.pop().unwrap_or(MAX_CHUNK));
let mut buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
if let Some(max) = frame.resizes.iter().max() {
decoder.queue_size_update(*max);
@@ -149,20 +148,23 @@ impl FuzzHpack {
index = Some(i);
// Decode the chunk!
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
}).unwrap();
decoder
.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
})
.unwrap();
buf = BytesMut::with_capacity(
chunks.pop().unwrap_or(MAX_CHUNK));
buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
}
}
}
// Decode the chunk!
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
}).unwrap();
decoder
.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
})
.unwrap();
}
assert_eq!(0, expect.len());
@@ -193,9 +195,9 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
4 => Method::DELETE,
5 => {
let n: usize = g.gen_range(3, 7);
let bytes: Vec<u8> = (0..n).map(|_| {
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap().clone()
}).collect();
let bytes: Vec<u8> = (0..n)
.map(|_| g.choose(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap().clone())
.collect();
Method::from_bytes(&bytes).unwrap()
}
@@ -237,7 +239,10 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
value.set_sensitive(true);
}
Header::Field { name: Some(name), value: value }
Header::Field {
name: Some(name),
value: value,
}
}
}
@@ -320,7 +325,8 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
header::X_DNS_PREFETCH_CONTROL,
header::X_FRAME_OPTIONS,
header::X_XSS_PROTECTION,
]).unwrap().clone()
]).unwrap()
.clone()
} else {
let value = gen_string(g, 1, 25);
HeaderName::from_bytes(value.as_bytes()).unwrap()
@@ -333,10 +339,14 @@ fn gen_header_value(g: &mut StdRng) -> HeaderValue {
}
fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
let bytes: Vec<_> = (min..max).map(|_| {
// Chars to pick from
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----").unwrap().clone()
}).collect();
let bytes: Vec<_> = (min..max)
.map(|_| {
// Chars to pick from
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----")
.unwrap()
.clone()
})
.collect();
String::from_utf8(bytes).unwrap()
}

View File

@@ -7,12 +7,15 @@ extern crate futures;
extern crate tokio_io;
// HTTP types
extern crate http;
// Buffer utilities
extern crate bytes;
// Hash function used for HPACK encoding and tracking stream states.
extern crate fnv;
extern crate byteorder;
@@ -43,4 +46,4 @@ pub mod server;
pub use error::{Error, Reason};
#[cfg(feature = "unstable")]
pub use codec::{Codec, SendError, RecvError, UserError};
pub use codec::{Codec, RecvError, SendError, UserError};

View File

@@ -1,13 +1,13 @@
use {client, frame, server, proto};
use {client, frame, proto, server};
use codec::{RecvError, SendError};
use frame::Reason;
use codec::{SendError, RecvError};
use frame::DEFAULT_INITIAL_WINDOW_SIZE;
use proto::*;
use http::Request;
use futures::{Stream};
use bytes::{Bytes, IntoBuf};
use futures::Stream;
use http::Request;
use tokio_io::{AsyncRead, AsyncWrite};
use std::marker::PhantomData;
@@ -15,7 +15,8 @@ use std::marker::PhantomData;
/// An H2 connection
#[derive(Debug)]
pub(crate) struct Connection<T, P, B: IntoBuf = Bytes>
where P: Peer,
where
P: Peer,
{
/// Tracks the connection level state transitions.
state: State,
@@ -52,18 +53,19 @@ enum State {
}
impl<T, P, B> Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
where
T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
pub fn new(codec: Codec<T, Prioritized<B::Buf>>) -> Connection<T, P, B> {
// TODO: Actually configure
let streams = Streams::new(streams::Config {
max_remote_initiated: None,
init_remote_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
max_local_initiated: None,
init_local_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
});
max_remote_initiated: None,
init_remote_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
max_local_initiated: None,
init_local_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
});
Connection {
state: State::Open,
@@ -83,7 +85,8 @@ impl<T, P, B> Connection<T, P, B>
// The order of these calls don't really matter too much as only one
// should have pending work.
try_ready!(self.ping_pong.send_pending_pong(&mut self.codec));
try_ready!(self.settings.send_pending_ack(&mut self.codec, &mut self.streams));
try_ready!(self.settings
.send_pending_ack(&mut self.codec, &mut self.streams));
try_ready!(self.streams.send_pending_refusal(&mut self.codec));
Ok(().into())
@@ -128,7 +131,10 @@ impl<T, P, B> Connection<T, P, B>
// Attempting to read a frame resulted in a stream level error.
// This is handled by resetting the frame then trying to read
// another frame.
Err(Stream { id, reason }) => {
Err(Stream {
id,
reason,
}) => {
trace!("stream level error; id={:?}; reason={:?}", id, reason);
self.streams.send_reset(id, reason);
}
@@ -146,14 +152,16 @@ impl<T, P, B> Connection<T, P, B>
return Err(e);
}
}
},
}
State::GoAway(frame) => {
// Ensure the codec is ready to accept the frame
try_ready!(self.codec.poll_ready());
// Buffer the GO_AWAY frame
self.codec.buffer(frame.into())
.ok().expect("invalid GO_AWAY frame");
self.codec
.buffer(frame.into())
.ok()
.expect("invalid GO_AWAY frame");
// GO_AWAY sent, transition the connection to an errored state
self.state = State::Flush(frame.reason());
@@ -182,15 +190,15 @@ impl<T, P, B> Connection<T, P, B>
match try_ready!(self.codec.poll()) {
Some(Headers(frame)) => {
trace!("recv HEADERS; frame={:?}", frame);
try!(self.streams.recv_headers(frame));
self.streams.recv_headers(frame)?;
}
Some(Data(frame)) => {
trace!("recv DATA; frame={:?}", frame);
try!(self.streams.recv_data(frame));
self.streams.recv_data(frame)?;
}
Some(Reset(frame)) => {
trace!("recv RST_STREAM; frame={:?}", frame);
try!(self.streams.recv_reset(frame));
self.streams.recv_reset(frame)?;
}
Some(PushPromise(frame)) => {
trace!("recv PUSH_PROMISE; frame={:?}", frame);
@@ -229,8 +237,9 @@ impl<T, P, B> Connection<T, P, B>
}
impl<T, B> Connection<T, client::Peer, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf,
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Returns `Ready` when new the connection is able to support a new request stream.
pub fn poll_send_request_ready(&mut self) -> Async<()> {
@@ -238,16 +247,19 @@ impl<T, B> Connection<T, client::Peer, B>
}
/// Initialize a new HTTP/2.0 stream and send the message.
pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<StreamRef<B::Buf, client::Peer>, SendError>
{
pub fn send_request(
&mut self,
request: Request<()>,
end_of_stream: bool,
) -> Result<StreamRef<B::Buf, client::Peer>, SendError> {
self.streams.send_request(request, end_of_stream)
}
}
impl<T, B> Connection<T, server::Peer, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf,
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
pub fn next_incoming(&mut self) -> Option<StreamRef<B::Buf, server::Peer>> {
self.streams.next_incoming()
@@ -256,9 +268,10 @@ impl<T, B> Connection<T, server::Peer, B>
#[cfg(feature = "unstable")]
impl<T, P, B> Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
where
T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
pub fn num_active_streams(&self) -> usize {
self.streams.num_active_streams()

View File

@@ -1,5 +1,5 @@
use frame::Reason;
use codec::RecvError;
use frame::Reason;
use std::io;

View File

@@ -8,7 +8,7 @@ mod streams;
pub(crate) use self::connection::Connection;
pub(crate) use self::error::Error;
pub(crate) use self::peer::Peer;
pub(crate) use self::streams::{Streams, StreamRef};
pub(crate) use self::streams::{StreamRef, Streams};
use codec::Codec;
@@ -18,7 +18,7 @@ use self::streams::Prioritized;
use frame::{self, Frame};
use futures::{task, Poll, Async};
use futures::{task, Async, Poll};
use futures::task::Task;
use bytes::Buf;

View File

@@ -1,5 +1,5 @@
use frame::{Headers, StreamId};
use codec::RecvError;
use frame::{Headers, StreamId};
use std::fmt;
@@ -13,10 +13,7 @@ pub trait Peer {
fn is_server() -> bool;
fn convert_send_message(
id: StreamId,
headers: Self::Send,
end_of_stream: bool) -> Headers;
fn convert_send_message(id: StreamId, headers: Self::Send, end_of_stream: bool) -> Headers;
fn convert_poll_message(headers: Headers) -> Result<Self::Poll, RecvError>;

View File

@@ -14,7 +14,8 @@ pub struct PingPong<B> {
}
impl<B> PingPong<B>
where B: Buf,
where
B: Buf,
{
pub fn new() -> Self {
PingPong {
@@ -46,7 +47,8 @@ impl<B> PingPong<B>
/// Send any pending pongs.
pub fn send_pending_pong<T>(&mut self, dst: &mut Codec<T, B>) -> Poll<(), io::Error>
where T: AsyncWrite,
where
T: AsyncWrite,
{
if let Some(pong) = self.sending_pong.take() {
if !dst.poll_ready()?.is_ready() {

View File

@@ -1,5 +1,5 @@
use frame;
use codec::RecvError;
use frame;
use proto::*;
#[derive(Debug)]
@@ -20,21 +20,23 @@ impl Settings {
pub fn recv_settings(&mut self, frame: frame::Settings) {
if frame.is_ack() {
debug!("received remote settings ack");
// TODO: handle acks
// TODO: handle acks
} else {
assert!(self.pending.is_none());
self.pending = Some(frame);
}
}
pub fn send_pending_ack<T, B, C, P>(&mut self,
dst: &mut Codec<T, B>,
streams: &mut Streams<C, P>)
-> Poll<(), RecvError>
where T: AsyncWrite,
B: Buf,
C: Buf,
P: Peer,
pub fn send_pending_ack<T, B, C, P>(
&mut self,
dst: &mut Codec<T, B>,
streams: &mut Streams<C, P>,
) -> Poll<(), RecvError>
where
T: AsyncWrite,
B: Buf,
C: Buf,
P: Peer,
{
trace!("send_pending_ack; pending={:?}", self.pending);
@@ -48,7 +50,9 @@ impl Settings {
let frame = frame::Settings::ack();
// Buffer the settings frame
dst.buffer(frame.into()).ok().expect("invalid settings frame");
dst.buffer(frame.into())
.ok()
.expect("invalid settings frame");
trace!("ACK sent; applying settings");

View File

@@ -50,9 +50,9 @@ impl<T> Deque<T> {
pub fn push_back(&mut self, buf: &mut Buffer<T>, value: T) {
let key = buf.slab.insert(Slot {
value,
next: None,
});
value,
next: None,
});
match self.indices {
Some(ref mut idxs) => {
@@ -61,18 +61,18 @@ impl<T> Deque<T> {
}
None => {
self.indices = Some(Indices {
head: key,
tail: key,
});
head: key,
tail: key,
});
}
}
}
pub fn push_front(&mut self, buf: &mut Buffer<T>, value: T) {
let key = buf.slab.insert(Slot {
value,
next: None,
});
value,
next: None,
});
match self.indices {
Some(ref mut idxs) => {
@@ -81,9 +81,9 @@ impl<T> Deque<T> {
}
None => {
self.indices = Some(Indices {
head: key,
tail: key,
});
head: key,
tail: key,
});
}
}
}
@@ -109,9 +109,7 @@ impl<T> Deque<T> {
pub fn peek_front<'a>(&self, buf: &'a Buffer<T>) -> Option<&'a T> {
match self.indices {
Some(idxs) => {
Some(&buf.slab[idxs.head].value)
}
Some(idxs) => Some(&buf.slab[idxs.head].value),
None => None,
}
}

View File

@@ -1,12 +1,13 @@
use client;
use super::*;
use client;
use std::usize;
use std::marker::PhantomData;
use std::usize;
#[derive(Debug)]
pub(super) struct Counts<P>
where P: Peer,
where
P: Peer,
{
/// Maximum number of locally initiated streams
max_send_streams: Option<usize>,
@@ -27,7 +28,8 @@ pub(super) struct Counts<P>
}
impl<P> Counts<P>
where P: Peer,
where
P: Peer,
{
/// Create a new `Counts` using the provided configuration values.
pub fn new(config: &Config) -> Self {
@@ -94,7 +96,8 @@ impl<P> Counts<P>
/// If the stream state transitions to closed, this function will perform
/// all necessary cleanup.
pub fn transition<F, B, U>(&mut self, mut stream: store::Ptr<B, P>, f: F) -> U
where F: FnOnce(&mut Self, &mut store::Ptr<B, P>) -> U
where
F: FnOnce(&mut Self, &mut store::Ptr<B, P>) -> U,
{
let is_counted = stream.state.is_counted();

View File

@@ -1,5 +1,5 @@
use frame::Reason;
use proto::{MAX_WINDOW_SIZE, WindowSize};
use proto::{WindowSize, MAX_WINDOW_SIZE};
// We don't want to send WINDOW_UPDATE frames for tiny changes, but instead
// aggregate them when the changes are significant. Many implementations do
@@ -87,8 +87,7 @@ impl FlowControl {
}
let unclaimed = available - self.window_size;
let threshold = self.window_size / UNCLAIMED_DENOMINATOR
* UNCLAIMED_NUMERATOR;
let threshold = self.window_size / UNCLAIMED_DENOMINATOR * UNCLAIMED_NUMERATOR;
if unclaimed < threshold {
None
@@ -111,7 +110,10 @@ impl FlowControl {
return Err(Reason::FlowControlError);
}
trace!("inc_window; sz={}; old={}; new={}", sz, self.window_size, val);
trace!("inc_window; sz={}; old={}; new={}",
sz,
self.window_size,
val);
self.window_size = val;
Ok(())
@@ -130,7 +132,9 @@ impl FlowControl {
/// must ensure that the window has capacity.
pub fn send_data(&mut self, sz: WindowSize) {
trace!("send_data; sz={}; window={}; available={}",
sz, self.window_size, self.available);
sz,
self.window_size,
self.available);
// Ensure that the argument is correct
assert!(sz <= self.window_size as WindowSize);

View File

@@ -9,8 +9,8 @@ mod store;
mod stream;
mod streams;
pub(crate) use self::streams::{Streams, StreamRef};
pub(crate) use self::prioritize::Prioritized;
pub(crate) use self::streams::{StreamRef, Streams};
use self::buffer::Buffer;
use self::counts::Counts;
@@ -19,15 +19,15 @@ use self::prioritize::Prioritize;
use self::recv::Recv;
use self::send::Send;
use self::state::State;
use self::store::{Store, Entry};
use self::store::{Entry, Store};
use self::stream::Stream;
use error::Reason::*;
use frame::StreamId;
use proto::*;
use error::Reason::*;
use http::{Request, Response};
use bytes::Bytes;
use http::{Request, Response};
#[derive(Debug)]
pub struct Config {

View File

@@ -8,12 +8,13 @@ use codec::UserError::*;
use bytes::buf::Take;
use std::{cmp, fmt};
use std::io;
use std::{fmt, cmp};
#[derive(Debug)]
pub(super) struct Prioritize<B, P>
where P: Peer,
where
P: Peer,
{
/// Queue of streams waiting for socket capacity to send a frame
pending_send: store::Queue<B, stream::NextSend, P>,
@@ -41,14 +42,16 @@ pub(crate) struct Prioritized<B> {
// ===== impl Prioritize =====
impl<B, P> Prioritize<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
pub fn new(config: &Config) -> Prioritize<B, P> {
let mut flow = FlowControl::new();
flow.inc_window(config.init_local_window_sz)
.ok().expect("invalid initial window size");
.ok()
.expect("invalid initial window size");
flow.assign_capacity(config.init_local_window_sz);
@@ -63,11 +66,12 @@ impl<B, P> Prioritize<B, P>
}
/// Queue a frame to be sent to the remote
pub fn queue_frame(&mut self,
frame: Frame<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
{
pub fn queue_frame(
&mut self,
frame: Frame<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) {
// Queue the frame in the buffer
stream.pending_send.push_back(&mut self.buffer, frame);
@@ -81,12 +85,12 @@ impl<B, P> Prioritize<B, P>
}
/// Send a data frame
pub fn send_data(&mut self,
frame: frame::Data<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), UserError>
{
pub fn send_data(
&mut self,
frame: frame::Data<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
let sz = frame.payload().remaining();
if sz > MAX_WINDOW_SIZE as usize {
@@ -108,7 +112,9 @@ impl<B, P> Prioritize<B, P>
stream.buffered_send_data += sz;
trace!("send_data; sz={}; buffered={}; requested={}",
sz, stream.buffered_send_data, stream.requested_send_capacity);
sz,
stream.buffered_send_data,
stream.requested_send_capacity);
// Implicitly request more send capacity if not enough has been
// requested yet.
@@ -136,7 +142,9 @@ impl<B, P> Prioritize<B, P>
// The stream has no capacity to send the frame now, save it but
// don't notify the conneciton task. Once additional capacity
// becomes available, the frame will be flushed.
stream.pending_send.push_back(&mut self.buffer, frame.into());
stream
.pending_send
.push_back(&mut self.buffer, frame.into());
}
Ok(())
@@ -183,13 +191,16 @@ impl<B, P> Prioritize<B, P>
}
}
pub fn recv_stream_window_update(&mut self,
inc: WindowSize,
stream: &mut store::Ptr<B, P>)
-> Result<(), Reason>
{
pub fn recv_stream_window_update(
&mut self,
inc: WindowSize,
stream: &mut store::Ptr<B, P>,
) -> Result<(), Reason> {
trace!("recv_stream_window_update; stream={:?}; state={:?}; inc={}; flow={:?}",
stream.id, stream.state, inc, stream.send_flow);
stream.id,
stream.state,
inc,
stream.send_flow);
// Update the stream level flow control.
stream.send_flow.inc_window(inc)?;
@@ -201,11 +212,11 @@ impl<B, P> Prioritize<B, P>
Ok(())
}
pub fn recv_connection_window_update(&mut self,
inc: WindowSize,
store: &mut Store<B, P>)
-> Result<(), Reason>
{
pub fn recv_connection_window_update(
&mut self,
inc: WindowSize,
store: &mut Store<B, P>,
) -> Result<(), Reason> {
// Update the connection's window
self.flow.inc_window(inc)?;
@@ -213,10 +224,9 @@ impl<B, P> Prioritize<B, P>
Ok(())
}
pub fn assign_connection_capacity<R>(&mut self,
inc: WindowSize,
store: &mut R)
where R: Resolve<B, P>
pub fn assign_connection_capacity<R>(&mut self, inc: WindowSize, store: &mut R)
where
R: Resolve<B, P>,
{
self.flow.assign_capacity(inc);
@@ -244,10 +254,9 @@ impl<B, P> Prioritize<B, P>
// The amount of additional capacity that the stream requests.
// Don't assign more than the window has available!
let additional = cmp::min(
total_requested - stream.send_flow.available(),
// Can't assign more than what is available
stream.send_flow.window_size() - stream.send_flow.available());
let additional = cmp::min(total_requested - stream.send_flow.available(),
// Can't assign more than what is available
stream.send_flow.window_size() - stream.send_flow.available());
trace!("try_assign_capacity; requested={}; additional={}; buffered={}; window={}; conn={}",
total_requested,
@@ -265,7 +274,8 @@ impl<B, P> Prioritize<B, P>
// streaming state (more data could be sent) or there is buffered data
// waiting to be sent.
debug_assert!(stream.state.is_send_streaming() || stream.buffered_send_data > 0,
"state={:?}", stream.state);
"state={:?}",
stream.state);
// The amount of currently available capacity on the connection
let conn_available = self.flow.available();
@@ -286,7 +296,8 @@ impl<B, P> Prioritize<B, P>
self.flow.claim_capacity(assign);
}
trace!("try_assign_capacity; available={}; requested={}; buffered={}; has_unavailable={:?}",
trace!("try_assign_capacity; available={}; requested={}; buffered={}; \
has_unavailable={:?}",
stream.send_flow.available(),
stream.requested_send_capacity,
stream.buffered_send_data,
@@ -324,12 +335,14 @@ impl<B, P> Prioritize<B, P>
}
}
pub fn poll_complete<T>(&mut self,
store: &mut Store<B, P>,
counts: &mut Counts<P>,
dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn poll_complete<T>(
&mut self,
store: &mut Store<B, P>,
counts: &mut Counts<P>,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
// Ensure codec is ready
try_ready!(dst.poll_ready());
@@ -378,15 +391,18 @@ impl<B, P> Prioritize<B, P>
/// When a data frame is written to the codec, it may not be written in its
/// entirety (large chunks are split up into potentially many data frames).
/// In this case, the stream needs to be reprioritized.
fn reclaim_frame<T>(&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>) -> bool
{
fn reclaim_frame<T>(
&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>,
) -> bool {
trace!("try reclaim frame");
// First check if there are any data chunks to take back
if let Some(frame) = dst.take_last_data_frame() {
trace!(" -> reclaimed; frame={:?}; sz={}", frame, frame.payload().remaining());
trace!(" -> reclaimed; frame={:?}; sz={}",
frame,
frame.payload().remaining());
let mut eos = false;
let key = frame.payload().stream;
@@ -435,9 +451,12 @@ impl<B, P> Prioritize<B, P>
}
}
fn pop_frame(&mut self, store: &mut Store<B, P>, max_len: usize, counts: &mut Counts<P>)
-> Option<Frame<Prioritized<B>>>
{
fn pop_frame(
&mut self,
store: &mut Store<B, P>,
max_len: usize,
counts: &mut Counts<P>,
) -> Option<Frame<Prioritized<B>>> {
trace!("pop_frame");
loop {
@@ -455,7 +474,8 @@ impl<B, P> Prioritize<B, P>
let stream_capacity = stream.send_flow.available();
let sz = frame.payload().remaining();
trace!(" --> data frame; stream={:?}; sz={}; eos={:?}; window={}; available={}; requested={}",
trace!(" --> data frame; stream={:?}; sz={}; eos={:?}; \
window={}; available={}; requested={}",
frame.stream_id(),
sz,
frame.is_end_stream(),
@@ -479,7 +499,9 @@ impl<B, P> Prioritize<B, P>
// happen if the remote reduced the stream
// window. In this case, we need to buffer the
// frame and wait for a window update...
stream.pending_send.push_front(&mut self.buffer, frame.into());
stream
.pending_send
.push_front(&mut self.buffer, frame.into());
continue;
}
@@ -556,7 +578,8 @@ impl<B, P> Prioritize<B, P>
// ===== impl Prioritized =====
impl<B> Buf for Prioritized<B>
where B: Buf,
where
B: Buf,
{
fn remaining(&self) -> usize {
self.inner.remaining()

View File

@@ -1,8 +1,8 @@
use {client, server, frame, proto};
use frame::Reason;
use codec::{RecvError, UserError};
use proto::*;
use super::*;
use {client, frame, proto, server};
use codec::{RecvError, UserError};
use frame::Reason;
use proto::*;
use http::HeaderMap;
@@ -11,7 +11,8 @@ use std::marker::PhantomData;
#[derive(Debug)]
pub(super) struct Recv<B, P>
where P: Peer,
where
P: Peer,
{
/// Initial window size of remote initiated streams
init_window_sz: WindowSize,
@@ -54,20 +55,18 @@ struct Indices {
}
impl<B, P> Recv<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
pub fn new(config: &Config) -> Self {
let next_stream_id = if P::is_server() {
1
} else {
2
};
let next_stream_id = if P::is_server() { 1 } else { 2 };
let mut flow = FlowControl::new();
flow.inc_window(config.init_remote_window_sz)
.ok().expect("invalid initial remote window size");
.ok()
.expect("invalid initial remote window size");
flow.assign_capacity(config.init_remote_window_sz);
Recv {
@@ -96,12 +95,14 @@ impl<B, P> Recv<B, P>
/// Update state reflecting a new, remotely opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(&mut self, id: StreamId, counts: &mut Counts<P>)
-> Result<Option<StreamId>, RecvError>
{
pub fn open(
&mut self,
id: StreamId,
counts: &mut Counts<P>,
) -> Result<Option<StreamId>, RecvError> {
assert!(self.refused.is_none());
try!(self.ensure_can_open(id));
self.ensure_can_open(id)?;
if id < self.next_stream_id {
return Err(RecvError::Connection(ProtocolError));
@@ -121,12 +122,12 @@ impl<B, P> Recv<B, P>
/// Transition the stream state based on receiving headers
///
/// The caller ensures that the frame represents headers and not trailers.
pub fn recv_headers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
counts: &mut Counts<P>)
-> Result<(), RecvError>
{
pub fn recv_headers(
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
counts: &mut Counts<P>,
) -> Result<(), RecvError> {
trace!("opening stream; init_window={}", self.init_window_sz);
let is_initial = stream.state.recv_open(frame.is_end_stream())?;
@@ -159,7 +160,9 @@ impl<B, P> Recv<B, P>
let message = P::convert_poll_message(frame)?;
// Push the frame onto the stream's recv buffer
stream.pending_recv.push_back(&mut self.buffer, Event::Headers(message));
stream
.pending_recv
.push_back(&mut self.buffer, Event::Headers(message));
stream.notify_recv();
// Only servers can receive a headers frame that initiates the stream.
@@ -172,37 +175,39 @@ impl<B, P> Recv<B, P>
}
/// Transition the stream based on receiving trailers
pub fn recv_trailers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>)
-> Result<(), RecvError>
{
pub fn recv_trailers(
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
) -> Result<(), RecvError> {
// Transition the state
stream.state.recv_close()?;
if stream.ensure_content_length_zero().is_err() {
return Err(RecvError::Stream {
id: stream.id,
reason: ProtocolError,
});
id: stream.id,
reason: ProtocolError,
});
}
let trailers = frame.into_fields();
// Push the frame onto the stream's recv buffer
stream.pending_recv.push_back(&mut self.buffer, Event::Trailers(trailers));
stream
.pending_recv
.push_back(&mut self.buffer, Event::Trailers(trailers));
stream.notify_recv();
Ok(())
}
/// Releases capacity back to the connection
pub fn release_capacity(&mut self,
capacity: WindowSize,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), UserError>
{
pub fn release_capacity(
&mut self,
capacity: WindowSize,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
trace!("release_capacity; size={}", capacity);
if capacity > stream.in_flight_recv_data {
@@ -233,16 +238,18 @@ impl<B, P> Recv<B, P>
return false;
}
stream.pending_recv.peek_front(&self.buffer)
stream
.pending_recv
.peek_front(&self.buffer)
.map(|event| !event.is_data())
.unwrap_or(true)
}
pub fn recv_data(&mut self,
frame: frame::Data,
stream: &mut store::Ptr<B, P>)
-> Result<(), RecvError>
{
pub fn recv_data(
&mut self,
frame: frame::Data,
stream: &mut store::Ptr<B, P>,
) -> Result<(), RecvError> {
let sz = frame.payload().len();
if sz > MAX_WINDOW_SIZE as usize {
@@ -258,7 +265,9 @@ impl<B, P> Recv<B, P>
}
trace!("recv_data; size={}; connection={}; stream={}",
sz, self.flow.window_size(), stream.recv_flow.window_size());
sz,
self.flow.window_size(),
stream.recv_flow.window_size());
// Ensure that there is enough capacity on the connection before acting
// on the stream.
@@ -277,17 +286,17 @@ impl<B, P> Recv<B, P>
if stream.dec_content_length(frame.payload().len()).is_err() {
return Err(RecvError::Stream {
id: stream.id,
reason: ProtocolError,
});
id: stream.id,
reason: ProtocolError,
});
}
if frame.is_end_stream() {
if stream.ensure_content_length_zero().is_err() {
return Err(RecvError::Stream {
id: stream.id,
reason: ProtocolError,
});
id: stream.id,
reason: ProtocolError,
});
}
if stream.state.recv_close().is_err() {
@@ -304,18 +313,20 @@ impl<B, P> Recv<B, P>
Ok(())
}
pub fn recv_push_promise(&mut self,
frame: frame::PushPromise,
send: &Send<B, P>,
stream: store::Key,
store: &mut Store<B, P>)
-> Result<(), RecvError>
{
pub fn recv_push_promise(
&mut self,
frame: frame::PushPromise,
send: &Send<B, P>,
stream: store::Key,
store: &mut Store<B, P>,
) -> Result<(), RecvError> {
// First, make sure that the values are legit
self.ensure_can_reserve(frame.promised_id())?;
// Make sure that the stream state is valid
store[stream].state.ensure_recv_open()
store[stream]
.state
.ensure_recv_open()
.map_err(|e| e.into_connection_recv_error())?;
// TODO: Streams in the reserved states do not count towards the concurrency
@@ -332,10 +343,9 @@ impl<B, P> Recv<B, P>
// TODO: All earlier stream IDs should be implicitly closed.
// Now, create a new entry for the stream
let mut new_stream = Stream::new(
frame.promised_id(),
send.init_window_sz(),
self.init_window_sz);
let mut new_stream = Stream::new(frame.promised_id(),
send.init_window_sz(),
self.init_window_sz);
new_stream.state.reserve_remote()?;
@@ -343,8 +353,7 @@ impl<B, P> Recv<B, P>
{
// Store the stream
let mut new_stream = store
.insert(frame.promised_id(), new_stream);
let mut new_stream = store.insert(frame.promised_id(), new_stream);
ppp.push(&mut new_stream);
}
@@ -366,9 +375,11 @@ impl<B, P> Recv<B, P>
Ok(())
}
pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream<B, P>)
-> Result<(), RecvError>
{
pub fn recv_reset(
&mut self,
frame: frame::Reset,
stream: &mut Stream<B, P>,
) -> Result<(), RecvError> {
let err = proto::Error::Proto(frame.reason());
// Notify the stream
@@ -387,9 +398,7 @@ impl<B, P> Recv<B, P>
}
/// Returns true if the remote peer can initiate a stream with the given ID.
fn ensure_can_open(&self, id: StreamId)
-> Result<(), RecvError>
{
fn ensure_can_open(&self, id: StreamId) -> Result<(), RecvError> {
if !P::is_server() {
// Remote is a server and cannot open streams. PushPromise is
// registered by reserving, so does not go through this path.
@@ -405,9 +414,7 @@ impl<B, P> Recv<B, P>
}
/// Returns true if the remote peer can reserve a stream with the given ID.
fn ensure_can_reserve(&self, promised_id: StreamId)
-> Result<(), RecvError>
{
fn ensure_can_reserve(&self, promised_id: StreamId) -> Result<(), RecvError> {
// TODO: Are there other rules?
if P::is_server() {
// The remote is a client and cannot reserve
@@ -422,9 +429,12 @@ impl<B, P> Recv<B, P>
}
/// Send any pending refusals.
pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn send_pending_refusal<T>(
&mut self,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
if let Some(stream_id) = self.refused {
try_ready!(dst.poll_ready());
@@ -433,7 +443,9 @@ impl<B, P> Recv<B, P>
let frame = frame::Reset::new(stream_id, RefusedStream);
// Buffer the frame
dst.buffer(frame.into()).ok().expect("invalid RST_STREAM frame");
dst.buffer(frame.into())
.ok()
.expect("invalid RST_STREAM frame");
}
self.refused = None;
@@ -441,11 +453,13 @@ impl<B, P> Recv<B, P>
Ok(Async::Ready(()))
}
pub fn poll_complete<T>(&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn poll_complete<T>(
&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
// Send any pending connection level window updates
try_ready!(self.send_connection_window_update(dst));
@@ -457,9 +471,12 @@ impl<B, P> Recv<B, P>
}
/// Send connection level window update
fn send_connection_window_update<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
fn send_connection_window_update<T>(
&mut self,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
if let Some(incr) = self.flow.unclaimed_capacity() {
let frame = frame::WindowUpdate::new(StreamId::zero(), incr);
@@ -468,10 +485,15 @@ impl<B, P> Recv<B, P>
try_ready!(dst.poll_ready());
// Buffer the WINDOW_UPDATE frame
dst.buffer(frame.into()).ok().expect("invalid WINDOW_UPDATE frame");
dst.buffer(frame.into())
.ok()
.expect("invalid WINDOW_UPDATE frame");
// Update flow control
self.flow.inc_window(incr).ok().expect("unexpected flow control state");
self.flow
.inc_window(incr)
.ok()
.expect("unexpected flow control state");
}
Ok(().into())
@@ -479,11 +501,13 @@ impl<B, P> Recv<B, P>
/// Send stream level window update
pub fn send_stream_window_updates<T>(&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn send_stream_window_updates<T>(
&mut self,
store: &mut Store<B, P>,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
loop {
// Ensure the codec has capacity
@@ -507,27 +531,28 @@ impl<B, P> Recv<B, P>
let frame = frame::WindowUpdate::new(stream.id, incr);
// Buffer it
dst.buffer(frame.into()).ok().expect("invalid WINDOW_UPDATE frame");
dst.buffer(frame.into())
.ok()
.expect("invalid WINDOW_UPDATE frame");
// Update flow control
stream.recv_flow.inc_window(incr).ok().expect("unexpected flow control state");
stream
.recv_flow
.inc_window(incr)
.ok()
.expect("unexpected flow control state");
}
}
}
pub fn next_incoming(&mut self, store: &mut Store<B, P>) -> Option<store::Key> {
self.pending_accept.pop(store)
.map(|ptr| ptr.key())
self.pending_accept.pop(store).map(|ptr| ptr.key())
}
pub fn poll_data(&mut self, stream: &mut Stream<B, P>)
-> Poll<Option<Bytes>, proto::Error>
{
pub fn poll_data(&mut self, stream: &mut Stream<B, P>) -> Poll<Option<Bytes>, proto::Error> {
// TODO: Return error when the stream is reset
match stream.pending_recv.pop_front(&mut self.buffer) {
Some(Event::Data(payload)) => {
Ok(Some(payload).into())
}
Some(Event::Data(payload)) => Ok(Some(payload).into()),
Some(event) => {
// Frame is trailer
stream.pending_recv.push_front(&mut self.buffer, event);
@@ -548,13 +573,12 @@ impl<B, P> Recv<B, P>
}
}
pub fn poll_trailers(&mut self, stream: &mut Stream<B, P>)
-> Poll<Option<HeaderMap>, proto::Error>
{
pub fn poll_trailers(
&mut self,
stream: &mut Stream<B, P>,
) -> Poll<Option<HeaderMap>, proto::Error> {
match stream.pending_recv.pop_front(&mut self.buffer) {
Some(Event::Trailers(trailers)) => {
Ok(Some(trailers).into())
}
Some(Event::Trailers(trailers)) => Ok(Some(trailers).into()),
Some(_) => {
// TODO: This is a user error. `poll_trailers` was called before
// the entire set of data frames have been consumed. What should
@@ -576,12 +600,11 @@ impl<B, P> Recv<B, P>
}
impl<B> Recv<B, server::Peer>
where B: Buf,
where
B: Buf,
{
/// TODO: Should this fn return `Result`?
pub fn take_request(&mut self, stream: &mut store::Ptr<B, server::Peer>)
-> Request<()>
{
pub fn take_request(&mut self, stream: &mut store::Ptr<B, server::Peer>) -> Request<()> {
match stream.pending_recv.pop_front(&mut self.buffer) {
Some(Event::Headers(request)) => request,
_ => panic!(),
@@ -590,16 +613,17 @@ impl<B> Recv<B, server::Peer>
}
impl<B> Recv<B, client::Peer>
where B: Buf,
where
B: Buf,
{
pub fn poll_response(&mut self, stream: &mut store::Ptr<B, client::Peer>)
-> Poll<Response<()>, proto::Error> {
pub fn poll_response(
&mut self,
stream: &mut store::Ptr<B, client::Peer>,
) -> Poll<Response<()>, proto::Error> {
// If the buffer is not empty, then the first frame must be a HEADERS
// frame or the user violated the contract.
match stream.pending_recv.pop_front(&mut self.buffer) {
Some(Event::Headers(response)) => {
Ok(response.into())
}
Some(Event::Headers(response)) => Ok(response.into()),
Some(_) => unimplemented!(),
None => {
stream.state.ensure_recv_open()?;

View File

@@ -1,8 +1,8 @@
use frame::{self, Reason};
use super::*;
use codec::{RecvError, UserError};
use codec::UserError::*;
use frame::{self, Reason};
use proto::*;
use super::*;
use bytes::Buf;
@@ -11,7 +11,8 @@ use std::io;
/// Manages state transitions related to outbound frames.
#[derive(Debug)]
pub(super) struct Send<B, P>
where P: Peer,
where
P: Peer,
{
/// Stream identifier to use for next initialized stream.
next_stream_id: StreamId,
@@ -24,8 +25,9 @@ pub(super) struct Send<B, P>
}
impl<B, P> Send<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
/// Create a new `Send`
pub fn new(config: &Config) -> Self {
@@ -46,10 +48,8 @@ where B: Buf,
/// Update state reflecting a new, locally opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(&mut self, counts: &mut Counts<P>)
-> Result<StreamId, UserError>
{
try!(self.ensure_can_open());
pub fn open(&mut self, counts: &mut Counts<P>) -> Result<StreamId, UserError> {
self.ensure_can_open()?;
if !counts.can_inc_num_send_streams() {
return Err(Rejected.into());
@@ -64,13 +64,15 @@ where B: Buf,
Ok(ret)
}
pub fn send_headers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), UserError>
{
trace!("send_headers; frame={:?}; init_window={:?}", frame, self.init_window_sz);
pub fn send_headers(
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
trace!("send_headers; frame={:?}; init_window={:?}",
frame,
self.init_window_sz);
let end_stream = frame.is_end_stream();
@@ -83,11 +85,12 @@ where B: Buf,
Ok(())
}
pub fn send_reset(&mut self,
reason: Reason,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
{
pub fn send_reset(
&mut self,
reason: Reason,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) {
if stream.state.is_reset() {
// Don't double reset
return;
@@ -116,24 +119,25 @@ where B: Buf,
self.prioritize.queue_frame(frame.into(), stream, task);
// Re-assign all capacity to the connection
self.prioritize.assign_connection_capacity(available, stream);
self.prioritize
.assign_connection_capacity(available, stream);
}
pub fn send_data(&mut self,
frame: frame::Data<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), UserError>
{
pub fn send_data(
&mut self,
frame: frame::Data<B>,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
self.prioritize.send_data(frame, stream, task)
}
pub fn send_trailers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), UserError>
{
pub fn send_trailers(
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
// TODO: Should this logic be moved into state.rs?
if !stream.state.is_send_streaming() {
return Err(UnexpectedFrameType.into());
@@ -150,12 +154,14 @@ where B: Buf,
Ok(())
}
pub fn poll_complete<T>(&mut self,
store: &mut Store<B, P>,
counts: &mut Counts<P>,
dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn poll_complete<T>(
&mut self,
store: &mut Store<B, P>,
counts: &mut Counts<P>,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
self.prioritize.poll_complete(store, counts, dst)
}
@@ -165,9 +171,10 @@ where B: Buf,
self.prioritize.reserve_capacity(capacity, stream)
}
pub fn poll_capacity(&mut self, stream: &mut store::Ptr<B, P>)
-> Poll<Option<WindowSize>, UserError>
{
pub fn poll_capacity(
&mut self,
stream: &mut store::Ptr<B, P>,
) -> Poll<Option<WindowSize>, UserError> {
if !stream.state.is_send_streaming() {
return Ok(Async::Ready(None));
}
@@ -193,20 +200,21 @@ where B: Buf,
}
}
pub fn recv_connection_window_update(&mut self,
frame: frame::WindowUpdate,
store: &mut Store<B, P>)
-> Result<(), Reason>
{
self.prioritize.recv_connection_window_update(frame.size_increment(), store)
pub fn recv_connection_window_update(
&mut self,
frame: frame::WindowUpdate,
store: &mut Store<B, P>,
) -> Result<(), Reason> {
self.prioritize
.recv_connection_window_update(frame.size_increment(), store)
}
pub fn recv_stream_window_update(&mut self,
sz: WindowSize,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>)
-> Result<(), Reason>
{
pub fn recv_stream_window_update(
&mut self,
sz: WindowSize,
stream: &mut store::Ptr<B, P>,
task: &mut Option<Task>,
) -> Result<(), Reason> {
if let Err(e) = self.prioritize.recv_stream_window_update(sz, stream) {
debug!("recv_stream_window_update !!; err={:?}", e);
self.send_reset(FlowControlError.into(), stream, task);
@@ -217,12 +225,12 @@ where B: Buf,
Ok(())
}
pub fn apply_remote_settings(&mut self,
settings: &frame::Settings,
store: &mut Store<B, P>,
task: &mut Option<Task>)
-> Result<(), RecvError>
{
pub fn apply_remote_settings(
&mut self,
settings: &frame::Settings,
store: &mut Store<B, P>,
task: &mut Option<Task>,
) -> Result<(), RecvError> {
// Applies an update to the remote endpoint's initial window size.
//
// Per RFC 7540 §6.9.2:
@@ -254,7 +262,9 @@ where B: Buf,
stream.send_flow.dec_window(dec);
trace!("decremented stream window; id={:?}; decr={}; flow={:?}",
stream.id, dec, stream.send_flow);
stream.id,
dec,
stream.send_flow);
// TODO: Probably try to assign capacity?

View File

@@ -1,7 +1,7 @@
use frame::Reason;
use frame::Reason::*;
use codec::{RecvError, UserError};
use codec::UserError::*;
use frame::Reason;
use frame::Reason::*;
use proto;
use self::Inner::*;
@@ -58,10 +58,7 @@ enum Inner {
// TODO: these states shouldn't count against concurrency limits:
//ReservedLocal,
ReservedRemote,
Open {
local: Peer,
remote: Peer,
},
Open { local: Peer, remote: Peer },
HalfClosedLocal(Peer), // TODO: explicitly name this value
HalfClosedRemote(Peer),
// When reset, a reason is provided
@@ -96,7 +93,10 @@ impl State {
}
}
}
Open { local: AwaitingHeaders, remote } => {
Open {
local: AwaitingHeaders,
remote,
} => {
if eos {
HalfClosedLocal(remote)
} else {
@@ -155,7 +155,10 @@ impl State {
}
}
}
Open { local, remote: AwaitingHeaders } => {
Open {
local,
remote: AwaitingHeaders,
} => {
if eos {
HalfClosedRemote(local)
} else {
@@ -195,7 +198,9 @@ impl State {
/// Indicates that the remote side will not send more data to the local.
pub fn recv_close(&mut self) -> Result<(), RecvError> {
match self.inner {
Open { local, .. } => {
Open {
local, ..
} => {
// The remote side will continue to receive data.
trace!("recv_close: Open => HalfClosedRemote({:?})", local);
self.inner = HalfClosedRemote(local);
@@ -218,9 +223,9 @@ impl State {
_ => {
trace!("recv_err; err={:?}", err);
self.inner = Closed(match *err {
Proto(reason) => Some(Cause::Proto(reason)),
Io(..) => Some(Cause::Io),
});
Proto(reason) => Some(Cause::Proto(reason)),
Io(..) => Some(Cause::Io),
});
}
}
}
@@ -228,7 +233,9 @@ impl State {
/// Indicates that the local side will not send more data to the local.
pub fn send_close(&mut self) {
match self.inner {
Open { remote, .. } => {
Open {
remote, ..
} => {
// The remote side will continue to receive data.
trace!("send_close: Open => HalfClosedLocal({:?})", remote);
self.inner = HalfClosedLocal(remote);
@@ -259,7 +266,9 @@ impl State {
/// concurrency limit.
pub fn is_counted(&self) -> bool {
match self.inner {
Open { .. } => true,
Open {
..
} => true,
HalfClosedLocal(..) => true,
HalfClosedRemote(..) => true,
_ => false,
@@ -268,7 +277,10 @@ impl State {
pub fn is_send_streaming(&self) -> bool {
match self.inner {
Open { local: Peer::Streaming, .. } => true,
Open {
local: Peer::Streaming,
..
} => true,
HalfClosedRemote(Peer::Streaming) => true,
_ => false,
}
@@ -278,7 +290,10 @@ impl State {
pub fn is_recv_headers(&self) -> bool {
match self.inner {
Idle => true,
Open { remote: AwaitingHeaders, .. } => true,
Open {
remote: AwaitingHeaders,
..
} => true,
HalfClosedLocal(AwaitingHeaders) => true,
_ => false,
}
@@ -286,7 +301,10 @@ impl State {
pub fn is_recv_streaming(&self) -> bool {
match self.inner {
Open { remote: Peer::Streaming, .. } => true,
Open {
remote: Peer::Streaming,
..
} => true,
HalfClosedLocal(Peer::Streaming) => true,
_ => false,
}
@@ -311,12 +329,8 @@ impl State {
// TODO: Is this correct?
match self.inner {
Closed(Some(Cause::Proto(reason))) => {
Err(proto::Error::Proto(reason))
}
Closed(Some(Cause::Io)) => {
Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into()))
}
Closed(Some(Cause::Proto(reason))) => Err(proto::Error::Proto(reason)),
Closed(Some(Cause::Io)) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())),
_ => Ok(()),
}
}
@@ -324,7 +338,9 @@ impl State {
impl Default for State {
fn default() -> State {
State { inner: Inner::Idle }
State {
inner: Inner::Idle,
}
}
}

View File

@@ -4,13 +4,14 @@ use slab;
use ordermap::{self, OrderMap};
use std::ops;
use std::marker::PhantomData;
use std::ops;
/// Storage for streams
#[derive(Debug)]
pub(super) struct Store<B, P>
where P: Peer,
where
P: Peer,
{
slab: slab::Slab<Stream<B, P>>,
ids: OrderMap<StreamId, usize>,
@@ -18,7 +19,8 @@ pub(super) struct Store<B, P>
/// "Pointer" to an entry in the store
pub(super) struct Ptr<'a, B: 'a, P>
where P: Peer + 'a,
where
P: Peer + 'a,
{
key: Key,
store: &'a mut Store<B, P>,
@@ -30,7 +32,8 @@ pub(super) struct Key(usize);
#[derive(Debug)]
pub(super) struct Queue<B, N, P>
where P: Peer,
where
P: Peer,
{
indices: Option<store::Indices>,
_p: PhantomData<(B, N, P)>,
@@ -65,14 +68,16 @@ pub(super) struct OccupiedEntry<'a> {
}
pub(super) struct VacantEntry<'a, B: 'a, P>
where P: Peer + 'a,
where
P: Peer + 'a,
{
ids: ordermap::VacantEntry<'a, StreamId, usize>,
slab: &'a mut slab::Slab<Stream<B, P>>,
}
pub(super) trait Resolve<B, P>
where P: Peer,
where
P: Peer,
{
fn resolve(&mut self, key: Key) -> Ptr<B, P>;
}
@@ -80,7 +85,8 @@ pub(super) trait Resolve<B, P>
// ===== impl Store =====
impl<B, P> Store<B, P>
where P: Peer,
where
P: Peer,
{
pub fn new() -> Self {
Store {
@@ -100,9 +106,9 @@ impl<B, P> Store<B, P>
};
Some(Ptr {
key: Key(key),
store: self,
})
key: Key(key),
store: self,
})
}
pub fn insert(&mut self, id: StreamId, val: Stream<B, P>) -> Ptr<B, P> {
@@ -121,20 +127,21 @@ impl<B, P> Store<B, P>
match self.ids.entry(id) {
Occupied(e) => {
Entry::Occupied(OccupiedEntry {
ids: e,
})
ids: e,
})
}
Vacant(e) => {
Entry::Vacant(VacantEntry {
ids: e,
slab: &mut self.slab,
})
ids: e,
slab: &mut self.slab,
})
}
}
}
pub fn for_each<F, E>(&mut self, mut f: F) -> Result<(), E>
where F: FnMut(Ptr<B, P>) -> Result<(), E>,
where
F: FnMut(Ptr<B, P>) -> Result<(), E>,
{
let mut len = self.ids.len();
let mut i = 0;
@@ -144,9 +151,9 @@ impl<B, P> Store<B, P>
let key = *self.ids.get_index(i).unwrap().1;
f(Ptr {
key: Key(key),
store: self,
})?;
key: Key(key),
store: self,
})?;
// TODO: This logic probably could be better...
let new_len = self.ids.len();
@@ -164,7 +171,8 @@ impl<B, P> Store<B, P>
}
impl<B, P> Resolve<B, P> for Store<B, P>
where P: Peer,
where
P: Peer,
{
fn resolve(&mut self, key: Key) -> Ptr<B, P> {
Ptr {
@@ -175,7 +183,8 @@ impl<B, P> Resolve<B, P> for Store<B, P>
}
impl<B, P> ops::Index<Key> for Store<B, P>
where P: Peer,
where
P: Peer,
{
type Output = Stream<B, P>;
@@ -185,7 +194,8 @@ impl<B, P> ops::Index<Key> for Store<B, P>
}
impl<B, P> ops::IndexMut<Key> for Store<B, P>
where P: Peer,
where
P: Peer,
{
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
self.slab.index_mut(key.0)
@@ -194,7 +204,8 @@ impl<B, P> ops::IndexMut<Key> for Store<B, P>
#[cfg(feature = "unstable")]
impl<B, P> Store<B, P>
where P: Peer,
where
P: Peer,
{
pub fn num_active_streams(&self) -> usize {
self.ids.len()
@@ -208,8 +219,9 @@ impl<B, P> Store<B, P>
// ===== impl Queue =====
impl<B, N, P> Queue<B, N, P>
where N: Next,
P: Peer,
where
N: Next,
P: Peer,
{
pub fn new() -> Self {
Queue {
@@ -260,9 +272,9 @@ impl<B, N, P> Queue<B, N, P>
None => {
trace!(" -> first entry");
self.indices = Some(store::Indices {
head: stream.key(),
tail: stream.key(),
});
head: stream.key(),
tail: stream.key(),
});
}
}
@@ -270,7 +282,8 @@ impl<B, N, P> Queue<B, N, P>
}
pub fn pop<'a, R>(&mut self, store: &'a mut R) -> Option<store::Ptr<'a, B, P>>
where R: Resolve<B, P>
where
R: Resolve<B, P>,
{
if let Some(mut idxs) = self.indices {
let mut stream = store.resolve(idxs.head);
@@ -296,7 +309,8 @@ impl<B, N, P> Queue<B, N, P>
// ===== impl Ptr =====
impl<'a, B: 'a, P> Ptr<'a, B, P>
where P: Peer,
where
P: Peer,
{
/// Returns the Key associated with the stream
pub fn key(&self) -> Key {
@@ -323,7 +337,8 @@ impl<'a, B: 'a, P> Ptr<'a, B, P>
}
impl<'a, B: 'a, P> Resolve<B, P> for Ptr<'a, B, P>
where P: Peer,
where
P: Peer,
{
fn resolve(&mut self, key: Key) -> Ptr<B, P> {
Ptr {
@@ -334,7 +349,8 @@ impl<'a, B: 'a, P> Resolve<B, P> for Ptr<'a, B, P>
}
impl<'a, B: 'a, P> ops::Deref for Ptr<'a, B, P>
where P: Peer,
where
P: Peer,
{
type Target = Stream<B, P>;
@@ -344,7 +360,8 @@ impl<'a, B: 'a, P> ops::Deref for Ptr<'a, B, P>
}
impl<'a, B: 'a, P> ops::DerefMut for Ptr<'a, B, P>
where P: Peer,
where
P: Peer,
{
fn deref_mut(&mut self) -> &mut Stream<B, P> {
&mut self.store.slab[self.key.0]
@@ -362,7 +379,8 @@ impl<'a> OccupiedEntry<'a> {
// ===== impl VacantEntry =====
impl<'a, B, P> VacantEntry<'a, B, P>
where P: Peer,
where
P: Peer,
{
pub fn insert(self, value: Stream<B, P>) -> Key {
// Insert the value in the slab

View File

@@ -15,7 +15,8 @@ use std::usize;
/// Thus, `ref_count` can be zero and the stream still has to be kept around.
#[derive(Debug)]
pub(super) struct Stream<B, P>
where P: Peer,
where
P: Peer,
{
/// The h2 stream identifier
pub id: StreamId,
@@ -27,7 +28,6 @@ pub(super) struct Stream<B, P>
pub ref_count: usize,
// ===== Fields related to sending =====
/// Next node in the accept linked list
pub next_pending_send: Option<store::Key>,
@@ -61,7 +61,6 @@ pub(super) struct Stream<B, P>
pub send_capacity_inc: bool,
// ===== Fields related to receiving =====
/// Next node in the accept linked list
pub next_pending_accept: Option<store::Key>,
@@ -90,7 +89,6 @@ pub(super) struct Stream<B, P>
/// Validate content-length headers
pub content_length: ContentLength,
}
/// State related to validating a stream's content-length
@@ -114,21 +112,27 @@ pub(super) struct NextSendCapacity;
pub(super) struct NextWindowUpdate;
impl<B, P> Stream<B, P>
where P: Peer,
where
P: Peer,
{
pub fn new(id: StreamId,
init_send_window: WindowSize,
init_recv_window: WindowSize) -> Stream<B, P>
{
pub fn new(
id: StreamId,
init_send_window: WindowSize,
init_recv_window: WindowSize,
) -> Stream<B, P> {
let mut send_flow = FlowControl::new();
let mut recv_flow = FlowControl::new();
recv_flow.inc_window(init_recv_window)
.ok().expect("invalid initial receive window");
recv_flow
.inc_window(init_recv_window)
.ok()
.expect("invalid initial receive window");
recv_flow.assign_capacity(init_recv_window);
send_flow.inc_window(init_send_window)
.ok().expect("invalid initial send window size");
send_flow
.inc_window(init_send_window)
.ok()
.expect("invalid initial send window size");
Stream {
id,
@@ -136,7 +140,6 @@ impl<B, P> Stream<B, P>
ref_count: 0,
// ===== Fields related to sending =====
next_pending_send: None,
is_pending_send: false,
send_flow: send_flow,
@@ -149,7 +152,6 @@ impl<B, P> Stream<B, P>
send_capacity_inc: false,
// ===== Fields related to receiving =====
next_pending_accept: None,
is_pending_accept: false,
recv_flow: recv_flow,
@@ -197,10 +199,8 @@ impl<B, P> Stream<B, P>
// There are no more outstanding references to the stream
self.ref_count == 0 &&
// The stream is not in any queue
!self.is_pending_send &&
!self.is_pending_send_capacity &&
!self.is_pending_accept &&
!self.is_pending_window_update
!self.is_pending_send && !self.is_pending_send_capacity &&
!self.is_pending_accept && !self.is_pending_window_update
}
pub fn assign_capacity(&mut self, capacity: WindowSize) {

View File

@@ -1,9 +1,9 @@
use {client, server, proto};
use frame::Reason;
use codec::{SendError, RecvError, UserError};
use proto::*;
use super::*;
use super::store::Resolve;
use {client, proto, server};
use codec::{RecvError, SendError, UserError};
use frame::Reason;
use proto::*;
use http::HeaderMap;
@@ -12,7 +12,8 @@ use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub(crate) struct Streams<B, P>
where P: Peer,
where
P: Peer,
{
inner: Arc<Mutex<Inner<B, P>>>,
}
@@ -20,7 +21,8 @@ pub(crate) struct Streams<B, P>
/// Reference to the stream state
#[derive(Debug)]
pub(crate) struct StreamRef<B, P>
where P: Peer,
where
P: Peer,
{
inner: Arc<Mutex<Inner<B, P>>>,
key: store::Key,
@@ -32,7 +34,8 @@ pub(crate) struct StreamRef<B, P>
/// TODO: better name
#[derive(Debug)]
struct Inner<B, P>
where P: Peer,
where
P: Peer,
{
/// Tracks send & recv stream concurrency.
counts: Counts<P>,
@@ -42,7 +45,8 @@ struct Inner<B, P>
#[derive(Debug)]
struct Actions<B, P>
where P: Peer,
where
P: Peer,
{
/// Manages state transitions initiated by receiving frames
recv: Recv<B, P>,
@@ -55,27 +59,26 @@ struct Actions<B, P>
}
impl<B, P> Streams<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
pub fn new(config: Config) -> Self {
Streams {
inner: Arc::new(Mutex::new(Inner {
counts: Counts::new(&config),
actions: Actions {
recv: Recv::new(&config),
send: Send::new(&config),
task: None,
},
store: Store::new(),
})),
counts: Counts::new(&config),
actions: Actions {
recv: Recv::new(&config),
send: Send::new(&config),
task: None,
},
store: Store::new(),
})),
}
}
/// Process inbound headers
pub fn recv_headers(&mut self, frame: frame::Headers)
-> Result<(), RecvError>
{
pub fn recv_headers(&mut self, frame: frame::Headers) -> Result<(), RecvError> {
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -83,12 +86,11 @@ impl<B, P> Streams<B, P>
let key = match me.store.find_entry(id) {
Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => {
match try!(me.actions.recv.open(id, &mut me.counts)) {
match me.actions.recv.open(id, &mut me.counts)? {
Some(stream_id) => {
let stream = Stream::new(
stream_id,
me.actions.send.init_window_sz(),
me.actions.recv.init_window_sz());
let stream = Stream::new(stream_id,
me.actions.send.init_window_sz(),
me.actions.recv.init_window_sz());
e.insert(stream)
}
@@ -101,7 +103,9 @@ impl<B, P> Streams<B, P>
let actions = &mut me.actions;
me.counts.transition(stream, |counts, stream| {
trace!("recv_headers; stream={:?}; state={:?}", stream.id, stream.state);
trace!("recv_headers; stream={:?}; state={:?}",
stream.id,
stream.state);
let res = if stream.state.is_recv_headers() {
actions.recv.recv_headers(frame, stream, counts)
@@ -118,9 +122,7 @@ impl<B, P> Streams<B, P>
})
}
pub fn recv_data(&mut self, frame: frame::Data)
-> Result<(), RecvError>
{
pub fn recv_data(&mut self, frame: frame::Data) -> Result<(), RecvError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -139,9 +141,7 @@ impl<B, P> Streams<B, P>
})
}
pub fn recv_reset(&mut self, frame: frame::Reset)
-> Result<(), RecvError>
{
pub fn recv_reset(&mut self, frame: frame::Reset) -> Result<(), RecvError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -155,7 +155,8 @@ impl<B, P> Streams<B, P>
Some(stream) => stream,
None => {
// TODO: Are there other error cases?
me.actions.ensure_not_idle(id)
me.actions
.ensure_not_idle(id)
.map_err(RecvError::Connection)?;
return Ok(());
@@ -181,26 +182,27 @@ impl<B, P> Streams<B, P>
let last_processed_id = actions.recv.last_processed_id();
me.store.for_each(|stream| {
counts.transition(stream, |_, stream| {
actions.recv.recv_err(err, &mut *stream);
Ok::<_, ()>(())
me.store
.for_each(|stream| {
counts.transition(stream, |_, stream| {
actions.recv.recv_err(err, &mut *stream);
Ok::<_, ()>(())
})
})
}).unwrap();
.unwrap();
last_processed_id
}
pub fn recv_window_update(&mut self, frame: frame::WindowUpdate)
-> Result<(), RecvError>
{
pub fn recv_window_update(&mut self, frame: frame::WindowUpdate) -> Result<(), RecvError> {
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
if id.is_zero() {
me.actions.send.recv_connection_window_update(
frame, &mut me.store)
me.actions
.send
.recv_connection_window_update(frame, &mut me.store)
.map_err(RecvError::Connection)?;
} else {
// The remote may send window updates for streams that the local now
@@ -209,12 +211,15 @@ impl<B, P> Streams<B, P>
// This result is ignored as there is nothing to do when there
// is an error. The stream is reset by the function on error and
// the error is informational.
let _ = me.actions.send.recv_stream_window_update(
frame.size_increment(),
&mut stream,
&mut me.actions.task);
let _ = me.actions
.send
.recv_stream_window_update(frame.size_increment(),
&mut stream,
&mut me.actions.task);
} else {
me.actions.recv.ensure_not_idle(id)
me.actions
.recv
.ensure_not_idle(id)
.map_err(RecvError::Connection)?;
}
}
@@ -222,9 +227,7 @@ impl<B, P> Streams<B, P>
Ok(())
}
pub fn recv_push_promise(&mut self, frame: frame::PushPromise)
-> Result<(), RecvError>
{
pub fn recv_push_promise(&mut self, frame: frame::PushPromise) -> Result<(), RecvError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -235,8 +238,9 @@ impl<B, P> Streams<B, P>
None => return Err(RecvError::Connection(ProtocolError)),
};
me.actions.recv.recv_push_promise(
frame, &me.actions.send, stream, &mut me.store)
me.actions
.recv
.recv_push_promise(frame, &me.actions.send, stream, &mut me.store)
}
pub fn next_incoming(&mut self) -> Option<StreamRef<B, P>> {
@@ -264,18 +268,21 @@ impl<B, P> Streams<B, P>
})
}
pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn send_pending_refusal<T>(
&mut self,
dst: &mut Codec<T, Prioritized<B>>,
) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.actions.recv.send_pending_refusal(dst)
}
pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>)
-> Poll<(), io::Error>
where T: AsyncWrite,
pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) -> Poll<(), io::Error>
where
T: AsyncWrite,
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -287,7 +294,9 @@ impl<B, P> Streams<B, P>
try_ready!(me.actions.recv.poll_complete(&mut me.store, dst));
// Send any other pending frames
try_ready!(me.actions.send.poll_complete(&mut me.store, &mut me.counts, dst));
try_ready!(me.actions
.send
.poll_complete(&mut me.store, &mut me.counts, dst));
// Nothing else to do, track the task
me.actions.task = Some(task::current());
@@ -295,21 +304,22 @@ impl<B, P> Streams<B, P>
Ok(().into())
}
pub fn apply_remote_settings(&mut self, frame: &frame::Settings)
-> Result<(), RecvError>
{
pub fn apply_remote_settings(&mut self, frame: &frame::Settings) -> Result<(), RecvError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.counts.apply_remote_settings(frame);
me.actions.send.apply_remote_settings(
frame, &mut me.store, &mut me.actions.task)
me.actions
.send
.apply_remote_settings(frame, &mut me.store, &mut me.actions.task)
}
pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<StreamRef<B, P>, SendError>
{
pub fn send_request(
&mut self,
request: Request<()>,
end_of_stream: bool,
) -> Result<StreamRef<B, P>, SendError> {
use http::Method;
use super::stream::ContentLength;
@@ -325,23 +335,22 @@ impl<B, P> Streams<B, P>
// Initialize a new stream. This fails if the connection is at capacity.
let stream_id = me.actions.send.open(&mut me.counts)?;
let mut stream = Stream::new(
stream_id,
me.actions.send.init_window_sz(),
me.actions.recv.init_window_sz());
let mut stream = Stream::new(stream_id,
me.actions.send.init_window_sz(),
me.actions.recv.init_window_sz());
if *request.method() == Method::HEAD {
stream.content_length = ContentLength::Head;
}
// Convert the message
let headers = client::Peer::convert_send_message(
stream_id, request, end_of_stream);
let headers = client::Peer::convert_send_message(stream_id, request, end_of_stream);
let mut stream = me.store.insert(stream.id, stream);
me.actions.send.send_headers(
headers, &mut stream, &mut me.actions.task)?;
me.actions
.send
.send_headers(headers, &mut stream, &mut me.actions.task)?;
// Given that the stream has been initialized, it should not be in the
// closed state.
@@ -354,9 +363,9 @@ impl<B, P> Streams<B, P>
};
Ok(StreamRef {
inner: self.inner.clone(),
key: key,
})
inner: self.inner.clone(),
key: key,
})
}
pub fn send_reset(&mut self, id: StreamId, reason: Reason) {
@@ -368,8 +377,7 @@ impl<B, P> Streams<B, P>
Entry::Vacant(e) => {
match me.actions.recv.open(id, &mut me.counts) {
Ok(Some(stream_id)) => {
let stream = Stream::new(
stream_id, 0, 0);
let stream = Stream::new(stream_id, 0, 0);
e.insert(stream)
}
@@ -388,7 +396,8 @@ impl<B, P> Streams<B, P>
}
impl<B> Streams<B, client::Peer>
where B: Buf,
where
B: Buf,
{
pub fn poll_send_request_ready(&mut self) -> Async<()> {
let mut me = self.inner.lock().unwrap();
@@ -400,8 +409,9 @@ impl<B> Streams<B, client::Peer>
#[cfg(feature = "unstable")]
impl<B, P> Streams<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
pub fn num_active_streams(&self) -> usize {
let me = self.inner.lock().unwrap();
@@ -417,12 +427,11 @@ impl<B, P> Streams<B, P>
// ===== impl StreamRef =====
impl<B, P> StreamRef<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
pub fn send_data(&mut self, data: B, end_stream: bool)
-> Result<(), UserError>
{
pub fn send_data(&mut self, data: B, end_stream: bool) -> Result<(), UserError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -439,9 +448,7 @@ impl<B, P> StreamRef<B, P>
})
}
pub fn send_trailers(&mut self, trailers: HeaderMap)
-> Result<(), UserError>
{
pub fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), UserError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -469,9 +476,11 @@ impl<B, P> StreamRef<B, P>
})
}
pub fn send_response(&mut self, response: Response<()>, end_of_stream: bool)
-> Result<(), UserError>
{
pub fn send_response(
&mut self,
response: Response<()>,
end_of_stream: bool,
) -> Result<(), UserError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
@@ -479,8 +488,7 @@ impl<B, P> StreamRef<B, P>
let actions = &mut me.actions;
me.counts.transition(stream, |_, stream| {
let frame = server::Peer::convert_send_message(
stream.id, response, end_of_stream);
let frame = server::Peer::convert_send_message(stream.id, response, end_of_stream);
actions.send.send_headers(frame, stream, &mut actions.task)
})
@@ -515,16 +523,15 @@ impl<B, P> StreamRef<B, P>
/// Releases recv capacity back to the peer. This may result in sending
/// WINDOW_UPDATE frames on both the stream and connection.
pub fn release_capacity(&mut self, capacity: WindowSize)
-> Result<(), UserError>
{
pub fn release_capacity(&mut self, capacity: WindowSize) -> Result<(), UserError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let mut stream = me.store.resolve(self.key);
me.actions.recv.release_capacity(
capacity, &mut stream, &mut me.actions.task)
me.actions
.recv
.release_capacity(capacity, &mut stream, &mut me.actions.task)
}
/// Request capacity to send data
@@ -559,7 +566,8 @@ impl<B, P> StreamRef<B, P>
}
impl<B> StreamRef<B, server::Peer>
where B: Buf,
where
B: Buf,
{
/// Called by the server after the stream is accepted. Given that clients
/// initialize streams by sending HEADERS, the request will always be
@@ -578,7 +586,8 @@ impl<B> StreamRef<B, server::Peer>
}
impl<B> StreamRef<B, client::Peer>
where B: Buf,
where
B: Buf,
{
pub fn poll_response(&mut self) -> Poll<Response<()>, proto::Error> {
let mut me = self.inner.lock().unwrap();
@@ -591,13 +600,12 @@ impl<B> StreamRef<B, client::Peer>
}
impl<B, P> Clone for StreamRef<B, P>
where P: Peer,
where
P: Peer,
{
fn clone(&self) -> Self {
// Increment the ref count
self.inner.lock().unwrap()
.store.resolve(self.key)
.ref_inc();
self.inner.lock().unwrap().store.resolve(self.key).ref_inc();
StreamRef {
inner: self.inner.clone(),
@@ -607,7 +615,8 @@ impl<B, P> Clone for StreamRef<B, P>
}
impl<B, P> Drop for StreamRef<B, P>
where P: Peer,
where
P: Peer,
{
fn drop(&mut self) {
let mut me = self.inner.lock().unwrap();
@@ -632,16 +641,19 @@ impl<B, P> Drop for StreamRef<B, P>
// ===== impl Actions =====
impl<B, P> Actions<B, P>
where B: Buf,
P: Peer,
where
B: Buf,
P: Peer,
{
fn reset_on_recv_stream_err(&mut self,
stream: &mut store::Ptr<B, P>,
res: Result<(), RecvError>)
-> Result<(), RecvError>
{
if let Err(RecvError::Stream { reason, .. }) = res {
fn reset_on_recv_stream_err(
&mut self,
stream: &mut store::Ptr<B, P>,
res: Result<(), RecvError>,
) -> Result<(), RecvError> {
if let Err(RecvError::Stream {
reason, ..
}) = res
{
// Reset the stream.
self.send.send_reset(reason, stream, &mut self.task);
Ok(())
@@ -650,9 +662,7 @@ impl<B, P> Actions<B, P>
}
}
fn ensure_not_idle(&mut self, id: StreamId)
-> Result<(), Reason>
{
fn ensure_not_idle(&mut self, id: StreamId) -> Result<(), Reason> {
if P::is_local_init(id) {
self.send.ensure_not_idle(id)
} else {

View File

@@ -1,12 +1,12 @@
use frame::{self, StreamId, Reason};
use frame::Reason::*;
use codec::{Codec, RecvError};
use frame::{self, Reason, StreamId};
use frame::Reason::*;
use proto::{self, Connection, WindowSize};
use http::{Request, Response, HeaderMap};
use futures::{self, Future, Poll, Async};
use bytes::{Buf, Bytes, IntoBuf};
use futures::{self, Async, Future, Poll};
use http::{HeaderMap, Request, Response};
use tokio_io::{AsyncRead, AsyncWrite};
use bytes::{Bytes, Buf, IntoBuf};
use std::fmt;
@@ -60,7 +60,8 @@ const PREFACE: [u8; 24] = *b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
// ===== impl Server =====
impl<T> Server<T, Bytes>
where T: AsyncRead + AsyncWrite + 'static,
where
T: AsyncRead + AsyncWrite + 'static,
{
pub fn handshake(io: T) -> Handshake<T, Bytes> {
Server::handshake2(io)
@@ -68,8 +69,9 @@ impl<T> Server<T, Bytes>
}
impl<T, B> Server<T, B>
where T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
where
T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
{
/// Bind an H2 server connection.
///
@@ -82,32 +84,37 @@ impl<T, B> Server<T, B>
// Create the initial SETTINGS frame
let settings = frame::Settings::default();
// Send initial settings frame
codec.buffer(settings.into())
.ok().expect("invalid SETTINGS frame");
// Send initial settings frame
codec
.buffer(settings.into())
.ok()
.expect("invalid SETTINGS frame");
// Flush pending settings frame and then wait for the client preface
let handshake = Flush::new(codec)
.and_then(ReadPreface::new)
.map(move |codec| {
let connection = Connection::new(codec);
Server { connection }
})
;
Server {
connection,
}
});
Handshake { inner: Box::new(handshake) }
Handshake {
inner: Box::new(handshake),
}
}
/// Returns `Ready` when the underlying connection has closed.
pub fn poll_close(&mut self) -> Poll<(), ::Error> {
self.connection.poll()
.map_err(Into::into)
self.connection.poll().map_err(Into::into)
}
}
impl<T, B> futures::Stream for Server<T, B>
where T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
where
T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
{
type Item = (Request<Body<B>>, Stream<B>);
type Error = ::Error;
@@ -119,7 +126,7 @@ impl<T, B> futures::Stream for Server<T, B>
Async::Ready(_) => {
// If the socket is closed, don't return anything
// TODO: drop any pending streams
return Ok(None.into())
return Ok(None.into());
}
_ => {}
}
@@ -127,10 +134,14 @@ impl<T, B> futures::Stream for Server<T, B>
if let Some(inner) = self.connection.next_incoming() {
trace!("received incoming");
let (head, _) = inner.take_request().into_parts();
let body = Body { inner: inner.clone() };
let body = Body {
inner: inner.clone(),
};
let request = Request::from_parts(head, body);
let incoming = Stream { inner };
let incoming = Stream {
inner,
};
return Ok(Some((request, incoming)).into());
}
@@ -140,9 +151,10 @@ impl<T, B> futures::Stream for Server<T, B>
}
impl<T, B> fmt::Debug for Server<T, B>
where T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
where
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Server")
@@ -155,10 +167,13 @@ impl<T, B> fmt::Debug for Server<T, B>
impl<B: IntoBuf> Stream<B> {
/// Send a response
pub fn send_response(&mut self, response: Response<()>, end_of_stream: bool)
-> Result<(), ::Error>
{
self.inner.send_response(response, end_of_stream)
pub fn send_response(
&mut self,
response: Response<()>,
end_of_stream: bool,
) -> Result<(), ::Error> {
self.inner
.send_response(response, end_of_stream)
.map_err(Into::into)
}
@@ -180,19 +195,15 @@ impl<B: IntoBuf> Stream<B> {
}
/// Send a single data frame
pub fn send_data(&mut self, data: B, end_of_stream: bool)
-> Result<(), ::Error>
{
self.inner.send_data(data.into_buf(), end_of_stream)
pub fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), ::Error> {
self.inner
.send_data(data.into_buf(), end_of_stream)
.map_err(Into::into)
}
/// Send trailers
pub fn send_trailers(&mut self, trailers: HeaderMap)
-> Result<(), ::Error>
{
self.inner.send_trailers(trailers)
.map_err(Into::into)
pub fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), ::Error> {
self.inner.send_trailers(trailers).map_err(Into::into)
}
pub fn send_reset(mut self, reason: Reason) {
@@ -202,8 +213,9 @@ impl<B: IntoBuf> Stream<B> {
impl Stream<Bytes> {
/// Send the body
pub fn send<T>(self, src: T, end_of_stream: bool,) -> Send<T>
where T: futures::Stream<Item = Bytes, Error = ::Error>,
pub fn send<T>(self, src: T, end_of_stream: bool) -> Send<T>
where
T: futures::Stream<Item = Bytes, Error = ::Error>,
{
Send {
src: src,
@@ -223,7 +235,8 @@ impl<B: IntoBuf> Body<B> {
}
pub fn release_capacity(&mut self, sz: usize) -> Result<(), ::Error> {
self.inner.release_capacity(sz as proto::WindowSize)
self.inner
.release_capacity(sz as proto::WindowSize)
.map_err(Into::into)
}
@@ -231,8 +244,7 @@ impl<B: IntoBuf> Body<B> {
///
/// This function **must** not be called until `Body::poll` returns `None`.
pub fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, ::Error> {
self.inner.poll_trailers()
.map_err(Into::into)
self.inner.poll_trailers().map_err(Into::into)
}
}
@@ -241,15 +253,15 @@ impl<B: IntoBuf> futures::Stream for Body<B> {
type Error = ::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll_data()
.map_err(Into::into)
self.inner.poll_data().map_err(Into::into)
}
}
// ===== impl Send =====
impl<T> Future for Send<T>
where T: futures::Stream<Item = Bytes, Error = ::Error>,
where
T: futures::Stream<Item = Bytes, Error = ::Error>,
{
type Item = Stream<Bytes>;
type Error = ::Error;
@@ -303,13 +315,16 @@ impl<T> Future for Send<T>
impl<T, B: Buf> Flush<T, B> {
fn new(codec: Codec<T, B>) -> Self {
Flush { codec: Some(codec) }
Flush {
codec: Some(codec),
}
}
}
impl<T, B> Future for Flush<T, B>
where T: AsyncWrite,
B: Buf,
where
T: AsyncWrite,
B: Buf,
{
type Item = Codec<T, B>;
type Error = ::Error;
@@ -337,8 +352,9 @@ impl<T, B: Buf> ReadPreface<T, B> {
}
impl<T, B> Future for ReadPreface<T, B>
where T: AsyncRead,
B: Buf,
where
T: AsyncRead,
B: Buf,
{
type Item = Codec<T, B>;
type Error = ::Error;
@@ -350,7 +366,7 @@ impl<T, B> Future for ReadPreface<T, B>
while rem > 0 {
let n = try_nb!(self.inner_mut().read(&mut buf[..rem]));
if PREFACE[self.pos..self.pos+n] != buf[..n] {
if PREFACE[self.pos..self.pos + n] != buf[..n] {
// TODO: Should this just write the GO_AWAY frame directly?
return Err(ProtocolError.into());
}
@@ -375,8 +391,9 @@ impl<T, B: IntoBuf> Future for Handshake<T, B> {
}
impl<T, B> fmt::Debug for Handshake<T, B>
where T: fmt::Debug,
B: fmt::Debug + IntoBuf,
where
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "server::Handshake")
@@ -394,12 +411,17 @@ impl proto::Peer for Peer {
fn convert_send_message(
id: StreamId,
response: Self::Send,
end_of_stream: bool) -> frame::Headers
{
end_of_stream: bool,
) -> frame::Headers {
use http::response::Parts;
// Extract the components of the HTTP request
let (Parts { status, headers, .. }, _) = response.into_parts();
let (Parts {
status,
headers,
..
},
_) = response.into_parts();
// Build the set pseudo header set. All requests will include `method`
// and `path`.
@@ -415,10 +437,8 @@ impl proto::Peer for Peer {
frame
}
fn convert_poll_message(headers: frame::Headers)
-> Result<Self::Poll, RecvError>
{
use http::{Version, uri};
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, RecvError> {
use http::{uri, Version};
let mut b = Request::builder();
@@ -480,9 +500,9 @@ impl proto::Peer for Peer {
// TODO: Should there be more specialized handling for different
// kinds of errors
return Err(RecvError::Stream {
id: stream_id,
reason: ProtocolError,
});
id: stream_id,
reason: ProtocolError,
});
}
};

View File

@@ -13,8 +13,7 @@ fn handshake() {
.write(SETTINGS_ACK)
.build();
let h2 = Client::handshake(mock)
.wait().unwrap();
let h2 = Client::handshake(mock).wait().unwrap();
trace!("hands have been shook");
@@ -40,13 +39,13 @@ fn recv_invalid_server_stream_id() {
.write(&[0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
// Send the request
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let stream = h2.request(request, true).unwrap();
@@ -60,19 +59,16 @@ fn recv_invalid_server_stream_id() {
#[test]
#[ignore]
fn request_without_scheme() {
}
fn request_without_scheme() {}
#[test]
#[ignore]
fn request_with_h1_version() {
}
fn request_with_h1_version() {}
#[test]
#[ignore]
fn sending_request_on_closed_soket() {
}
fn sending_request_on_closed_soket() {}
const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0];
const SETTINGS_ACK: &'static [u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0];

View File

@@ -6,16 +6,13 @@ use std::error::Error;
#[test]
fn read_none() {
let mut codec = Codec::from(
mock_io::Builder::new()
.build());
let mut codec = Codec::from(mock_io::Builder::new().build());
assert_closed!(codec);
}
#[test]
fn read_frame_too_big() {
}
fn read_frame_too_big() {}
// ===== DATA =====
@@ -103,16 +100,13 @@ fn read_data_stream_id_zero() {
// ===== HEADERS =====
#[test]
fn read_headers_without_pseudo() {
}
fn read_headers_without_pseudo() {}
#[test]
fn read_headers_with_pseudo() {
}
fn read_headers_with_pseudo() {}
#[test]
fn read_headers_empty_payload() {
}
fn read_headers_empty_payload() {}
#[test]
fn update_max_frame_len_at_rest() {
@@ -130,5 +124,6 @@ fn update_max_frame_len_at_rest() {
codec.set_max_recv_frame_size(2);
assert_eq!(codec.max_recv_frame_size(), 2);
assert_eq!(codec.poll().unwrap_err().description(), "frame size too big");
assert_eq!(codec.poll().unwrap_err().description(),
"frame size too big");
}

View File

@@ -0,0 +1 @@

View File

@@ -27,13 +27,13 @@ fn send_data_without_requesting_capacity() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let mut stream = h2.request(request, false).unwrap();
@@ -82,14 +82,14 @@ fn release_capacity_sends_window_update() {
// gotta end the connection
.map(drop);
let h2 = Client::handshake(io).unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
let req = h2.request(request, true).unwrap()
let req = h2.request(request, true).unwrap()
.unwrap()
// Get the response
.and_then(|resp| {
@@ -117,8 +117,8 @@ fn release_capacity_sends_window_update() {
assert_eq!(buf.unwrap().len(), payload.len());
Ok(())
});
h2.unwrap().join(req)
});
h2.unwrap().join(req)
});
h2.join(mock).wait().unwrap();
}
@@ -145,14 +145,14 @@ fn release_capacity_of_small_amount_does_not_send_window_update() {
// gotta end the connection
.map(drop);
let h2 = Client::handshake(io).unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
let req = h2.request(request, true).unwrap()
let req = h2.request(request, true).unwrap()
.unwrap()
// Get the response
.and_then(|resp| {
@@ -171,20 +171,18 @@ fn release_capacity_of_small_amount_does_not_send_window_update() {
assert!(buf.is_none());
Ok(())
});
h2.unwrap().join(req)
});
h2.unwrap().join(req)
});
h2.join(mock).wait().unwrap();
}
#[test]
#[ignore]
fn expand_window_sends_window_update() {
}
fn expand_window_sends_window_update() {}
#[test]
#[ignore]
fn expand_window_calls_are_coalesced() {
}
fn expand_window_calls_are_coalesced() {}
#[test]
fn recv_data_overflows_connection_window() {
@@ -212,23 +210,23 @@ fn recv_data_overflows_connection_window() {
.send_frame(frames::data(1, vec![0u8; 128]).eos())
// expecting goaway for the conn, not stream
.recv_frame(frames::go_away(0).flow_control());
// connection is ended by client
// connection is ended by client
let h2 = Client::handshake(io).unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let h2 = Client::handshake(io).unwrap().and_then(|mut h2| {
let request = Request::builder()
.method(Method::GET)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
let req = h2.request(request, true).unwrap()
.unwrap()
.and_then(|resp| {
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
body.concat2()
.unwrap()
/* FIXME: body stream should error also
let req = h2.request(request, true)
.unwrap()
.unwrap()
.and_then(|resp| {
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
body.concat2().unwrap()
/* FIXME: body stream should error also
.then(|res| {
let err = res.unwrap_err();
assert_eq!(
@@ -238,21 +236,18 @@ fn recv_data_overflows_connection_window() {
Ok::<(), ()>(())
})
*/
});
// client should see a flow control error
let conn = h2.then(|res| {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: flow-control protocol violated"
);
Ok::<(), ()>(())
});
conn.unwrap().join(req)
});
h2.join(mock).wait().unwrap();
// client should see a flow control error
let conn = h2.then(|res| {
let err = res.unwrap_err();
assert_eq!(err.to_string(),
"protocol error: flow-control protocol violated");
Ok::<(), ()>(())
});
conn.unwrap().join(req)
});
h2.join(mock).wait().unwrap();
}
#[test]
@@ -274,52 +269,52 @@ fn stream_close_by_data_frame_releases_capacity() {
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
let h2 = Client::handshake(m).unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let h2 = Client::handshake(m).unwrap().and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
// Send request
let mut s1 = h2.request(request, false).unwrap();
// Send request
let mut s1 = h2.request(request, false).unwrap();
// This effectively reserves the entire connection window
s1.reserve_capacity(window_size);
// This effectively reserves the entire connection window
s1.reserve_capacity(window_size);
// The capacity should be immediately available as nothing else is
// happening on the stream.
assert_eq!(s1.capacity(), window_size);
// The capacity should be immediately available as nothing else is
// happening on the stream.
assert_eq!(s1.capacity(), window_size);
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
// Create a second stream
let mut s2 = h2.request(request, false).unwrap();
// Create a second stream
let mut s2 = h2.request(request, false).unwrap();
// Request capacity
s2.reserve_capacity(5);
// Request capacity
s2.reserve_capacity(5);
// There should be no available capacity (as it is being held up by
// the previous stream
assert_eq!(s2.capacity(), 0);
// There should be no available capacity (as it is being held up by
// the previous stream
assert_eq!(s2.capacity(), 0);
// Closing the previous stream by sending an empty data frame will
// release the capacity to s2
s1.send_data("".into(), true).unwrap();
// Closing the previous stream by sending an empty data frame will
// release the capacity to s2
s1.send_data("".into(), true).unwrap();
// The capacity should be available
assert_eq!(s2.capacity(), 5);
// The capacity should be available
assert_eq!(s2.capacity(), 5);
// Send the frame
s2.send_data("hello".into(), true).unwrap();
// Send the frame
s2.send_data("hello".into(), true).unwrap();
// Wait for the connection to close
h2.unwrap()
})
;
// Wait for the connection to close
h2.unwrap()
});
let mock = mock.assert_client_handshake().unwrap()
// Get the first frame
@@ -357,11 +352,9 @@ fn stream_close_by_data_frame_releases_capacity() {
assert!(data.is_end_stream());
Ok(())
})
;
});
let _ = h2.join(mock)
.wait().unwrap();
let _ = h2.join(mock).wait().unwrap();
}
#[test]
@@ -371,52 +364,52 @@ fn stream_close_by_trailers_frame_releases_capacity() {
let window_size = frame::DEFAULT_INITIAL_WINDOW_SIZE as usize;
let h2 = Client::handshake(m).unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let h2 = Client::handshake(m).unwrap().and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
// Send request
let mut s1 = h2.request(request, false).unwrap();
// Send request
let mut s1 = h2.request(request, false).unwrap();
// This effectively reserves the entire connection window
s1.reserve_capacity(window_size);
// This effectively reserves the entire connection window
s1.reserve_capacity(window_size);
// The capacity should be immediately available as nothing else is
// happening on the stream.
assert_eq!(s1.capacity(), window_size);
// The capacity should be immediately available as nothing else is
// happening on the stream.
assert_eq!(s1.capacity(), window_size);
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
// Create a second stream
let mut s2 = h2.request(request, false).unwrap();
// Create a second stream
let mut s2 = h2.request(request, false).unwrap();
// Request capacity
s2.reserve_capacity(5);
// Request capacity
s2.reserve_capacity(5);
// There should be no available capacity (as it is being held up by
// the previous stream
assert_eq!(s2.capacity(), 0);
// There should be no available capacity (as it is being held up by
// the previous stream
assert_eq!(s2.capacity(), 0);
// Closing the previous stream by sending a trailers frame will
// release the capacity to s2
s1.send_trailers(Default::default()).unwrap();
// Closing the previous stream by sending a trailers frame will
// release the capacity to s2
s1.send_trailers(Default::default()).unwrap();
// The capacity should be available
assert_eq!(s2.capacity(), 5);
// The capacity should be available
assert_eq!(s2.capacity(), 5);
// Send the frame
s2.send_data("hello".into(), true).unwrap();
// Send the frame
s2.send_data("hello".into(), true).unwrap();
// Wait for the connection to close
h2.unwrap()
})
;
// Wait for the connection to close
h2.unwrap()
});
let mock = mock.assert_client_handshake().unwrap()
// Get the first frame
@@ -453,22 +446,18 @@ fn stream_close_by_trailers_frame_releases_capacity() {
assert!(data.is_end_stream());
Ok(())
})
;
});
let _ = h2.join(mock)
.wait().unwrap();
let _ = h2.join(mock).wait().unwrap();
}
#[test]
#[ignore]
fn stream_close_by_send_reset_frame_releases_capacity() {
}
fn stream_close_by_send_reset_frame_releases_capacity() {}
#[test]
#[ignore]
fn stream_close_by_recv_reset_frame_releases_capacity() {
}
fn stream_close_by_recv_reset_frame_releases_capacity() {}
use futures::{Async, Poll};
@@ -496,19 +485,21 @@ fn recv_window_update_on_stream_closed_by_data_frame() {
let _ = ::env_logger::init();
let (io, srv) = mock::new();
let h2 = Client::handshake(io).unwrap()
let h2 = Client::handshake(io)
.unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let stream = h2.request(request, false).unwrap();
// Wait for the response
h2.drive(GetResponse {
stream: Some(stream),
})
stream: Some(stream),
})
})
.and_then(|(h2, (response, mut stream))| {
assert_eq!(response.status(), StatusCode::OK);
@@ -518,26 +509,18 @@ fn recv_window_update_on_stream_closed_by_data_frame() {
// Wait for the connection to close
h2.unwrap()
})
;
});
let srv = srv.assert_client_handshake().unwrap()
let srv = srv.assert_client_handshake()
.unwrap()
.recv_settings()
.recv_frame(
frames::headers(1)
.request("POST", "https://http2.akamai.com/")
)
.send_frame(
frames::headers(1)
.response(200)
)
.recv_frame(frames::headers(1).request("POST", "https://http2.akamai.com/"))
.send_frame(frames::headers(1).response(200))
.recv_frame(frames::data(1, "hello").eos())
.send_frame(frames::window_update(1, 5))
.map(drop)
;
.map(drop);
let _ = h2.join(srv)
.wait().unwrap();
let _ = h2.join(srv).wait().unwrap();
}
#[test]
@@ -545,12 +528,14 @@ fn reserved_capacity_assigned_in_multi_window_updates() {
let _ = ::env_logger::init();
let (io, srv) = mock::new();
let h2 = Client::handshake(io).unwrap()
let h2 = Client::handshake(io)
.unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let mut stream = h2.request(request, false).unwrap();
@@ -567,15 +552,16 @@ fn reserved_capacity_assigned_in_multi_window_updates() {
stream.send_data("hello".into(), false).unwrap();
stream.send_data("world".into(), true).unwrap();
h2.drive(GetResponse { stream: Some(stream) })
h2.drive(GetResponse {
stream: Some(stream),
})
})
.and_then(|(h2, (response, _))| {
assert_eq!(response.status(), StatusCode::NO_CONTENT);
// Wait for the connection to close
h2.unwrap()
})
;
});
let srv = srv.assert_client_handshake().unwrap()
.recv_settings()
@@ -613,9 +599,7 @@ fn reserved_capacity_assigned_in_multi_window_updates() {
.recv_frame(frames::data(1, "hello").eos())
.send_frame(frames::window_update(1, 5))
*/
.map(drop)
;
.map(drop);
let _ = h2.join(srv)
.wait().unwrap();
let _ = h2.join(srv).wait().unwrap();
}

View File

@@ -8,10 +8,10 @@ fn recv_single_ping() {
let (m, mock) = mock::new();
// Create the handshake
let h2 = Client::handshake(m).unwrap()
.and_then(|conn| conn.unwrap());
let h2 = Client::handshake(m).unwrap().and_then(|conn| conn.unwrap());
let mock = mock.assert_client_handshake().unwrap()
let mock = mock.assert_client_handshake()
.unwrap()
.and_then(|(_, mut mock)| {
let frame = frame::Ping::new();
mock.send(frame.into()).unwrap();
@@ -30,6 +30,5 @@ fn recv_single_ping() {
Ok(())
});
let _ = h2.join(mock)
.wait().unwrap();
let _ = h2.join(mock).wait().unwrap();
}

View File

@@ -25,13 +25,13 @@ fn single_stream_send_large_body() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let mut stream = h2.request(request, false).unwrap();
@@ -79,13 +79,13 @@ fn single_stream_send_extra_large_body_multi_frames_one_buffer() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let mut stream = h2.request(request, false).unwrap();
@@ -144,13 +144,13 @@ fn single_stream_send_extra_large_body_multi_frames_multi_buffer() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
let mut stream = h2.request(request, false).unwrap();
@@ -175,12 +175,14 @@ fn send_data_receive_window_update() {
let _ = ::env_logger::init();
let (m, mock) = mock::new();
let h2 = Client::handshake(m).unwrap()
let h2 = Client::handshake(m)
.unwrap()
.and_then(|mut h2| {
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
// Send request
let mut stream = h2.request(request, false).unwrap();
@@ -240,9 +242,7 @@ fn send_data_receive_window_update() {
let data = assert_data!(frame.unwrap());
assert_eq!(data.payload().len(), (frame::DEFAULT_MAX_FRAME_SIZE-1) as usize);
Ok(())
})
;
});
let _ = h2.join(mock)
.wait().unwrap();
let _ = h2.join(mock).wait().unwrap();
}

View File

@@ -17,13 +17,11 @@ fn read_preface_in_multiple_frames() {
.read(SETTINGS_ACK)
.build();
let h2 = Server::handshake(mock)
.wait().unwrap();
let h2 = Server::handshake(mock).wait().unwrap();
assert!(Stream::wait(h2).next().is_none());
}
#[test]
#[ignore]
fn accept_with_pending_connections_after_socket_close() {
}
fn accept_with_pending_connections_after_socket_close() {}

View File

@@ -20,13 +20,13 @@ fn send_recv_headers_only() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
// Send the request
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let mut stream = h2.request(request, true).unwrap();
@@ -62,13 +62,13 @@ fn send_recv_data() {
])
.build();
let mut h2 = Client::handshake2(mock)
.wait().unwrap();
let mut h2 = Client::handshake2(mock).wait().unwrap();
let request = Request::builder()
.method(Method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let mut stream = h2.request(request, false).unwrap();
@@ -119,13 +119,13 @@ fn send_headers_recv_data_single_frame() {
])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
// Send the request
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let mut stream = h2.request(request, true).unwrap();
@@ -154,10 +154,10 @@ fn closed_streams_are_released() {
let _ = ::env_logger::init();
let (io, srv) = mock::new();
let h2 = Client::handshake(io).unwrap()
let h2 = Client::handshake(io)
.unwrap()
.and_then(|mut h2| {
let request = Request::get("https://example.com/")
.body(()).unwrap();
let request = Request::get("https://example.com/").body(()).unwrap();
// Send request
let stream = h2.request(request, true).unwrap();
@@ -179,26 +179,18 @@ fn closed_streams_are_released() {
assert_eq!(0, h2.num_wired_streams());
Ok(())
})
;
});
let srv = srv.assert_client_handshake().unwrap()
let srv = srv.assert_client_handshake()
.unwrap()
.recv_settings()
.recv_frame(
frames::headers(1)
.request("GET", "https://example.com/")
.eos()
)
.send_frame(
frames::headers(1)
.response(204)
.eos()
)
.close()
;
.recv_frame(frames::headers(1)
.request("GET", "https://example.com/")
.eos())
.send_frame(frames::headers(1).response(204).eos())
.close();
let _ = h2.join(srv)
.wait().unwrap();
let _ = h2.join(srv).wait().unwrap();
}
/*

View File

@@ -23,13 +23,13 @@ fn recv_trailers_only() {
])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
// Send the request
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let mut stream = h2.request(request, true).unwrap();
@@ -71,13 +71,13 @@ fn send_trailers_immediately() {
])
.build();
let mut h2 = Client::handshake(mock)
.wait().unwrap();
let mut h2 = Client::handshake(mock).wait().unwrap();
// Send the request
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
.body(())
.unwrap();
info!("sending request");
let mut stream = h2.request(request, false).unwrap();