Skip to content

Commit ac87344

Browse files
saleemrashiddjc
authored andcommitted
Fix https_only/enforce_https enforcement
1 parent 1b7d8cf commit ac87344

File tree

1 file changed

+102
-1
lines changed

1 file changed

+102
-1
lines changed

src/connector.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ where
6969
// dst.scheme() would need to derive Eq to be matchable;
7070
// use an if cascade instead
7171
match dst.scheme() {
72-
Some(scheme) if scheme == &http::uri::Scheme::HTTP => {
72+
Some(scheme) if scheme == &http::uri::Scheme::HTTP && !self.force_https => {
7373
let future = self.http.call(dst);
7474
return Box::pin(async move {
7575
Ok(MaybeHttpsStream::Http(future.await.map_err(Into::into)?))
@@ -199,3 +199,104 @@ pub trait ResolveServerName {
199199
uri: &Uri,
200200
) -> Result<ServerName<'static>, Box<dyn std::error::Error + Sync + Send>>;
201201
}
202+
203+
#[cfg(all(
204+
test,
205+
any(feature = "ring", feature = "aws-lc-rs"),
206+
any(
207+
feature = "rustls-native-certs",
208+
feature = "webpki-roots",
209+
feature = "rustls-platform-verifier",
210+
)
211+
))]
212+
mod tests {
213+
use std::future::poll_fn;
214+
215+
use http::Uri;
216+
use hyper_util::client::legacy::connect::HttpConnector;
217+
use tower_service::Service;
218+
219+
use super::HttpsConnector;
220+
use crate::{ConfigBuilderExt, HttpsConnectorBuilder};
221+
222+
fn tls_config() -> rustls::ClientConfig {
223+
#[cfg(feature = "rustls-native-certs")]
224+
return rustls::ClientConfig::builder()
225+
.with_native_roots()
226+
.unwrap()
227+
.with_no_client_auth();
228+
229+
#[cfg(feature = "webpki-roots")]
230+
return rustls::ClientConfig::builder()
231+
.with_webpki_roots()
232+
.with_no_client_auth();
233+
234+
#[cfg(feature = "rustls-platform-verifier")]
235+
return rustls::ClientConfig::builder()
236+
.with_platform_verifier()
237+
.with_no_client_auth();
238+
}
239+
240+
fn https_or_http_connector() -> HttpsConnector<HttpConnector> {
241+
HttpsConnectorBuilder::new()
242+
.with_tls_config(tls_config())
243+
.https_or_http()
244+
.enable_http1()
245+
.build()
246+
}
247+
248+
fn https_only_connector() -> HttpsConnector<HttpConnector> {
249+
HttpsConnectorBuilder::new()
250+
.with_tls_config(tls_config())
251+
.https_only()
252+
.enable_http1()
253+
.build()
254+
}
255+
256+
async fn oneshot<S, Req>(mut service: S, req: Req) -> Result<S::Response, S::Error>
257+
where
258+
S: Service<Req>,
259+
{
260+
poll_fn(|cx| service.poll_ready(cx)).await?;
261+
service.call(req).await
262+
}
263+
264+
fn https_uri() -> Uri {
265+
Uri::from_static("https://google.com")
266+
}
267+
268+
fn http_uri() -> Uri {
269+
Uri::from_static("http://google.com")
270+
}
271+
272+
#[tokio::test]
273+
async fn connects_https() {
274+
oneshot(https_or_http_connector(), https_uri())
275+
.await
276+
.unwrap();
277+
}
278+
279+
#[tokio::test]
280+
async fn connects_http() {
281+
oneshot(https_or_http_connector(), http_uri())
282+
.await
283+
.unwrap();
284+
}
285+
286+
#[tokio::test]
287+
async fn connects_https_only() {
288+
oneshot(https_only_connector(), https_uri())
289+
.await
290+
.unwrap();
291+
}
292+
293+
#[tokio::test]
294+
async fn enforces_https_only() {
295+
let message = oneshot(https_only_connector(), http_uri())
296+
.await
297+
.unwrap_err()
298+
.to_string();
299+
300+
assert_eq!(message, "unsupported scheme http");
301+
}
302+
}

0 commit comments

Comments
 (0)