Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 1 addition & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,12 @@ jobs:
target: ${{ matrix.platform.target }}
args: --release --out dist --manifest-path crates/primp-python/Cargo.toml
manylinux: auto
maturin-version: 1.12.4
- name: Build free-threaded wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist -i python3.14t --manifest-path crates/primp-python/Cargo.toml
manylinux: auto
maturin-version: 1.12.4
- name: Upload wheels
uses: actions/upload-artifact@v6
with:
Expand Down Expand Up @@ -144,14 +142,12 @@ jobs:
target: ${{ matrix.platform.target }}
args: --release --out dist --manifest-path crates/primp-python/Cargo.toml
manylinux: musllinux_1_2
maturin-version: 1.12.4
- name: Build free-threaded wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist -i python3.14t --manifest-path crates/primp-python/Cargo.toml
manylinux: musllinux_1_2
maturin-version: 1.12.4
- name: Upload wheels
uses: actions/upload-artifact@v6
with:
Expand Down Expand Up @@ -218,7 +214,6 @@ jobs:
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --manifest-path crates/primp-python/Cargo.toml
maturin-version: 1.12.4
- uses: actions/setup-python@v6
with:
python-version: 3.14t
Expand All @@ -228,7 +223,6 @@ jobs:
with:
target: ${{ matrix.platform.target }}
args: --release --out dist -i python3.14t --manifest-path crates/primp-python/Cargo.toml
maturin-version: 1.12.4
- name: Upload wheels
uses: actions/upload-artifact@v6
with:
Expand Down Expand Up @@ -270,13 +264,11 @@ jobs:
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --manifest-path crates/primp-python/Cargo.toml
maturin-version: 1.12.4
- name: Build free-threaded wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist -i python3.14t --manifest-path crates/primp-python/Cargo.toml
maturin-version: 1.12.4
- name: Upload wheels
uses: actions/upload-artifact@v6
with:
Expand Down Expand Up @@ -306,7 +298,6 @@ jobs:
with:
command: sdist
args: --out dist --manifest-path crates/primp-python/Cargo.toml
maturin-version: 1.12.4
- name: Upload sdist
uses: actions/upload-artifact@v6
with:
Expand All @@ -325,7 +316,7 @@ jobs:
steps:
- uses: actions/download-artifact@v7
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v4
uses: actions/attest@v4
with:
subject-path: 'wheels-*/*'
- name: Install uv
Expand Down
6 changes: 2 additions & 4 deletions crates/primp-hyper-rustls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "primp-hyper-rustls"
version = "0.27.7"
version = "0.27.9"
edition = "2021"
rust-version = "1.84"
license = "Apache-2.0 OR ISC OR MIT"
Expand Down Expand Up @@ -28,9 +28,8 @@ http = "1"
hyper = { version = "1.8", path = "../primp-hyper", package = "primp-hyper", default-features = false }
hyper-util = { version = "0.1", path = "../primp-hyper-util", package = "primp-hyper-util", default-features = false, features = ["client-legacy", "tokio"] }
log = { version = "0.4.4", optional = true }
pki-types = { package = "rustls-pki-types", version = "1" }
rustls-native-certs = { version = "0.8", optional = true }
rustls-platform-verifier = { version = "0.6", optional = true }
rustls-platform-verifier = { version = "0.7", optional = true }
rustls = { version = "0.23", path = "../primp-rustls/rustls", package = "primp-rustls", default-features = false }
tokio = "1.0"
tokio-rustls = { version = "0.26", path = "../primp-tokio-rustls", package = "primp-tokio-rustls", default-features = false }
Expand All @@ -42,7 +41,6 @@ cfg-if = "1"
http-body-util = "0.1"
hyper-util = { version = "0.1", path = "../primp-hyper-util", package = "primp-hyper-util", default-features = false, features = ["server-auto"] }
rustls = { version = "0.23", path = "../primp-rustls/rustls", package = "primp-rustls", default-features = false, features = ["tls12"] }
rustls-pemfile = "2"
tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] }

[package.metadata.docs.rs]
Expand Down
6 changes: 2 additions & 4 deletions crates/primp-hyper-rustls/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,14 @@ impl ConfigBuilderExt for ConfigBuilder<ClientConfig, WantsVerifier> {
match roots.add(cert) {
Ok(_) => valid_count += 1,
Err(err) => {
crate::log::debug!("certificate parsing failed: {:?}", err);
crate::log::debug!("certificate parsing failed: {err:?}");
invalid_count += 1
}
}
}

crate::log::debug!(
"with_native_roots processed {} valid and {} invalid certs",
valid_count,
invalid_count
"with_native_roots processed {valid_count} valid and {invalid_count} invalid certs"
);
if roots.is_empty() {
crate::log::debug!("no valid native root CA certificates found");
Expand Down
19 changes: 18 additions & 1 deletion crates/primp-hyper-rustls/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use http::Uri;
use hyper::rt;
use hyper_util::client::legacy::connect::Connection;
use hyper_util::rt::TokioIo;
use pki_types::ServerName;
use rustls::pki_types::ServerName;
use tokio_rustls::TlsConnector;
use tower_service::Service;

Expand All @@ -35,6 +35,23 @@ impl<T> HttpsConnector<T> {
builder::ConnectorBuilder::new()
}

/// Creates a new `HttpsConnector`.
///
/// The recommended way to create a `HttpsConnector` is to use a [`crate::HttpsConnectorBuilder`]. See [`HttpsConnector::builder()`].
pub fn new(
http: T,
tls_config: impl Into<Arc<rustls::ClientConfig>>,
force_https: bool,
server_name_resolver: Arc<dyn ResolveServerName + Send + Sync>,
) -> Self {
Self {
http,
tls_config: tls_config.into(),
force_https,
server_name_resolver,
}
}

/// Force the use of HTTPS when connecting.
///
/// If a URL is not `https` when connecting, an error is returned.
Expand Down
4 changes: 2 additions & 2 deletions crates/primp-hyper-rustls/src/connector/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{DefaultServerNameResolver, HttpsConnector, ResolveServerName};
feature = "rustls-platform-verifier"
))]
use crate::config::ConfigBuilderExt;
use pki_types::ServerName;
use rustls::pki_types::ServerName;

/// A builder for an [`HttpsConnector`]
///
Expand Down Expand Up @@ -108,7 +108,7 @@ impl ConnectorBuilder<WantsTlsConfig> {
ClientConfig::builder_with_provider(provider.into())
.with_safe_default_protocol_versions()
.and_then(|builder| builder.try_with_platform_verifier())
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
.map_err(std::io::Error::other)?
.with_no_client_auth(),
))
}
Expand Down
11 changes: 4 additions & 7 deletions crates/primp-hyper-util/src/client/pool/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,25 +264,22 @@ mod internal {
future::Either::Left((Ok(pool_got), connecting)) => {
events.on_race_lost(BackgroundConnect {
future: connecting,
shared: Arc::downgrade(&shared),
shared: Arc::downgrade(shared),
});
return Poll::Ready(Ok(Cached::new(
pool_got,
Arc::downgrade(&shared),
Arc::downgrade(shared),
)));
}
future::Either::Right((connected, _waiter)) => {
let inner = connected?;
return Poll::Ready(Ok(Cached::new(
inner,
Arc::downgrade(&shared),
)));
return Poll::Ready(Ok(Cached::new(inner, Arc::downgrade(shared))));
}
}
}
CacheFuture::Connecting { shared, future } => {
let inner = ready!(Pin::new(future).poll(cx))?;
return Poll::Ready(Ok(Cached::new(inner, Arc::downgrade(&shared))));
return Poll::Ready(Ok(Cached::new(inner, Arc::downgrade(shared))));
}
CacheFuture::Cached { svc } => {
return Poll::Ready(Ok(svc.take().unwrap()));
Expand Down
7 changes: 1 addition & 6 deletions crates/primp-hyper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "primp-hyper"
version = "1.8.1"
version = "1.9.0"
description = "Fork of the original hyper HTTP library."
readme = "README.md"
license = "MIT"
Expand Down Expand Up @@ -76,7 +76,6 @@ http1 = [
"dep:futures-core",
"dep:httparse",
"dep:itoa",
"dep:pin-utils",
]
http2 = [
"dep:futures-channel",
Expand Down Expand Up @@ -149,10 +148,6 @@ optional = true
version = "0.2.4"
optional = true

[dependencies.pin-utils]
version = "0.1"
optional = true

[dependencies.smallvec]
version = "1.12"
features = [
Expand Down
4 changes: 4 additions & 0 deletions crates/primp-hyper/src/body/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,16 @@ impl fmt::Debug for Sender {

#[cfg(test)]
mod tests {
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
use std::mem;
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
use std::task::Poll;

#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
use super::{Body, Incoming, SizeHint};
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
use super::{DecodedLength, Sender};
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
use http_body_util::BodyExt;

#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
Expand Down
33 changes: 32 additions & 1 deletion crates/primp-hyper/src/client/conn/http2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,26 @@ where
pub fn is_extended_connect_protocol_enabled(&self) -> bool {
self.inner.1.is_extended_connect_protocol_enabled()
}

/// Returns the current maximum send stream count.
///
/// This setting is configured in a [`SETTINGS_MAX_CONCURRENT_STREAMS` parameter][1] in a `SETTINGS` frame,
/// and may change throughout the connection lifetime.
///
/// [1]: https://datatracker.ietf.org/doc/html/rfc7540#section-5.1.2
pub fn current_max_send_streams(&self) -> usize {
self.inner.1.current_max_send_streams()
}

/// Returns the current maximum receive stream count.
///
/// This setting is configured in a [`SETTINGS_MAX_CONCURRENT_STREAMS` parameter][1] in a `SETTINGS` frame,
/// and may change throughout the connection lifetime.
///
/// [1]: https://datatracker.ietf.org/doc/html/rfc7540#section-5.1.2
pub fn current_max_recv_streams(&self) -> usize {
self.inner.1.current_max_recv_streams()
}
}

impl<T, B, E> fmt::Debug for Connection<T, B, E>
Expand Down Expand Up @@ -399,7 +419,7 @@ where
///
/// See [Section 5.1.2] in the HTTP/2 spec for more details.
///
/// [Section 5.1.2]: https://http2.github.io/http2-spec/#rfc.section.5.1.2
/// [Section 5.1.2]: https://httpwg.org/specs/rfc7540.html#rfc.section.5.1.2
pub fn max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {
self.h2_builder.max_concurrent_streams = max.into();
self
Expand Down Expand Up @@ -544,6 +564,17 @@ where
self
}

/// Configures the maximum number of local resets due to protocol errors made by the remote end.
///
/// See the documentation of [`h2::client::Builder::max_local_error_reset_streams`] for more
/// details.
///
/// The default value is 1024.
pub fn max_local_error_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {
self.h2_builder.max_local_error_reset_streams = max.into();
self
}

/// Constructs a connection with the configured options and IO.
/// See [`client::conn`](crate::client::conn) for more.
///
Expand Down
3 changes: 3 additions & 0 deletions crates/primp-hyper/src/client/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ where
}
};
trace!("send_when canceled");
// Tell pipe_task to reset the h2 stream so that
// RST_STREAM is sent and flow-control capacity freed.
this.when.as_mut().cancel();
Poll::Ready(())
}
Poll::Ready(Err((error, message))) => {
Expand Down
12 changes: 10 additions & 2 deletions crates/primp-hyper/src/common/io/rewind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ pub(crate) struct Rewind<T> {
}

impl<T> Rewind<T> {
#[cfg(test)]
#[cfg(all(
test,
any(feature = "client", feature = "server"),
any(feature = "http1", feature = "http2")
))]
pub(crate) fn new(io: T) -> Self {
Rewind {
pre: None,
Expand All @@ -29,7 +33,11 @@ impl<T> Rewind<T> {
}
}

#[cfg(test)]
#[cfg(all(
test,
any(feature = "client", feature = "server"),
any(feature = "http1", feature = "http2")
))]
pub(crate) fn rewind(&mut self, bs: Bytes) {
debug_assert!(self.pre.is_none());
self.pre = Some(bs);
Expand Down
4 changes: 2 additions & 2 deletions crates/primp-hyper/src/common/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ fn noop_waker() -> Waker {
pub(crate) fn now_or_never<F: std::future::Future>(fut: F) -> Option<F::Output> {
let waker = noop_waker();
let mut cx = Context::from_waker(&waker);
// TODO: replace with std::pin::pin! and drop pin-utils once MSRV >= 1.68
pin_utils::pin_mut!(fut);
// TODO: replace with std::pin::pin! once MSRV >= 1.68
tokio::pin!(fut);
match fut.poll(&mut cx) {
Poll::Ready(res) => Some(res),
Poll::Pending => None,
Expand Down
23 changes: 23 additions & 0 deletions crates/primp-hyper/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ impl Error {
matches!(self.inner.kind, Kind::Parse(Parse::Status))
}

/// Returns true if this was an HTTP parse error caused by HTTP2 preface sent over an HTTP1
/// connection.
#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub fn is_parse_version_h2(&self) -> bool {
matches!(self.inner.kind, Kind::Parse(Parse::VersionH2))
}

/// Returns true if this error was caused by user code.
pub fn is_user(&self) -> bool {
matches!(self.inner.kind, Kind::User(_))
Expand All @@ -218,6 +225,22 @@ impl Error {
}

/// Returns true if the connection closed before a message could complete.
///
/// This means that the supplied IO connection reported EOF (closed) while
/// hyper's HTTP state indicates more of the message (either request or
/// response) needed to be transmitted.
///
/// Some cases this could happen (not exhaustive):
///
/// - A request is written on a connection, and the next `read` reports
/// EOF (perhaps a server just closed an "idle" connection).
/// - A message body is only partially receive before the connection
/// reports EOF.
/// - A client writes a request to your server, and then closes the write
/// half while waiting for your response. If you need to support this,
/// consider enabling [`half_close`].
///
/// [`half_close`]: crate::server::conn::http1::Builder::half_close()
pub fn is_incomplete_message(&self) -> bool {
#[cfg(not(all(any(feature = "client", feature = "server"), feature = "http1")))]
return false;
Expand Down
Loading
Loading