1 //! Simple HTTPS echo service based on hyper-rustls
2 //!
3 //! First parameter is the mandatory port to use.
4 //! Certificate and private key are hardcoded to sample files.
5 //! hyper will automatically use HTTP/2 if a client starts talking HTTP/2,
6 //! otherwise HTTP/1.1 will be used.
7 use async_stream::stream;
8 use core::task::{Context, Poll};
9 use futures_util::{future::TryFutureExt, stream::Stream};
10 use hyper::service::{make_service_fn, service_fn};
11 use hyper::{Body, Method, Request, Response, Server, StatusCode};
12 use rustls::internal::pemfile;
13 use std::pin::Pin;
14 use std::vec::Vec;
15 use std::{env, fs, io, sync};
16 use tokio::net::{TcpListener, TcpStream};
17 use tokio_rustls::server::TlsStream;
18 use tokio_rustls::TlsAcceptor;
19 
main()20 fn main() {
21     // Serve an echo service over HTTPS, with proper error handling.
22     if let Err(e) = run_server() {
23         eprintln!("FAILED: {}", e);
24         std::process::exit(1);
25     }
26 }
27 
error(err: String) -> io::Error28 fn error(err: String) -> io::Error {
29     io::Error::new(io::ErrorKind::Other, err)
30 }
31 
32 #[tokio::main]
run_server() -> Result<(), Box<dyn std::error::Error + Send + Sync>>33 async fn run_server() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
34     // First parameter is port number (optional, defaults to 1337)
35     let port = match env::args().nth(1) {
36         Some(ref p) => p.to_owned(),
37         None => "1337".to_owned(),
38     };
39     let addr = format!("127.0.0.1:{}", port);
40 
41     // Build TLS configuration.
42     let tls_cfg = {
43         // Load public certificate.
44         let certs = load_certs("examples/sample.pem")?;
45         // Load private key.
46         let key = load_private_key("examples/sample.rsa")?;
47         // Do not use client certificate authentication.
48         let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new());
49         // Select a certificate to use.
50         cfg.set_single_cert(certs, key)
51             .map_err(|e| error(format!("{}", e)))?;
52         // Configure ALPN to accept HTTP/2, HTTP/1.1 in that order.
53         cfg.set_protocols(&[b"h2".to_vec(), b"http/1.1".to_vec()]);
54         sync::Arc::new(cfg)
55     };
56 
57     // Create a TCP listener via tokio.
58     let tcp = TcpListener::bind(&addr).await?;
59     let tls_acceptor = TlsAcceptor::from(tls_cfg);
60     // Prepare a long-running future stream to accept and serve clients.
61     let incoming_tls_stream = stream! {
62         loop {
63             let (socket, _) = tcp.accept().await?;
64             let stream = tls_acceptor.accept(socket).map_err(|e| {
65                 println!("[!] Voluntary server halt due to client-connection error...");
66                 // Errors could be handled here, instead of server aborting.
67                 // Ok(None)
68                 error(format!("TLS Error: {:?}", e))
69             });
70             yield stream.await;
71         }
72     };
73     let service = make_service_fn(|_| async { Ok::<_, io::Error>(service_fn(echo)) });
74     let server = Server::builder(HyperAcceptor {
75         acceptor: Box::pin(incoming_tls_stream),
76     })
77     .serve(service);
78 
79     // Run the future, keep going until an error occurs.
80     println!("Starting to serve on https://{}.", addr);
81     server.await?;
82     Ok(())
83 }
84 
85 struct HyperAcceptor<'a> {
86     acceptor: Pin<Box<dyn Stream<Item = Result<TlsStream<TcpStream>, io::Error>> + 'a>>,
87 }
88 
89 impl hyper::server::accept::Accept for HyperAcceptor<'_> {
90     type Conn = TlsStream<TcpStream>;
91     type Error = io::Error;
92 
poll_accept( mut self: Pin<&mut Self>, cx: &mut Context, ) -> Poll<Option<Result<Self::Conn, Self::Error>>>93     fn poll_accept(
94         mut self: Pin<&mut Self>,
95         cx: &mut Context,
96     ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
97         Pin::new(&mut self.acceptor).poll_next(cx)
98     }
99 }
100 
101 // Custom echo service, handling two different routes and a
102 // catch-all 404 responder.
echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error>103 async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
104     let mut response = Response::new(Body::empty());
105     match (req.method(), req.uri().path()) {
106         // Help route.
107         (&Method::GET, "/") => {
108             *response.body_mut() = Body::from("Try POST /echo\n");
109         }
110         // Echo service route.
111         (&Method::POST, "/echo") => {
112             *response.body_mut() = req.into_body();
113         }
114         // Catch-all 404.
115         _ => {
116             *response.status_mut() = StatusCode::NOT_FOUND;
117         }
118     };
119     Ok(response)
120 }
121 
122 // Load public certificate from file.
load_certs(filename: &str) -> io::Result<Vec<rustls::Certificate>>123 fn load_certs(filename: &str) -> io::Result<Vec<rustls::Certificate>> {
124     // Open certificate file.
125     let certfile = fs::File::open(filename)
126         .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
127     let mut reader = io::BufReader::new(certfile);
128 
129     // Load and return certificate.
130     pemfile::certs(&mut reader).map_err(|_| error("failed to load certificate".into()))
131 }
132 
133 // Load private key from file.
load_private_key(filename: &str) -> io::Result<rustls::PrivateKey>134 fn load_private_key(filename: &str) -> io::Result<rustls::PrivateKey> {
135     // Open keyfile.
136     let keyfile = fs::File::open(filename)
137         .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
138     let mut reader = io::BufReader::new(keyfile);
139 
140     // Load and return a single private key.
141     let keys = pemfile::rsa_private_keys(&mut reader)
142         .map_err(|_| error("failed to load private key".into()))?;
143     if keys.len() != 1 {
144         return Err(error("expected a single private key".into()));
145     }
146     Ok(keys[0].clone())
147 }
148