From ea050c7045764f69a6dd25a2b0c75186dddfc50e Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 24 Jan 2022 20:55:26 +0100 Subject: [PATCH] Actually that was quite a stupid way of handling timeouts --- src/https.rs | 37 +++++++++++-------------------------- src/reverse_proxy.rs | 18 ++++++++++++++---- src/tls_util.rs | 7 +++++-- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/https.rs b/src/https.rs index d621cfe..83eca7c 100644 --- a/src/https.rs +++ b/src/https.rs @@ -9,7 +9,7 @@ use log::*; use accept_encoding_fork::Encoding; use async_compression::tokio::bufread::*; use futures::stream::FuturesUnordered; -use futures::{Future, StreamExt, TryStreamExt}; +use futures::{StreamExt, TryStreamExt}; use http::header::{HeaderName, HeaderValue}; use http::method::Method; use hyper::server::conn::Http; @@ -25,7 +25,6 @@ use crate::cert_store::{CertStore, StoreResolver}; use crate::proxy_config::ProxyConfig; use crate::reverse_proxy; -const PROXY_TIMEOUT: Duration = Duration::from_secs(60); const MAX_CONNECTION_LIFETIME: Duration = Duration::from_secs(24 * 3600); pub struct HttpsConfig { @@ -189,11 +188,10 @@ async fn handle( let mut response = if proxy_to.https_target { let to_addr = format!("https://{}", proxy_to.target_addr); - handle_timeout_and_error(reverse_proxy::call_https(remote_addr.ip(), &to_addr, req)) - .await + handle_error(reverse_proxy::call_https(remote_addr.ip(), &to_addr, req).await) } else { let to_addr = format!("http://{}", proxy_to.target_addr); - handle_timeout_and_error(reverse_proxy::call(remote_addr.ip(), &to_addr, req)).await + handle_error(reverse_proxy::call(remote_addr.ip(), &to_addr, req).await) }; // Do further processing (compression, additionnal headers) only for 2xx responses @@ -225,27 +223,14 @@ async fn handle( } } -async fn handle_timeout_and_error( - fut: impl Future>>, -) -> Response { - select!( - resp = fut => { - match resp { - Ok(resp) => resp, - Err(e) => - Response::builder() - .status(StatusCode::BAD_GATEWAY) - .body(Body::from(format!("Proxy error: {}", e))) - .unwrap(), - } - } - _ = tokio::time::sleep(PROXY_TIMEOUT) => { - Response::builder() - .status(StatusCode::BAD_GATEWAY) - .body(Body::from("Proxy timeout")) - .unwrap() - } - ) +fn handle_error(resp: Result>) -> Response { + match resp { + Ok(resp) => resp, + Err(e) => Response::builder() + .status(StatusCode::BAD_GATEWAY) + .body(Body::from(format!("Proxy error: {}", e))) + .unwrap(), + } } async fn try_compress( diff --git a/src/reverse_proxy.rs b/src/reverse_proxy.rs index f4ded40..6ea15a0 100644 --- a/src/reverse_proxy.rs +++ b/src/reverse_proxy.rs @@ -5,19 +5,21 @@ use std::convert::TryInto; use std::net::IpAddr; use std::str::FromStr; use std::sync::Arc; -use std::time::SystemTime; +use std::time::{Duration, SystemTime}; use anyhow::Result; use log::*; use http::header::HeaderName; use hyper::header::{HeaderMap, HeaderValue}; -use hyper::{header, Body, Client, Request, Response, Uri}; +use hyper::{client::HttpConnector, header, Body, Client, Request, Response, Uri}; use rustls::client::{ServerCertVerified, ServerCertVerifier}; use rustls::{Certificate, ServerName}; use crate::tls_util::HttpsConnectorFixedDnsname; +pub const PROXY_TIMEOUT: Duration = Duration::from_secs(60); + const HOP_HEADERS: &[HeaderName] = &[ header::CONNECTION, //header::KEEP_ALIVE, @@ -128,7 +130,11 @@ pub async fn call( trace!("Proxied request: {:?}", proxied_request); - let client = Client::new(); + let mut connector = HttpConnector::new(); + connector.set_connect_timeout(Some(PROXY_TIMEOUT)); + + let client: Client<_, hyper::Body> = Client::builder().build(connector); + let response = client.request(proxied_request).await?; trace!("Inner response: {:?}", response); @@ -150,7 +156,11 @@ pub async fn call_https( .with_safe_defaults() .with_custom_certificate_verifier(Arc::new(DontVerifyServerCert)) .with_no_client_auth(); - let connector = HttpsConnectorFixedDnsname::new(tls_config, "dummy"); + + let mut http_connector = HttpConnector::new(); + http_connector.set_connect_timeout(Some(PROXY_TIMEOUT)); + let connector = HttpsConnectorFixedDnsname::new(tls_config, "dummy", http_connector); + let client: Client<_, hyper::Body> = Client::builder().build(connector); let response = client.request(proxied_request).await?; diff --git a/src/tls_util.rs b/src/tls_util.rs index 91ad31c..836f41e 100644 --- a/src/tls_util.rs +++ b/src/tls_util.rs @@ -23,8 +23,11 @@ pub struct HttpsConnectorFixedDnsname { } type BoxError = Box; impl HttpsConnectorFixedDnsname { - pub fn new(mut tls_config: rustls::ClientConfig, fixed_dnsname: &'static str) -> Self { - let mut http = HttpConnector::new(); + pub fn new( + mut tls_config: rustls::ClientConfig, + fixed_dnsname: &'static str, + mut http: HttpConnector, + ) -> Self { http.enforce_http(false); tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; Self {