]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/h2s-server.rs
src/bin/h2s-server.rs: test to reproduce slow h2 download
[proxmox-backup.git] / src / bin / h2s-server.rs
CommitLineData
5ed2277f
DM
1use failure::*;
2use futures::*;
3use std::path::Path;
4
5// Simple H2 server to test H2 speed with h2s-client.rs
6
7use hyper::{Request, Response, Body};
8use tokio::net::TcpListener;
9
10use proxmox_backup::client::pipe_to_stream::*;
11use proxmox_backup::tools;
12use proxmox_backup::configdir;
13
14pub fn main() -> Result<(), Error> {
15
16 start_h2_server()?;
17
18 Ok(())
19}
20
21fn load_certificate<T: AsRef<Path>, U: AsRef<Path>>(
22 key: T,
23 cert: U,
24) -> Result<openssl::pkcs12::Pkcs12, Error> {
25 let key = tools::file_get_contents(key)?;
26 let cert = tools::file_get_contents(cert)?;
27
28 let key = openssl::pkey::PKey::private_key_from_pem(&key)?;
29 let cert = openssl::x509::X509::from_pem(&cert)?;
30
31 Ok(openssl::pkcs12::Pkcs12::builder()
32 .build("", "", &key, &cert)?)
33}
34
35pub fn start_h2_server() -> Result<(), Error> {
36
37 let cert_path = configdir!("/proxy.pfx");
38 let raw_cert = match std::fs::read(cert_path) {
39 Ok(pfx) => pfx,
40 Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => {
41 let pkcs12 = load_certificate(configdir!("/proxy.key"), configdir!("/proxy.pem"))?;
42 pkcs12.to_der()?
43 }
44 Err(err) => bail!("unable to read certificate file {} - {}", cert_path, err),
45 };
46
47 let identity = match native_tls::Identity::from_pkcs12(&raw_cert, "") {
48 Ok(data) => data,
49 Err(err) => bail!("unable to decode pkcs12 identity {} - {}", cert_path, err),
50 };
51
52 let acceptor = native_tls::TlsAcceptor::new(identity)?;
53 let acceptor = std::sync::Arc::new(tokio_tls::TlsAcceptor::from(acceptor));
54
55 let listener = TcpListener::bind(&"127.0.0.1:8008".parse().unwrap()).unwrap();
56
57 println!("listening on {:?}", listener.local_addr());
58
59 let server = listener
60 .incoming()
61 .map_err(Error::from)
62 .and_then(move |sock| acceptor.accept(sock).map_err(|e| e.into()))
63 .then(|r| match r {
64 // accept()s can fail here with an Err() when eg. the client rejects
65 // the cert and closes the connection, so we follow up with mapping
66 // it to an option and then filtering None with filter_map
67 Ok(c) => Ok::<_, Error>(Some(c)),
68 Err(e) => {
69 if let Some(_io) = e.downcast_ref::<std::io::Error>() {
70 // "real" IO errors should not simply be ignored
71 bail!("shutting down...");
72 } else {
73 // handshake errors just get filtered by filter_map() below:
74 Ok(None)
75 }
76 }
77 })
78 .filter_map(|r| {
79 // Filter out the Nones
80 r
81 })
82 .for_each(move |socket| {
83
84 let mut http = hyper::server::conn::Http::new();
85 http.http2_only(true);
86 // increase window size: todo - find optiomal size
87 let max_window_size = (1 << 31) - 2;
88 http.http2_initial_stream_window_size(max_window_size);
89 http.http2_initial_connection_window_size(max_window_size);
90
91 let service = hyper::service::service_fn(|req: Request<Body>| {
92 println!("Got request");
93 let buffer = vec![65u8; 1024*1024]; // nonsense [A,A,A,A...]
94 let body = Body::from(buffer);
95
96 let response = Response::builder()
97 .status(http::StatusCode::OK)
98 .header(http::header::CONTENT_TYPE, "application/octet-stream")
99 .body(body)
100 .unwrap();
101 Ok::<_, Error>(response)
102 });
103 http.serve_connection(socket, service)
104 .map_err(Error::from)
105 })
106 .and_then(|_| {
107 println!("H2 connection CLOSE !");
108 Ok(())
109 })
110 .then(|res| {
111 if let Err(e) = res {
112 println!(" -> err={:?}", e);
113 }
114 Ok(())
115 });
116
117 tokio::run(server);
118
119 Ok(())
120}