Skip to content

Commit

Permalink
Merge patch (#16)
Browse files Browse the repository at this point in the history
* v0.3.26

* Rename project to `rh2`

* Refactor frame sending custom implementation

* Export frame `PseudoOrder` settings

* Reduce unnecessary Option packaging

* v0.3.27

* fix(frame/headers): Fix error when headers priority is empty

* v0.3.29

* feat(frame/headers): Packaging headers pseudo order type (#8)

* feat(frame/settings): Packaging settings type (#9)

* Initialize frame settings order in advance

* v0.3.31

* feat(frame): Add unknown_setting frame settings (#10)

* Add unknown_setting patch

* Customize all Http Settings order

* v0.3.40

* fix(frame): Fix unknown setting encode (#11)

* v0.3.41

* feat: Replace with static settings (#12)

* v0.3.50

* feat: Destructive update, fixed-length array records the setting frame order (#13)

* v0.3.60

* Update README.md

* Sync upstream (#14)

* fix: streams awaiting capacity lockout (#730) (#734)

This PR changes the the assign-capacity queue to prioritize streams that
are send-ready.

This is necessary to prevent a lockout when streams aren't able to proceed while
waiting for connection capacity, but there is none.

Closes hyperium/hyper#3338

Co-authored-by: dswij <dharmasw@outlook.com>

* v0.3.23

* streams: limit error resets for misbehaving connections

This change causes GOAWAYs to be issued to misbehaving connections which for one reason or another cause us to emit lots of error resets.

Error resets are not generally expected from valid implementations anyways.

The threshold after which we issue GOAWAYs is tunable, and will default to 1024.

* Prepare v0.3.24

* perf: optimize header list size calculations (#750)

This speeds up loading blocks in cases where we have many headers already.

* v0.3.25

* refactor: cleanup new unused warnings (#757)

* fix: limit number of CONTINUATION frames allowed

Calculate the amount of allowed CONTINUATION frames based on other
settings.

    max_header_list_size / max_frame_size

That is about how many CONTINUATION frames would be needed to send
headers up to the max allowed size. We then multiply by that by a small
amount, to allow for implementations that don't perfectly pack into the
minimum frames *needed*.

In practice, *much* more than that would be a very inefficient peer, or
a peer trying to waste resources.

See https://seanmonstar.com/blog/hyper-http2-continuation-flood/ for
more info.

* v0.3.26

* fix: return a WriteZero error if frames cannot be written (#783)

Some operating systems will allow you continually call `write()` on a closed socket, and will return `Ok(0)` instead of an error. This patch checks for a zero write, and instead of looping forever trying to write, returns a proper error.

Closes #781

Co-authored-by: leibeiyi <leibeiyi@coocaa.com>

* lints: fix unexpected cfgs warnings

* ci: pin deps for MSRV

* ci: pin more deps for MSRV job (#817)

* fix: notify_recv after send_reset() in reset_on_recv_stream_err() to ensure local stream is released properly (#816)

Similar to what have been done in fn send_reset<B>(), we should notify RecvStream that is parked after send_reset().

Co-authored-by: Jiahao Liang <gzliangjiahao@gmail.com>

---------

Co-authored-by: Sean McArthur <sean@seanmonstar.com>
Co-authored-by: dswij <dharmasw@outlook.com>
Co-authored-by: Noah Kennedy <nkennedy@cloudflare.com>
Co-authored-by: beiyi lei <niceskylei@gmail.com>
Co-authored-by: leibeiyi <leibeiyi@coocaa.com>
Co-authored-by: Jiahao Liang <gzliangjiahao@gmail.com>

* v0.3.61

---------

Co-authored-by: Sean McArthur <sean@seanmonstar.com>
Co-authored-by: dswij <dharmasw@outlook.com>
Co-authored-by: Noah Kennedy <nkennedy@cloudflare.com>
Co-authored-by: beiyi lei <niceskylei@gmail.com>
Co-authored-by: leibeiyi <leibeiyi@coocaa.com>
Co-authored-by: Jiahao Liang <gzliangjiahao@gmail.com>
  • Loading branch information
7 people authored Nov 15, 2024
1 parent a3b3d71 commit 8e21a74
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 110 deletions.
20 changes: 2 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,9 @@

* Limit number of CONTINUATION frames for misbehaving connections.

# 0.4.3 (March 15, 2024)
# 0.3.25 (March 15, 2024)

* Fix flow control limits to not apply until receiving SETTINGS ack.
* Fix not returning an error if IO ended without `close_notify`.
* Improve performance of decoding many headers.

# 0.4.2 (January 17th, 2024)

* Limit error resets for misbehaving connections.
* Fix selecting MAX_CONCURRENT_STREAMS value if no value is advertised initially.

# 0.4.1 (January 8, 2024)

* Fix assigning connection capacity which could starve streams in some instances.

# 0.4.0 (November 15, 2023)

* Update to `http` 1.0.
* Remove deprecated `Server::poll_close()`.
* Improve performance decoding many headers.

# 0.3.24 (January 17, 2024)

Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# H2

This project is forked from [h2](https://github.com/hyperium/h2)

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)
[![Documentation](https://docs.rs/h2/badge.svg)][dox]
[![Crates.io](https://img.shields.io/crates/v/rh2.svg)](https://crates.io/crates/rh2)
[![Documentation](https://docs.rs/rh2/badge.svg)][dox]

More information about this crate can be found in the [crate documentation][dox].

[dox]: https://docs.rs/h2
[dox]: https://docs.rs/rh2

## Features

Expand All @@ -34,19 +32,19 @@ This crate is now used by [hyper](https://github.com/hyperium/hyper), which will

## Usage

To use `h2`, first add this to your `Cargo.toml`:
To use `rh2`, first add this to your `Cargo.toml`:

```toml
[dependencies]
h2 = "0.4"
rh2 = "0.4"
```

Next, add this to your crate:

```rust
extern crate h2;
extern crate rh2;

use h2::server::Connection;
use rh2::server::Connection;

fn main() {
// ...
Expand All @@ -71,3 +69,7 @@ actively maintained.
[solicit]: https://github.com/mlalic/solicit
[rust-http2]: https://github.com/stepancheg/rust-http2
[h2spec]: https://github.com/summerwind/h2spec

## Accolades

The project is based on a fork of [h2](https://github.com/hyperium/h2).
31 changes: 22 additions & 9 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@
use crate::codec::{Codec, SendError, UserError};
use crate::ext::Protocol;
use crate::frame::{
Headers, Pseudo, PseudoOrder, Reason, Settings, SettingsOrder, StreamDependency, StreamId,
Headers, Pseudo, PseudoOrder, PseudoOrders, Reason, Settings, SettingsOrder, StreamDependency,
StreamId
};
use crate::proto::{self, Error};
use crate::{FlowControl, PingPong, RecvStream, SendStream};
Expand Down Expand Up @@ -347,7 +348,7 @@ pub struct Builder {
local_max_error_reset_streams: Option<usize>,

/// The headers frame pseudo order
headers_pseudo_order: Option<[PseudoOrder; 4]>,
headers_pseudo_order: Option<PseudoOrders>,

/// The headers frame priority
headers_priority: Option<StreamDependency>,
Expand Down Expand Up @@ -677,20 +678,20 @@ impl Builder {
}

/// Set http2 header pseudo order
pub fn headers_psuedo(&mut self, headers_psuedo: Option<[PseudoOrder; 4]>) -> &mut Self {
self.headers_pseudo_order = headers_psuedo;
pub fn headers_psuedo(&mut self, order: [PseudoOrder; 4]) -> &mut Self {
self.headers_pseudo_order = Some(order.into());
self
}

/// Set http2 header priority
pub fn headers_priority(&mut self, headers_priority: Option<StreamDependency>) -> &mut Self {
self.headers_priority = headers_priority;
pub fn headers_priority(&mut self, headers_priority: StreamDependency) -> &mut Self {
self.headers_priority = Some(headers_priority);
self
}

/// Settings frame order
pub fn settings_order(&mut self, order: Option<[SettingsOrder; 2]>) -> &mut Self {
self.settings.set_settings_order(order);
pub fn settings_order(&mut self, order: [SettingsOrder; 8]) -> &mut Self {
self.settings.set_settings_order(Some(order));
self
}

Expand Down Expand Up @@ -1173,6 +1174,18 @@ impl Builder {
self
}

/// unknown_setting8
pub fn unknown_setting8(&mut self, enabled: bool) -> &mut Self {
self.settings.set_unknown_setting_8(enabled);
self
}

/// unknown_setting8
pub fn unknown_setting9(&mut self, enabled: bool) -> &mut Self {
self.settings.set_unknown_setting_9(enabled);
self
}

/// Sets the first stream ID to something other than 1.
#[cfg(feature = "unstable")]
pub fn initial_stream_id(&mut self, stream_id: u32) -> &mut Self {
Expand Down Expand Up @@ -1614,7 +1627,7 @@ impl Peer {
request: Request<()>,
protocol: Option<Protocol>,
end_of_stream: bool,
pseudo_order: Option<[PseudoOrder; 4]>,
pseudo_order: Option<PseudoOrders>,
headers_priority: Option<StreamDependency>,
) -> Result<Headers, SendError> {
use http::request::Parts;
Expand Down
8 changes: 7 additions & 1 deletion src/codec/framed_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ where

loop {
while !self.encoder.is_empty() {
match self.encoder.next {
let n = match self.encoder.next {
Some(Next::Data(ref mut frame)) => {
tracing::trace!(queued_data_frame = true);
let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut());
Expand All @@ -148,6 +148,12 @@ where
))?
}
};
if n == 0 {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write frame to socket",
)));
}
}

match self.encoder.unset_frame() {
Expand Down
79 changes: 53 additions & 26 deletions src/frame/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub struct Pseudo {
pub status: Option<StatusCode>,

// order of pseudo headers
pub order: Option<[PseudoOrder; 4]>,
pub order: PseudoOrders,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand All @@ -85,6 +85,26 @@ pub enum PseudoOrder {
Path,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PseudoOrders([PseudoOrder; 4]);

impl From<[PseudoOrder; 4]> for PseudoOrders {
fn from(src: [PseudoOrder; 4]) -> Self {
PseudoOrders(src)
}
}

impl Default for PseudoOrders {
fn default() -> Self {
PseudoOrders([
PseudoOrder::Method,
PseudoOrder::Scheme,
PseudoOrder::Authority,
PseudoOrder::Path,
])
}
}

#[derive(Debug)]
pub struct Iter {
/// Pseudo headers
Expand Down Expand Up @@ -131,6 +151,13 @@ impl Headers {
fields: HeaderMap,
stream_dep: Option<StreamDependency>,
) -> Self {
// If the stream dependency is set, the PRIORITY flag must be set
let flags = if stream_dep.is_some() {
HeadersFlag(END_HEADERS | PRIORITY)
} else {
HeadersFlag::default()
};

Headers {
stream_id,
stream_dep,
Expand All @@ -140,7 +167,7 @@ impl Headers {
is_over_size: false,
pseudo,
},
flags: HeadersFlag::default(),
flags,
}
}

Expand Down Expand Up @@ -580,7 +607,7 @@ impl Pseudo {
method: Method,
uri: Uri,
protocol: Option<Protocol>,
pseudo_order: Option<[PseudoOrder; 4]>,
order: Option<PseudoOrders>,
) -> Self {
let parts = uri::Parts::from(uri);

Expand Down Expand Up @@ -610,7 +637,7 @@ impl Pseudo {
path,
protocol,
status: None,
order: pseudo_order,
order: order.unwrap_or_default(),
};

// If the URI includes a scheme component, add it to the pseudo headers
Expand All @@ -635,7 +662,7 @@ impl Pseudo {
path: None,
protocol: None,
status: Some(status),
order: None,
order: Default::default(),
}
}

Expand Down Expand Up @@ -730,28 +757,26 @@ impl Iterator for Iter {
use crate::hpack::Header::*;

if let Some(ref mut pseudo) = self.pseudo {
if let Some(orders) = pseudo.order.as_ref() {
for pseudo_type in orders {
match pseudo_type {
PseudoOrder::Method => {
if let Some(method) = pseudo.method.take() {
return Some(Method(method));
}
for pseudo_type in pseudo.order.0.iter() {
match pseudo_type {
PseudoOrder::Method => {
if let Some(method) = pseudo.method.take() {
return Some(Method(method));
}
PseudoOrder::Scheme => {
if let Some(scheme) = pseudo.scheme.take() {
return Some(Scheme(scheme));
}
}
PseudoOrder::Scheme => {
if let Some(scheme) = pseudo.scheme.take() {
return Some(Scheme(scheme));
}
PseudoOrder::Authority => {
if let Some(authority) = pseudo.authority.take() {
return Some(Authority(authority));
}
}
PseudoOrder::Authority => {
if let Some(authority) = pseudo.authority.take() {
return Some(Authority(authority));
}
PseudoOrder::Path => {
if let Some(path) = pseudo.path.take() {
return Some(Path(path));
}
}
PseudoOrder::Path => {
if let Some(path) = pseudo.path.take() {
return Some(Path(path));
}
}
}
Expand Down Expand Up @@ -827,9 +852,9 @@ impl HeadersFlag {
}

impl Default for HeadersFlag {
/// Returns a `HeadersFlag` value with `END_HEADERS` and `PRIORITY` set.
/// Returns a `HeadersFlag` value with `END_HEADERS` set.
fn default() -> Self {
HeadersFlag(END_HEADERS | PRIORITY)
HeadersFlag(END_HEADERS)
}
}

Expand Down Expand Up @@ -1048,6 +1073,8 @@ fn decoded_header_size(name: usize, value: usize) -> usize {

#[cfg(test)]
mod test {
use std::iter::FromIterator;

use super::*;
use crate::frame;
use crate::hpack::{huffman, Encoder};
Expand Down
3 changes: 2 additions & 1 deletion src/frame/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ pub use self::go_away::GoAway;
pub use self::head::{Head, Kind};
pub(crate) use self::headers::PseudoOrder;
pub use self::headers::{
parse_u64, Continuation, Headers, Pseudo, PushPromise, PushPromiseHeaderError,
parse_u64, Continuation, Headers, Pseudo, PseudoOrder, PseudoOrders, PushPromise,
PushPromiseHeaderError,
};
pub use self::ping::Ping;
pub use self::priority::{Priority, StreamDependency};
Expand Down
Loading

0 comments on commit 8e21a74

Please sign in to comment.