Compare commits
10 Commits
dc7aa8e0f2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b088466fea | ||
|
|
7c45fd1657 | ||
|
|
ee6d3fd5e1 | ||
|
|
88b0789254 | ||
|
|
d05d0a7a93 | ||
|
|
b0f54d80f2 | ||
|
|
756384f4cd | ||
|
|
fd4040d90d | ||
|
|
e4cf88c1a1 | ||
|
|
f6aa3be671 |
2
.github/workflows/CI.yml
vendored
2
.github/workflows/CI.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.49 # never go past Hyper's own MSRV
|
||||
- 1.56 # never go past Hyper's own MSRV
|
||||
|
||||
os:
|
||||
- ubuntu-latest
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,10 +1,11 @@
|
||||
target
|
||||
Cargo.lock
|
||||
h2spec
|
||||
.history
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Files generated by honggfuzz
|
||||
hfuzz_target
|
||||
hfuzz_workspace
|
||||
hfuzz_workspace
|
||||
@@ -1,3 +1,9 @@
|
||||
# 0.3.14 (August 16, 2022)
|
||||
|
||||
* Add `Error::is_reset` function.
|
||||
* Bump MSRV to Rust 1.56.
|
||||
* Return `RST_STREAM(NO_ERROR)` when the server early responds.
|
||||
|
||||
# 0.3.13 (March 31, 2022)
|
||||
|
||||
* Update private internal `tokio-util` dependency.
|
||||
|
||||
@@ -5,7 +5,7 @@ name = "h2"
|
||||
# - html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create git tag
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
license = "MIT"
|
||||
authors = [
|
||||
"Carl Lerche <me@carllerche.com>",
|
||||
|
||||
@@ -526,7 +526,7 @@ where
|
||||
///
|
||||
/// 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
|
||||
/// This method returns the currently acknowledged value received from the
|
||||
/// remote.
|
||||
///
|
||||
/// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
|
||||
@@ -1022,6 +1022,12 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the header table size
|
||||
pub fn header_table_size(&mut self, size: u32) -> &mut Self {
|
||||
self.settings.set_header_table_size(Some(size));
|
||||
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 {
|
||||
@@ -1280,7 +1286,7 @@ where
|
||||
///
|
||||
/// This limit is configured by the server peer by sending the
|
||||
/// [`SETTINGS_MAX_CONCURRENT_STREAMS` parameter][1] in a `SETTINGS` frame.
|
||||
/// This method returns the currently acknowledged value recieved from the
|
||||
/// This method returns the currently acknowledged value received from the
|
||||
/// remote.
|
||||
///
|
||||
/// [1]: https://tools.ietf.org/html/rfc7540#section-5.1.2
|
||||
|
||||
10
src/error.rs
10
src/error.rs
@@ -59,10 +59,7 @@ impl Error {
|
||||
|
||||
/// Returns true if the error is an io::Error
|
||||
pub fn is_io(&self) -> bool {
|
||||
match self.kind {
|
||||
Kind::Io(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.kind, Kind::Io(..))
|
||||
}
|
||||
|
||||
/// Returns the error if the error is an io::Error
|
||||
@@ -92,6 +89,11 @@ impl Error {
|
||||
matches!(self.kind, Kind::GoAway(..))
|
||||
}
|
||||
|
||||
/// Returns true if the error is from a `RST_STREAM`.
|
||||
pub fn is_reset(&self) -> bool {
|
||||
matches!(self.kind, Kind::Reset(..))
|
||||
}
|
||||
|
||||
/// Returns true if the error was received in a frame from the remote.
|
||||
///
|
||||
/// Such as from a received `RST_STREAM` or `GOAWAY` frame.
|
||||
|
||||
@@ -686,13 +686,13 @@ impl Iterator for Iter {
|
||||
return Some(Method(method));
|
||||
}
|
||||
|
||||
if let Some(scheme) = pseudo.scheme.take() {
|
||||
return Some(Scheme(scheme));
|
||||
}
|
||||
|
||||
if let Some(authority) = pseudo.authority.take() {
|
||||
return Some(Authority(authority));
|
||||
}
|
||||
|
||||
if let Some(scheme) = pseudo.scheme.take() {
|
||||
return Some(Scheme(scheme));
|
||||
}
|
||||
|
||||
if let Some(path) = pseudo.path.take() {
|
||||
return Some(Path(path));
|
||||
|
||||
@@ -120,12 +120,10 @@ impl Settings {
|
||||
pub fn header_table_size(&self) -> Option<u32> {
|
||||
self.header_table_size
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pub fn set_header_table_size(&mut self, size: Option<u32>) {
|
||||
self.header_table_size = size;
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
|
||||
use self::Setting::*;
|
||||
|
||||
43
src/lib.rs
43
src/lib.rs
@@ -78,7 +78,7 @@
|
||||
//! [`server::handshake`]: server/fn.handshake.html
|
||||
//! [`client::handshake`]: client/fn.handshake.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/h2/0.3.13")]
|
||||
#![doc(html_root_url = "https://docs.rs/h2/0.3.14")]
|
||||
#![deny(missing_debug_implementations, missing_docs)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
|
||||
@@ -133,44 +133,3 @@ pub use crate::share::{FlowControl, Ping, PingPong, Pong, RecvStream, SendStream
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
pub use codec::{Codec, SendError, UserError};
|
||||
|
||||
use std::task::Poll;
|
||||
|
||||
// TODO: Get rid of this trait once https://github.com/rust-lang/rust/pull/63512
|
||||
// is stabilized.
|
||||
trait PollExt<T, E> {
|
||||
/// Changes the success value of this `Poll` with the closure provided.
|
||||
fn map_ok_<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
|
||||
where
|
||||
F: FnOnce(T) -> U;
|
||||
/// Changes the error value of this `Poll` with the closure provided.
|
||||
fn map_err_<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
|
||||
where
|
||||
F: FnOnce(E) -> U;
|
||||
}
|
||||
|
||||
impl<T, E> PollExt<T, E> for Poll<Option<Result<T, E>>> {
|
||||
fn map_ok_<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
match self {
|
||||
Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_err_<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
|
||||
where
|
||||
F: FnOnce(E) -> U,
|
||||
{
|
||||
match self {
|
||||
Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ use http::{HeaderMap, Request, Response};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
use tokio::io::AsyncWrite;
|
||||
|
||||
use crate::PollExt;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fmt, io};
|
||||
|
||||
@@ -1282,7 +1281,7 @@ impl OpaqueStreamRef {
|
||||
me.actions
|
||||
.recv
|
||||
.poll_pushed(cx, &mut stream)
|
||||
.map_ok_(|(h, key)| {
|
||||
.map_ok(|(h, key)| {
|
||||
me.refs += 1;
|
||||
let opaque_ref =
|
||||
OpaqueStreamRef::new(self.inner.clone(), &mut me.store.resolve(key));
|
||||
@@ -1462,9 +1461,21 @@ fn drop_stream_ref(inner: &Mutex<Inner>, key: store::Key) {
|
||||
|
||||
fn maybe_cancel(stream: &mut store::Ptr, actions: &mut Actions, counts: &mut Counts) {
|
||||
if stream.is_canceled_interest() {
|
||||
// Server is allowed to early respond without fully consuming the client input stream
|
||||
// But per the RFC, must send a RST_STREAM(NO_ERROR) in such cases. https://www.rfc-editor.org/rfc/rfc7540#section-8.1
|
||||
// Some other http2 implementation may interpret other error code as fatal if not respected (i.e: nginx https://trac.nginx.org/nginx/ticket/2376)
|
||||
let reason = if counts.peer().is_server()
|
||||
&& stream.state.is_send_closed()
|
||||
&& stream.state.is_recv_streaming()
|
||||
{
|
||||
Reason::NO_ERROR
|
||||
} else {
|
||||
Reason::CANCEL
|
||||
};
|
||||
|
||||
actions
|
||||
.send
|
||||
.schedule_implicit_reset(stream, Reason::CANCEL, counts, &mut actions.task);
|
||||
.schedule_implicit_reset(stream, reason, counts, &mut actions.task);
|
||||
actions.recv.enqueue_reset_expiration(stream, counts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ where
|
||||
///
|
||||
/// This limit is configured by the client peer by sending the
|
||||
/// [`SETTINGS_MAX_CONCURRENT_STREAMS` parameter][1] in a `SETTINGS` frame.
|
||||
/// This method returns the currently acknowledged value recieved from the
|
||||
/// This method returns the currently acknowledged value received from the
|
||||
/// remote.
|
||||
///
|
||||
/// [1]: https://tools.ietf.org/html/rfc7540#section-5.1.2
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::proto::{self, WindowSize};
|
||||
use bytes::{Buf, Bytes};
|
||||
use http::HeaderMap;
|
||||
|
||||
use crate::PollExt;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "stream")]
|
||||
use std::pin::Pin;
|
||||
@@ -307,8 +306,8 @@ impl<B: Buf> SendStream<B> {
|
||||
pub fn poll_capacity(&mut self, cx: &mut Context) -> Poll<Option<Result<usize, crate::Error>>> {
|
||||
self.inner
|
||||
.poll_capacity(cx)
|
||||
.map_ok_(|w| w as usize)
|
||||
.map_err_(Into::into)
|
||||
.map_ok(|w| w as usize)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Sends a single data frame to the remote peer.
|
||||
@@ -403,7 +402,7 @@ impl RecvStream {
|
||||
|
||||
/// Poll for the next data frame.
|
||||
pub fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, crate::Error>>> {
|
||||
self.inner.inner.poll_data(cx).map_err_(Into::into)
|
||||
self.inner.inner.poll_data(cx).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
||||
@@ -566,7 +566,9 @@ async fn sends_reset_cancel_when_req_body_is_dropped() {
|
||||
client
|
||||
.recv_frame(frames::headers(1).response(200).eos())
|
||||
.await;
|
||||
client.recv_frame(frames::reset(1).cancel()).await;
|
||||
client
|
||||
.recv_frame(frames::reset(1).reason(Reason::NO_ERROR))
|
||||
.await;
|
||||
};
|
||||
|
||||
let srv = async move {
|
||||
|
||||
Reference in New Issue
Block a user