From 5834dbbd91c76288045799ef161b2ecdb76d04ce Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:44:33 +0200 Subject: [PATCH 01/13] acceptor: move TlsAcceptor above TlsStream --- src/acceptor.rs | 91 +++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index e843be2..ce5975b 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -16,6 +16,52 @@ mod builder; pub use builder::AcceptorBuilder; use builder::WantsTlsConfig; +/// A TLS acceptor that can be used with hyper servers. +pub struct TlsAcceptor { + config: Arc, + incoming: AddrIncoming, +} + +/// An Acceptor for the `https` scheme. +impl TlsAcceptor { + /// Provides a builder for a `TlsAcceptor`. + pub fn builder() -> AcceptorBuilder { + AcceptorBuilder::new() + } + + /// Creates a new `TlsAcceptor` from a `ServerConfig` and an `AddrIncoming`. + pub fn new(config: Arc, incoming: AddrIncoming) -> TlsAcceptor { + TlsAcceptor { config, incoming } + } +} + +impl Accept for TlsAcceptor { + type Conn = TlsStream; + type Error = io::Error; + + fn poll_accept( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + let pin = self.get_mut(); + match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) { + Some(Ok(sock)) => Poll::Ready(Some(Ok(TlsStream::new(sock, pin.config.clone())))), + Some(Err(e)) => Poll::Ready(Some(Err(e))), + None => Poll::Ready(None), + } + } +} + +impl From<(C, I)> for TlsAcceptor +where + C: Into>, + I: Into, +{ + fn from((config, incoming): (C, I)) -> TlsAcceptor { + TlsAcceptor::new(config.into(), incoming.into()) + } +} + enum State { Handshaking(tokio_rustls::Accept), Streaming(tokio_rustls::server::TlsStream), @@ -92,48 +138,3 @@ impl AsyncWrite for TlsStream { } } } - -/// A TLS acceptor that can be used with hyper servers. -pub struct TlsAcceptor { - config: Arc, - incoming: AddrIncoming, -} - -/// An Acceptor for the `https` scheme. -impl TlsAcceptor { - /// Provides a builder for a `TlsAcceptor`. - pub fn builder() -> AcceptorBuilder { - AcceptorBuilder::new() - } - /// Creates a new `TlsAcceptor` from a `ServerConfig` and an `AddrIncoming`. - pub fn new(config: Arc, incoming: AddrIncoming) -> TlsAcceptor { - TlsAcceptor { config, incoming } - } -} - -impl From<(C, I)> for TlsAcceptor -where - C: Into>, - I: Into, -{ - fn from((config, incoming): (C, I)) -> TlsAcceptor { - TlsAcceptor::new(config.into(), incoming.into()) - } -} - -impl Accept for TlsAcceptor { - type Conn = TlsStream; - type Error = io::Error; - - fn poll_accept( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let pin = self.get_mut(); - match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) { - Some(Ok(sock)) => Poll::Ready(Some(Ok(TlsStream::new(sock, pin.config.clone())))), - Some(Err(e)) => Poll::Ready(Some(Err(e))), - None => Poll::Ready(None), - } - } -} From 7dd9522bbc7cb7215ab3e3bc12361e838001e806 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:44:53 +0200 Subject: [PATCH 02/13] acceptor: move State below TlsStream --- src/acceptor.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index ce5975b..955483b 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -62,11 +62,6 @@ where } } -enum State { - Handshaking(tokio_rustls::Accept), - Streaming(tokio_rustls::server::TlsStream), -} - // tokio_rustls::server::TlsStream doesn't expose constructor methods, // so we have to TlsAcceptor::accept and handshake to have access to it // TlsStream implements AsyncRead/AsyncWrite by handshaking with tokio_rustls::Accept first @@ -138,3 +133,8 @@ impl AsyncWrite for TlsStream { } } } + +enum State { + Handshaking(tokio_rustls::Accept), + Streaming(tokio_rustls::server::TlsStream), +} From 7dd88683b7a558cc3adac8f375fc51890bf91ebe Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:46:32 +0200 Subject: [PATCH 03/13] acceptor: host Poll::Ready() out of match arms --- src/acceptor.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index 955483b..40a7f68 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -44,11 +44,11 @@ impl Accept for TlsAcceptor { cx: &mut Context<'_>, ) -> Poll>> { let pin = self.get_mut(); - match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) { - Some(Ok(sock)) => Poll::Ready(Some(Ok(TlsStream::new(sock, pin.config.clone())))), - Some(Err(e)) => Poll::Ready(Some(Err(e))), - None => Poll::Ready(None), - } + Poll::Ready(match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) { + Some(Ok(sock)) => Some(Ok(TlsStream::new(sock, pin.config.clone()))), + Some(Err(e)) => Some(Err(e)), + None => None, + }) } } From ec3715d55ae36281b5907c6d3e736692b8d57302 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:48:35 +0200 Subject: [PATCH 04/13] Lint against unreachable_pub --- src/connector.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/connector.rs b/src/connector.rs index 18ad689..f5e1b73 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -10,7 +10,7 @@ use tokio_rustls::TlsConnector; use crate::stream::MaybeHttpsStream; -pub mod builder; +pub(crate) mod builder; type BoxError = Box; diff --git a/src/lib.rs b/src/lib.rs index b207568..cd34b37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ //! # fn main() {} //! ``` -#![warn(missing_docs)] +#![warn(missing_docs, unreachable_pub)] #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "acceptor")] @@ -87,7 +87,7 @@ mod stream; #[cfg(feature = "logging")] mod log { - pub use log::{debug, trace}; + pub(crate) use log::{debug, trace}; } #[cfg(not(feature = "logging"))] From 26c7e08cb2e79c6f2f86ec6b4582770826e339b8 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:50:39 +0200 Subject: [PATCH 05/13] Warn against clippy::use_self --- src/acceptor.rs | 12 ++++++------ src/connector.rs | 2 +- src/lib.rs | 2 +- src/stream.rs | 28 ++++++++++++++-------------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index 40a7f68..73e0ffa 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -30,8 +30,8 @@ impl TlsAcceptor { } /// Creates a new `TlsAcceptor` from a `ServerConfig` and an `AddrIncoming`. - pub fn new(config: Arc, incoming: AddrIncoming) -> TlsAcceptor { - TlsAcceptor { config, incoming } + pub fn new(config: Arc, incoming: AddrIncoming) -> Self { + Self { config, incoming } } } @@ -57,8 +57,8 @@ where C: Into>, I: Into, { - fn from((config, incoming): (C, I)) -> TlsAcceptor { - TlsAcceptor::new(config.into(), incoming.into()) + fn from((config, incoming): (C, I)) -> Self { + Self::new(config.into(), incoming.into()) } } @@ -70,9 +70,9 @@ pub struct TlsStream { } impl TlsStream { - fn new(stream: AddrStream, config: Arc) -> TlsStream { + fn new(stream: AddrStream, config: Arc) -> Self { let accept = tokio_rustls::TlsAcceptor::from(config).accept(stream); - TlsStream { + Self { state: State::Handshaking(accept), } } diff --git a/src/connector.rs b/src/connector.rs index f5e1b73..1e3cc4e 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -45,7 +45,7 @@ where C: Into>, { fn from((http, cfg): (H, C)) -> Self { - HttpsConnector { + Self { force_https: false, http, tls_config: cfg.into(), diff --git a/src/lib.rs b/src/lib.rs index cd34b37..bc26b76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ //! # fn main() {} //! ``` -#![warn(missing_docs, unreachable_pub)] +#![warn(missing_docs, unreachable_pub, clippy::use_self)] #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "acceptor")] diff --git a/src/stream.rs b/src/stream.rs index 64ddc48..a0e8c68 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -21,8 +21,8 @@ pub enum MaybeHttpsStream { impl Connection for MaybeHttpsStream { fn connected(&self) -> Connected { match self { - MaybeHttpsStream::Http(s) => s.connected(), - MaybeHttpsStream::Https(s) => { + Self::Http(s) => s.connected(), + Self::Https(s) => { let (tcp, tls) = s.get_ref(); if tls.alpn_protocol() == Some(b"h2") { tcp.connected().negotiated_h2() @@ -37,21 +37,21 @@ impl Connection for MaybeHttpsSt impl fmt::Debug for MaybeHttpsStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - MaybeHttpsStream::Http(..) => f.pad("Http(..)"), - MaybeHttpsStream::Https(..) => f.pad("Https(..)"), + Self::Http(..) => f.pad("Http(..)"), + Self::Https(..) => f.pad("Https(..)"), } } } impl From for MaybeHttpsStream { fn from(inner: T) -> Self { - MaybeHttpsStream::Http(inner) + Self::Http(inner) } } impl From> for MaybeHttpsStream { fn from(inner: TlsStream) -> Self { - MaybeHttpsStream::Https(inner) + Self::Https(inner) } } @@ -63,8 +63,8 @@ impl AsyncRead for MaybeHttpsStream { buf: &mut ReadBuf<'_>, ) -> Poll> { match Pin::get_mut(self) { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_read(cx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_read(cx, buf), + Self::Http(s) => Pin::new(s).poll_read(cx, buf), + Self::Https(s) => Pin::new(s).poll_read(cx, buf), } } } @@ -77,24 +77,24 @@ impl AsyncWrite for MaybeHttpsStream { buf: &[u8], ) -> Poll> { match Pin::get_mut(self) { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_write(cx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_write(cx, buf), + Self::Http(s) => Pin::new(s).poll_write(cx, buf), + Self::Https(s) => Pin::new(s).poll_write(cx, buf), } } #[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match Pin::get_mut(self) { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_flush(cx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_flush(cx), + Self::Http(s) => Pin::new(s).poll_flush(cx), + Self::Https(s) => Pin::new(s).poll_flush(cx), } } #[inline] fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match Pin::get_mut(self) { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_shutdown(cx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_shutdown(cx), + Self::Http(s) => Pin::new(s).poll_shutdown(cx), + Self::Https(s) => Pin::new(s).poll_shutdown(cx), } } } From 304faeb38e06dbd6baa25cbc0b9d5e1beea60d36 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:51:11 +0200 Subject: [PATCH 06/13] Address clippy issues in tests --- tests/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index 72dd114..e9cb839 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -24,7 +24,7 @@ fn client_command() -> Command { fn wait_for_server(addr: &str) { for i in 0..10 { - if let Ok(_) = TcpStream::connect(addr) { + if TcpStream::connect(addr).is_ok() { return; } thread::sleep(time::Duration::from_millis(i * 100)); @@ -72,7 +72,7 @@ fn server() { println!("curl stderr:\n{}", String::from_utf8_lossy(&output.stderr)); } - assert_eq!(String::from_utf8_lossy(&*output.stdout), "Try POST /echo\n"); + assert_eq!(String::from_utf8_lossy(&output.stdout), "Try POST /echo\n"); } #[test] From aee0c0cc49866a93a7b1e9a12437f24228e4c7de Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:52:44 +0200 Subject: [PATCH 07/13] acceptor: make the acceptor module public --- src/acceptor.rs | 1 + src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index 73e0ffa..e4f7ac2 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -62,6 +62,7 @@ where } } +/// A TLS stream constructed by a [`TlsAcceptor`]. // tokio_rustls::server::TlsStream doesn't expose constructor methods, // so we have to TlsAcceptor::accept and handshake to have access to it // TlsStream implements AsyncRead/AsyncWrite by handshaking with tokio_rustls::Accept first diff --git a/src/lib.rs b/src/lib.rs index bc26b76..308f71e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,8 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "acceptor")] -mod acceptor; +/// TLS acceptor implementing hyper's `Accept` trait. +pub mod acceptor; mod config; mod connector; mod stream; From d4e934dd11b927ee80a1070937288d99b574cc30 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:56:57 +0200 Subject: [PATCH 08/13] acceptor: linearize AsyncRead and AsyncWrite implementations --- src/acceptor.rs | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index e4f7ac2..fc6594c 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -86,17 +86,19 @@ impl AsyncRead for TlsStream { buf: &mut ReadBuf, ) -> Poll> { let pin = self.get_mut(); - match pin.state { - State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) { - Ok(mut stream) => { - let result = Pin::new(&mut stream).poll_read(cx, buf); - pin.state = State::Streaming(stream); - result - } - Err(err) => Poll::Ready(Err(err)), - }, - State::Streaming(ref mut stream) => Pin::new(stream).poll_read(cx, buf), - } + let accept = match &mut pin.state { + State::Handshaking(accept) => accept, + State::Streaming(stream) => return Pin::new(stream).poll_read(cx, buf), + }; + + let mut stream = match ready!(Pin::new(accept).poll(cx)) { + Ok(stream) => stream, + Err(err) => return Poll::Ready(Err(err)), + }; + + let result = Pin::new(&mut stream).poll_read(cx, buf); + pin.state = State::Streaming(stream); + result } } @@ -107,17 +109,19 @@ impl AsyncWrite for TlsStream { buf: &[u8], ) -> Poll> { let pin = self.get_mut(); - match pin.state { - State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) { - Ok(mut stream) => { - let result = Pin::new(&mut stream).poll_write(cx, buf); - pin.state = State::Streaming(stream); - result - } - Err(err) => Poll::Ready(Err(err)), - }, - State::Streaming(ref mut stream) => Pin::new(stream).poll_write(cx, buf), - } + let accept = match &mut pin.state { + State::Handshaking(accept) => accept, + State::Streaming(stream) => return Pin::new(stream).poll_write(cx, buf), + }; + + let mut stream = match ready!(Pin::new(accept).poll(cx)) { + Ok(stream) => stream, + Err(err) => return Poll::Ready(Err(err)), + }; + + let result = Pin::new(&mut stream).poll_write(cx, buf); + pin.state = State::Streaming(stream); + result } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { From 9f1d992c17b03d0a9469a6ef7495540b46ab94bd Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 09:57:43 +0200 Subject: [PATCH 09/13] acceptor: replace ref mut patterns with &mut scrutinee --- src/acceptor.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index fc6594c..db420b5 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -125,16 +125,16 @@ impl AsyncWrite for TlsStream { } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.state { + match &mut self.state { State::Handshaking(_) => Poll::Ready(Ok(())), - State::Streaming(ref mut stream) => Pin::new(stream).poll_flush(cx), + State::Streaming(stream) => Pin::new(stream).poll_flush(cx), } } fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.state { + match &mut self.state { State::Handshaking(_) => Poll::Ready(Ok(())), - State::Streaming(ref mut stream) => Pin::new(stream).poll_shutdown(cx), + State::Streaming(stream) => Pin::new(stream).poll_shutdown(cx), } } } From da60499b00b57fa47475c8114983883273b32d26 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 10:57:48 +0200 Subject: [PATCH 10/13] acceptor: add accessor methods on TlsStream --- src/acceptor.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index db420b5..4cf816d 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -9,7 +9,7 @@ use hyper::server::{ accept::Accept, conn::{AddrIncoming, AddrStream}, }; -use rustls::ServerConfig; +use rustls::{ServerConfig, ServerConnection}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; mod builder; @@ -77,6 +77,26 @@ impl TlsStream { state: State::Handshaking(accept), } } + + /// Returns a reference to the underlying IO stream. + /// + /// This should always return `Some`, except if an error has already been yielded. + pub fn io(&self) -> Option<&AddrStream> { + match &self.state { + State::Handshaking(accept) => accept.get_ref(), + State::Streaming(stream) => Some(stream.get_ref().0), + } + } + + /// Returns a reference to the underlying [`rustls::ServerConnection']. + /// + /// This will start yielding `Some` only after the handshake has completed. + pub fn connection(&self) -> Option<&ServerConnection> { + match &self.state { + State::Handshaking(_) => None, + State::Streaming(stream) => Some(stream.get_ref().1), + } + } } impl AsyncRead for TlsStream { From 67e558ea3baa651b46cf82c9763b2bb3bd3783ff Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 11:00:20 +0200 Subject: [PATCH 11/13] Avoid deprecated rustls API --- Cargo.toml | 2 +- src/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6daff84..0bbf65d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ http = "0.2" hyper = { version = "0.14", default-features = false, features = ["client"] } log = { version = "0.4.4", optional = true } rustls-native-certs = { version = "0.6", optional = true } -rustls = { version = "0.21.0", default-features = false } +rustls = { version = "0.21.6", default-features = false } tokio = "1.0" tokio-rustls = { version = "0.24.0", default-features = false } webpki-roots = { version = "0.25", optional = true } diff --git a/src/config.rs b/src/config.rs index c4b4624..256856c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -54,7 +54,7 @@ impl ConfigBuilderExt for ConfigBuilder { #[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))] fn with_webpki_roots(self) -> ConfigBuilder { let mut roots = rustls::RootCertStore::empty(); - roots.add_server_trust_anchors( + roots.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { From 7617ff32b3c4e19b2a5fc71f6e51cfc59d909578 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 11:17:30 +0200 Subject: [PATCH 12/13] Run CI on a weekly schedule Probably don't need daily runs given the amount of changes. Run on Friday mornings so we can catch clippy changes from Rust releases that happen on Thursday relatively soon after. Also include merge group support. --- .github/workflows/build.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74852c0..2bca97f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,12 @@ name: rustls permissions: contents: read -on: [push, pull_request] +on: + push: + pull_request: + merge_group: + schedule: + - cron: '23 6 * * 5' jobs: build: From 10f3069649ba9f96581aea2be14623420fe924ab Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Aug 2023 11:19:29 +0200 Subject: [PATCH 13/13] Bump MSRV to 1.63 for socket2 0.5.3 --- .github/workflows/build.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bca97f..0e7f979 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: - name: Install rust toolchain uses: dtolnay/rust-toolchain@master with: - toolchain: "1.60" + toolchain: "1.63" - name: Check MSRV run: cargo check --lib --all-features diff --git a/Cargo.toml b/Cargo.toml index 0bbf65d..d8d9240 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "hyper-rustls" version = "0.24.1" edition = "2021" -rust-version = "1.60" +rust-version = "1.63" license = "Apache-2.0 OR ISC OR MIT" readme = "README.md" description = "Rustls+hyper integration for pure rust HTTPS"