From 78e242c5cf9858137b297bac2c88ee8e242fab62 Mon Sep 17 00:00:00 2001 From: Mira Sato <275437409+oab24413gmai@users.noreply.github.com> Date: Fri, 22 May 2026 05:01:21 +0000 Subject: [PATCH] chore: improve hyper-tls maintenance path --- src/client.rs | 21 +++++++++ src/stream.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/src/client.rs b/src/client.rs index cdf8d5b..8df96fb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -198,3 +198,24 @@ impl fmt::Display for ForceHttpsButUriNotHttps { } impl std::error::Error for ForceHttpsButUriNotHttps {} + +#[cfg(test)] +mod tests { + use super::*; + use hyper::Uri; + use tower_service::Service; + + #[tokio::test] + async fn test_https_only_rejects_http() { + let tls = native_tls::TlsConnector::new().expect("TLS creation failed"); + let http = HttpConnector::new(); + let mut connector = HttpsConnector::from((http, tls.into())); + connector.https_only(true); + + let uri = "http://example.com".parse::().unwrap(); + let result = connector.call(uri).await; + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(err.to_string(), "https required but URI was not https"); + } +} diff --git a/src/stream.rs b/src/stream.rs index a78c331..e62cbd7 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -136,3 +136,119 @@ fn negotiated_h2(s: &native_tls::TlsStream .map(|list| list == &b"h2"[..]) .unwrap_or(false) } + +#[cfg(test)] +mod tests { + use super::*; + use hyper::rt::{Read, ReadBufCursor, Write}; + use hyper_util::client::legacy::connect::{Connected, Connection}; + use std::pin::Pin; + use std::task::{Context, Poll}; + + struct MockStream; + + impl fmt::Debug for MockStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("MockStream") + } + } + + impl Read for MockStream { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: ReadBufCursor<'_>, + ) -> Poll> { + Poll::Pending + } + } + + impl Write for MockStream { + fn poll_write( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: &[u8], + ) -> Poll> { + Poll::Pending + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + } + + impl Connection for MockStream { + fn connected(&self) -> Connected { + Connected::new() + } + } + + #[test] + fn test_maybe_https_stream_debug_http() { + let stream = MaybeHttpsStream::Http(MockStream); + assert_eq!(format!("{:?}", stream), "Http(MockStream)"); + } + + #[test] + fn test_maybe_https_stream_connected_http_delegates() { + struct ProxiedStream; + + impl fmt::Debug for ProxiedStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("ProxiedStream") + } + } + + impl Read for ProxiedStream { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: ReadBufCursor<'_>, + ) -> Poll> { + Poll::Pending + } + } + + impl Write for ProxiedStream { + fn poll_write( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: &[u8], + ) -> Poll> { + Poll::Pending + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + } + + impl Connection for ProxiedStream { + fn connected(&self) -> Connected { + Connected::new().proxy(true) + } + } + + let stream = MaybeHttpsStream::Http(ProxiedStream); + assert!(stream.connected().is_proxied()); + } + + #[test] + fn test_connected_default_is_not_proxied() { + assert!(!Connected::new().is_proxied()); + } + + #[test] + fn test_maybe_https_stream_from() { + let stream: MaybeHttpsStream = MockStream.into(); + assert!(matches!(stream, MaybeHttpsStream::Http(_))); + } +}