Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to h2 v0.3.13 #1

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
dbaa3a4
fix: properly reject prioritized HEADERS with stream ID of zero
seanmonstar Nov 23, 2021
87969c1
Implement the extended CONNECT protocol from RFC 8441 (#565)
nox Nov 24, 2021
e9e0f27
Add test that would make wait_for_capacity hang if it doesn't loop
nox Dec 2, 2021
efa113b
Add max send buffer per stream option (#580)
seanmonstar Dec 8, 2021
88037ae
v0.3.8
seanmonstar Dec 8, 2021
a5c60b2
Fix poll_capacity to wake in combination with max_send_buffer_size
seanmonstar Dec 9, 2021
308663e
v0.3.9
seanmonstar Dec 9, 2021
c876dda
Fix panic when receiving malformed push promise with stream id 0
seanmonstar Dec 9, 2021
6336cc3
Add Error::is_go_away() and Error::is_remote()
seanmonstar Jan 6, 2022
b949d6e
v0.3.10
seanmonstar Jan 7, 2022
d92ba1c
Make SendStream::poll_capacity never return Ok(Some(0)) (#596)
nox Jan 19, 2022
a28a39c
Update tracing-subscriber and use tracing-tree when testing (#586)
nox Jan 21, 2022
7de2ccc
fix panic when receiving already reset push promise (#597)
seanmonstar Jan 21, 2022
556447c
Make use of NLL to clean up handshaking logic (#576)
nox Jan 26, 2022
b0d01bb
v0.3.11
nox Jan 26, 2022
4dc2b4a
Avoid time operations that can panic
olix0r Jan 31, 2022
47e9f62
There's no such thing as HTTP/2.0
LPardue Feb 6, 2022
4c31a32
Upgrade dev-dependencies
djc Feb 11, 2022
7bb1462
Bump MSRV to 1.49, since Tokio uses it
seanmonstar Feb 24, 2022
85549fc
fix header parsing: consume buf only if header name and value are bot…
hikaricai Feb 24, 2022
b8eab38
tracing: remove I/O type names from handshake spans (#608)
hawkw Mar 8, 2022
3383ef7
v0.3.12
hawkw Mar 9, 2022
a54d926
Upgrade tokio-util to 0.7
djc Feb 11, 2022
3a0c622
v0.3.13
seanmonstar Mar 31, 2022
7f99182
Merge tag 'v0.3.13' into feature/grpc-uds
nightkr May 10, 2022
9aab362
Ignore doctest that fails due to unexposed private API
nightkr May 10, 2022
4999051
Retrigger tests
nightkr Aug 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,32 @@ jobs:
- name: Check minimal versions
run: cargo clean; cargo update -Zminimal-versions; cargo check
if: matrix.rust == 'nightly'

msrv:
name: Check MSRV (${{ matrix.rust }})
needs: [style]
strategy:
matrix:
rust:
- 1.49 # never go past Hyper's own MSRV

os:
- ubuntu-latest

runs-on: ${{ matrix.os }}

steps:
- name: Checkout
uses: actions/checkout@v1

- name: Install Rust (${{ matrix.rust }})
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true

- name: Check
uses: actions-rs/cargo@v1
with:
command: check
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
# 0.3.13 (March 31, 2022)

* Update private internal `tokio-util` dependency.

# 0.3.12 (March 9, 2022)

* Avoid time operations that can panic (#599)
* Bump MSRV to Rust 1.49 (#606)
* Fix header decoding error when a header name is contained at a continuation
header boundary (#589)
* Remove I/O type names from handshake `tracing` spans (#608)

# 0.3.11 (January 26, 2022)

* Make `SendStream::poll_capacity` never return `Ok(Some(0))` (#596)
* Fix panic when receiving already reset push promise (#597)

# 0.3.10 (January 6, 2022)

* Add `Error::is_go_away()` and `Error::is_remote()` methods.
* Fix panic if receiving malformed PUSH_PROMISE with stream ID of 0.

# 0.3.9 (December 9, 2021)

* Fix hang related to new `max_send_buffer_size`.

# 0.3.8 (December 8, 2021)

* Add "extended CONNECT support". Adds `h2::ext::Protocol`, which is used for request and response extensions to connect new protocols over an HTTP/2 stream.
* Add `max_send_buffer_size` options to client and server builders, and a default of ~400MB. This acts like a high-water mark for the `poll_capacity()` method.
* Fix panic if receiving malformed HEADERS with stream ID of 0.

# 0.3.7 (October 22, 2021)

* Fix panic if server sends a malformed frame on a stream client was about to open.
Expand Down
22 changes: 10 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ name = "h2"
# - html_root_url.
# - Update CHANGELOG.md.
# - Create git tag
version = "0.3.7"
version = "0.3.13"
license = "MIT"
authors = [
"Carl Lerche <[email protected]>",
"Sean McArthur <[email protected]>",
]
description = "An HTTP/2.0 client and server"
description = "An HTTP/2 client and server"
documentation = "https://docs.rs/h2"
repository = "https://github.com/hyperium/h2"
readme = "README.md"
Expand Down Expand Up @@ -43,7 +43,7 @@ members = [
futures-core = { version = "0.3", default-features = false }
futures-sink = { version = "0.3", default-features = false }
futures-util = { version = "0.3", default-features = false }
tokio-util = { version = "0.6", features = ["codec"] }
tokio-util = { version = "0.7.1", features = ["codec"] }
tokio = { version = "1", features = ["io-util"] }
bytes = "1"
http = "0.2"
Expand All @@ -55,22 +55,20 @@ indexmap = { version = "1.5.2", features = ["std"] }
[dev-dependencies]

# Fuzzing
quickcheck = { version = "0.4.1", default-features = false }
rand = "0.3.15"
quickcheck = { version = "1.0.3", default-features = false }
rand = "0.8.4"

# HPACK fixtures
hex = "0.2.0"
walkdir = "1.0.0"
hex = "0.4.3"
walkdir = "2.3.2"
serde = "1.0.0"
serde_json = "1.0.0"

# Examples
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "net"] }
env_logger = { version = "0.5.3", default-features = false }
rustls = "0.19"
tokio-rustls = "0.22"
webpki = "0.21"
webpki-roots = "0.21"
env_logger = { version = "0.9", default-features = false }
tokio-rustls = "0.23.2"
webpki-roots = "0.22.2"

[package.metadata.docs.rs]
features = ["stream"]
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# H2

A Tokio aware, HTTP/2.0 client & server implementation for Rust.
A Tokio aware, HTTP/2 client & server implementation for Rust.

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Crates.io](https://img.shields.io/crates/v/h2.svg)](https://crates.io/crates/h2)
Expand All @@ -12,21 +12,21 @@ More information about this crate can be found in the [crate documentation][dox]

## Features

* Client and server HTTP/2.0 implementation.
* Implements the full HTTP/2.0 specification.
* Client and server HTTP/2 implementation.
* Implements the full HTTP/2 specification.
* Passes [h2spec](https://github.com/summerwind/h2spec).
* Focus on performance and correctness.
* Built on [Tokio](https://tokio.rs).

## Non goals

This crate is intended to only be an implementation of the HTTP/2.0
This crate is intended to only be an implementation of the HTTP/2
specification. It does not handle:

* Managing TCP connections
* HTTP 1.0 upgrade
* TLS
* Any feature not described by the HTTP/2.0 specification.
* Any feature not described by the HTTP/2 specification.

This crate is now used by [hyper](https://github.com/hyperium/hyper), which will provide all of these features.

Expand Down Expand Up @@ -55,7 +55,7 @@ fn main() {

**How does h2 compare to [solicit] or [rust-http2]?**

The h2 library has implemented more of the details of the HTTP/2.0 specification
The h2 library has implemented more of the details of the HTTP/2 specification
than any other Rust library. It also passes the [h2spec] set of tests. The h2
library is rapidly approaching "production ready" quality.

Expand Down
24 changes: 17 additions & 7 deletions examples/akamai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use http::{Method, Request};
use tokio::net::TcpStream;
use tokio_rustls::TlsConnector;

use rustls::Session;
use webpki::DNSNameRef;
use tokio_rustls::rustls::{OwnedTrustAnchor, RootCertStore, ServerName};

use std::convert::TryFrom;
use std::error::Error;
use std::net::ToSocketAddrs;

Expand All @@ -16,9 +16,19 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
let _ = env_logger::try_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);
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}));

let mut c = tokio_rustls::rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
c.alpn_protocols.push(ALPN_H2.as_bytes().to_owned());
c
});
Expand All @@ -33,13 +43,13 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
println!("ADDR: {:?}", addr);

let tcp = TcpStream::connect(&addr).await?;
let dns_name = DNSNameRef::try_from_ascii_str("http2.akamai.com").unwrap();
let dns_name = ServerName::try_from("http2.akamai.com").unwrap();
let connector = TlsConnector::from(tls_client_config);
let res = connector.connect(dns_name, tcp).await;
let tls = res.unwrap();
{
let (_, session) = tls.get_ref();
let negotiated_protocol = session.get_alpn_protocol();
let negotiated_protocol = session.alpn_protocol();
assert_eq!(
Some(ALPN_H2.as_bytes()),
negotiated_protocol.as_ref().map(|x| &**x)
Expand Down
2 changes: 0 additions & 2 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ cargo-fuzz = true
arbitrary = { version = "1", features = ["derive"] }
libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] }
tokio = { version = "1", features = [ "full" ] }
bytes = "0.5.2"
h2 = { path = "../", features = [ "unstable" ] }
h2-support = { path = "../tests/h2-support" }
futures = { version = "0.3", default-features = false, features = ["std"] }
http = "0.2"
env_logger = { version = "0.5.3", default-features = false }

# Prevent this from interfering with workspaces
[workspace]
Expand Down
45 changes: 41 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
//! [`Error`]: ../struct.Error.html

use crate::codec::{Codec, SendError, UserError};
use crate::ext::Protocol;
use crate::frame::{Headers, Pseudo, Reason, Settings, StreamId};
use crate::proto::{self, Error};
use crate::{FlowControl, PingPong, RecvStream, SendStream};
Expand Down Expand Up @@ -319,6 +320,9 @@ pub struct Builder {
/// Initial target window size for new connections.
initial_target_connection_window_size: Option<u32>,

/// Maximum amount of bytes to "buffer" for writing per stream.
max_send_buffer_size: usize,

/// Maximum number of locally reset streams to keep at a time.
reset_stream_max: usize,

Expand Down Expand Up @@ -517,6 +521,19 @@ where
(response, stream)
})
}

/// Returns whether the [extended CONNECT protocol][1] is enabled or not.
///
/// This setting is configured by the server peer by sending the
/// [`SETTINGS_ENABLE_CONNECT_PROTOCOL` parameter][2] in a `SETTINGS` frame.
/// This method returns the currently acknowledged value recieved from the
/// remote.
///
/// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
/// [2]: https://datatracker.ietf.org/doc/html/rfc8441#section-3
pub fn is_extended_connect_protocol_enabled(&self) -> bool {
self.inner.is_extended_connect_protocol_enabled()
}
}

impl<B> fmt::Debug for SendRequest<B>
Expand Down Expand Up @@ -614,6 +631,7 @@ impl Builder {
/// ```
pub fn new() -> Builder {
Builder {
max_send_buffer_size: proto::DEFAULT_MAX_SEND_BUFFER_SIZE,
reset_stream_duration: Duration::from_secs(proto::DEFAULT_RESET_STREAM_SECS),
reset_stream_max: proto::DEFAULT_RESET_STREAM_MAX,
initial_target_connection_window_size: None,
Expand Down Expand Up @@ -948,6 +966,24 @@ impl Builder {
self
}

/// Sets the maximum send buffer size per stream.
///
/// Once a stream has buffered up to (or over) the maximum, the stream's
/// flow control will not "poll" additional capacity. Once bytes for the
/// stream have been written to the connection, the send buffer capacity
/// will be freed up again.
///
/// The default is currently ~400MB, but may change.
///
/// # Panics
///
/// This function panics if `max` is larger than `u32::MAX`.
pub fn max_send_buffer_size(&mut self, max: usize) -> &mut Self {
assert!(max <= std::u32::MAX as usize);
self.max_send_buffer_size = max;
self
}

/// Enables or disables server push promises.
///
/// This value is included in the initial SETTINGS handshake. When set, the
Expand Down Expand Up @@ -1118,7 +1154,7 @@ where
let builder = Builder::new();
builder
.handshake(io)
.instrument(tracing::trace_span!("client_handshake", io = %std::any::type_name::<T>()))
.instrument(tracing::trace_span!("client_handshake"))
.await
}

Expand Down Expand Up @@ -1170,6 +1206,7 @@ where
proto::Config {
next_stream_id: builder.stream_id,
initial_max_send_streams: builder.initial_max_send_streams,
max_send_buffer_size: builder.max_send_buffer_size,
reset_stream_duration: builder.reset_stream_duration,
reset_stream_max: builder.reset_stream_max,
settings: builder.settings.clone(),
Expand Down Expand Up @@ -1246,11 +1283,10 @@ where
/// This method returns the currently acknowledged value recieved from the
/// remote.
///
/// [settings]: https://tools.ietf.org/html/rfc7540#section-5.1.2
/// [1]: https://tools.ietf.org/html/rfc7540#section-5.1.2
pub fn max_concurrent_send_streams(&self) -> usize {
self.inner.max_send_streams()
}

/// Returns the maximum number of concurrent streams that may be initiated
/// by the server on this connection.
///
Expand Down Expand Up @@ -1416,6 +1452,7 @@ impl Peer {
pub fn convert_send_message(
id: StreamId,
request: Request<()>,
protocol: Option<Protocol>,
end_of_stream: bool,
) -> Result<Headers, SendError> {
use http::request::Parts;
Expand All @@ -1435,7 +1472,7 @@ impl Peer {

// Build the set pseudo header set. All requests will include `method`
// and `path`.
let mut pseudo = Pseudo::request(method, uri);
let mut pseudo = Pseudo::request(method, uri, protocol);

if pseudo.scheme.is_none() {
// If the scheme is not set, then there are a two options.
Expand Down
17 changes: 16 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Error {
}
}

/// Returns the true if the error is an io::Error
/// Returns true if the error is an io::Error
pub fn is_io(&self) -> bool {
match self.kind {
Kind::Io(_) => true,
Expand Down Expand Up @@ -86,6 +86,21 @@ impl Error {
kind: Kind::Io(err),
}
}

/// Returns true if the error is from a `GOAWAY`.
pub fn is_go_away(&self) -> bool {
matches!(self.kind, Kind::GoAway(..))
}

/// Returns true if the error was received in a frame from the remote.
///
/// Such as from a received `RST_STREAM` or `GOAWAY` frame.
pub fn is_remote(&self) -> bool {
matches!(
self.kind,
Kind::GoAway(_, _, Initiator::Remote) | Kind::Reset(_, _, Initiator::Remote)
)
}
}

impl From<proto::Error> for Error {
Expand Down
Loading