I have implemented a reverse proxy with hyper-rustls and tokio. It works as intended when I use it against a non-https site, but when it hits a https host I get this from curl:
curl: (52) Empty reply from server
Structs
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Hive {
path: String,
hive: Option<String>,
host: Option<String>,
route: Option<String>,
java: Option<bool>,
}
impl Hive {
fn new() -> Hive {
Hive {
path: String::from(""),
hive: Option::from(String::from("")),
host: Option::from(String::from("")),
route: Option::from(String::from("")),
java: Option::from(false)
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Hives {
local_hives: Vec<Hive>,
remote_hives: Vec<Hive>,
critical_hives: Vec<Hive>,
}
impl Hives {
fn new() -> Hives {
Hives {
local_hives: Vec::new(),
remote_hives: Vec::new(),
critical_hives: Vec::new()
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct ServerObject {
https: Option<bool>,
name: String,
host: String,
port: String,
hives: Hives,
}
impl ServerObject {
fn new() -> ServerObject {
ServerObject {
hives: Hives::new(),
https: Option::from(false),
name: String::from(""),
host: String::from(""),
port: String::from("")
}
}
}
#[derive(Serialize, Deserialize)]
struct List {
servers: Vec<ServerObject>,
}
the code is pretty simple, but for some reason it does not work...
// current_server is a json with config about routes and host url
let connector = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_or_http()
.enable_http1()
.build();
let client: Client<_, hyper::Body> = Client::builder().build(connector);
let client: Arc<Client<_, hyper::Body>> = Arc::new(client);
let make_service = make_service_fn(move |_| {
let current_server = current_server.clone();
let client = Arc::clone(&client);
async move {
let client = Arc::clone(&client);
Ok::<_, Infallible>(
service_fn(move |req| {
let client = Arc::clone(&client);
handle(req, current_server.clone(), client)
})
)
}
});
handle is a bit more complicated.. but in essense this is the part that does the reverse proxy
async fn handle(
mut req: Request<Body>,
server: Arc<ServerObject>,
client: Arc<hyper::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>>
) -> Result<hyper::Response<hyper::Body>, Infallible> {
let headers = req.headers_mut();
headers.insert("cache-control", HeaderValue::from_static("no-store"));
headers.insert("service-worker-allowed", HeaderValue::from_static("/"));
let uri = req.uri();
let uri_str = match uri.query() {
None => format!("{}{}", server.host, uri.path()),
Some(query) => format!("{}{}?{}", server.host, uri.path(), query),
};
*req.uri_mut() = uri_str.parse().unwrap();
match client.request(req).await {
Ok(response) => {
Ok(response)
},
Err(err) =>{
println!("Error {}", err);
Ok(hyper::Response::builder()
.status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())
}
}
}
Here is the request headers from the call:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: da,en;q=0.9,en-GB;q=0.8,en-US;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Cookie: sys_sesid="2022-02-12-11.58.41.684888"
Host: localhost:4001
Pragma: no-cache
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Microsoft Edge";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43
Why does this happen and how can I fix it?