Skip to content

Commit

Permalink
add insecure http option
Browse files Browse the repository at this point in the history
  • Loading branch information
goatgoose committed Dec 12, 2024
1 parent 36d34da commit 30a9202
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 17 deletions.
38 changes: 30 additions & 8 deletions bindings/rust/s2n-tls-hyper/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use tower_service::Service;
pub struct HttpsConnector<Http, ConnBuilder = Config> {
http: Http,
conn_builder: ConnBuilder,
insecure_http: bool,
}

impl<ConnBuilder> HttpsConnector<HttpConnector, ConnBuilder>
Expand Down Expand Up @@ -101,7 +102,11 @@ where
http: HttpConnector,
conn_builder: ConnBuilder,
) -> Builder<HttpConnector, ConnBuilder> {
Builder { http, conn_builder }
Builder {
http,
conn_builder,
insecure_http: false,
}
}
}

Expand All @@ -110,14 +115,22 @@ where
pub struct Builder<Http, ConnBuilder> {
http: Http,
conn_builder: ConnBuilder,
insecure_http: bool,
}

impl<Http, ConnBuilder> Builder<Http, ConnBuilder> {
/// Allows communication with insecure HTTP endpoints in addition to secure HTTPS endpoints.
pub fn with_insecure_http(&mut self) -> &mut Self {
self.insecure_http = true;
self
}

/// Builds a new `HttpsConnector`.
pub fn build(self) -> HttpsConnector<Http, ConnBuilder> {
HttpsConnector {
http: self.http,
conn_builder: self.conn_builder,
insecure_http: self.insecure_http,
}
}
}
Expand Down Expand Up @@ -155,10 +168,18 @@ where
}

fn call(&mut self, req: Uri) -> Self::Future {
// Currently, the only supported stream type is TLS. If the application attempts to
// negotiate HTTP over plain TCP, return an error.
if req.scheme() == Some(&http::uri::Scheme::HTTP) {
return Box::pin(async move { Err(Error::InvalidScheme) });
match req.scheme() {
Some(scheme) if scheme == &http::uri::Scheme::HTTPS => (),
Some(scheme) if scheme == &http::uri::Scheme::HTTP && self.insecure_http => {
let call = self.http.call(req);
return Box::pin(async move {
let tcp = call.await.map_err(|e| Error::HttpError(e.into()))?;
Ok(MaybeHttpsStream::Http(tcp))
});
}
_ => {
return Box::pin(async move { Err(Error::InvalidScheme) });
}
}

// Attempt to negotiate HTTP/2 by including it in the ALPN extension. Other supported HTTP
Expand Down Expand Up @@ -235,15 +256,16 @@ mod tests {
}

#[tokio::test]
async fn test_unsecure_http() -> Result<(), Box<dyn StdError>> {
async fn test_invalid_scheme() -> Result<(), Box<dyn StdError>> {
let connector = HttpsConnector::new(Config::default());
let client: Client<_, Empty<Bytes>> =
Client::builder(TokioExecutor::new()).build(connector);

let uri = Uri::from_str("http://www.amazon.com")?;
// Attempt to make a request with an arbitrary invalid scheme.
let uri = Uri::from_str("notascheme://www.amazon.com")?;
let error = client.get(uri).await.unwrap_err();

// Ensure that an InvalidScheme error is returned when HTTP over TCP is attempted.
// Ensure that an InvalidScheme error is returned.
let error = error.source().unwrap().downcast_ref::<Error>().unwrap();
assert!(matches!(error, Error::InvalidScheme));

Expand Down
41 changes: 32 additions & 9 deletions bindings/rust/s2n-tls-hyper/tests/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use s2n_tls::{
security::DEFAULT_TLS13,
};
use s2n_tls_hyper::connector::HttpsConnector;
use s2n_tls_hyper::error;
use std::{error::Error, pin::Pin, str::FromStr};
use tokio::{
net::TcpListener,
Expand Down Expand Up @@ -356,16 +357,38 @@ async fn insecure_http() -> Result<(), Box<dyn Error + Send + Sync>> {

tasks.spawn(async move {
for enable_insecure_http in [false, true] {
let mut builder = HttpsConnector::builder();
}

let connector = HttpsConnector::new(common::config()?.build()?);
let client: Client<_, Empty<Bytes>> =
Client::builder(TokioExecutor::new()).build(connector);
let connector = {
let config = common::config()?.build()?;
let mut builder = HttpsConnector::builder(config);
if enable_insecure_http {
builder.with_insecure_http();
}
builder.build()
};

let uri = Uri::from_str(format!("http://127.0.0.1:{}", addr.port()).as_str())?;
let response = client.get(uri).await?;
assert_eq!(response.status(), 200);
let client: Client<_, Empty<Bytes>> =
Client::builder(TokioExecutor::new()).build(connector);
let uri = Uri::from_str(format!("http://127.0.0.1:{}", addr.port()).as_str())?;
let response = client.get(uri).await;

if enable_insecure_http {
// If insecure HTTP is enabled, the request should succeed.
let response = response.unwrap();
assert_eq!(response.status(), 200);
} else {
// By default, insecure HTTP is disabled, and the request should error.
let error = response.unwrap_err();

// Ensure an InvalidScheme error is produced.
let error = error
.source()
.unwrap()
.downcast_ref::<error::Error>()
.unwrap();
assert!(matches!(error, error::Error::InvalidScheme));
assert!(!error.to_string().is_empty());
}
}

Ok(())
});
Expand Down

0 comments on commit 30a9202

Please sign in to comment.