Merge pull request #71 from carllerche/ver/rustfmt
Use rustfmt to enforce consistent formatting
This commit is contained in:
84
.rustfmt.toml
Normal file
84
.rustfmt.toml
Normal 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
|
||||
@@ -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
95
CONTRIBUTING.md
Normal 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
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(())
|
||||
|
||||
173
src/client.rs
173
src/client.rs
@@ -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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
12
src/error.rs
12
src/error.rs
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::StreamId;
|
||||
|
||||
use bytes::{BufMut, BigEndian};
|
||||
use bytes::{BigEndian, BufMut};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Head {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use frame::Reason;
|
||||
use codec::RecvError;
|
||||
use frame::Reason;
|
||||
|
||||
use std::io;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
@@ -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?
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
148
src/server.rs
148
src/server.rs
@@ -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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user