1- //! Simple HTTPS echo service based on hyper- rustls
1+ //! Simple HTTPS echo service based on hyper_util and rustls
22//!
33//! First parameter is the mandatory port to use.
44//! Certificate and private key are hardcoded to sample files.
55//! hyper will automatically use HTTP/2 if a client starts talking HTTP/2,
66//! otherwise HTTP/1.1 will be used.
77
8- #! [ cfg ( feature = "acceptor" ) ]
9-
8+ use std :: net :: { Ipv4Addr , SocketAddr } ;
9+ use std :: sync :: Arc ;
1010use std:: vec:: Vec ;
1111use std:: { env, fs, io} ;
1212
13- use hyper:: server:: conn:: AddrIncoming ;
14- use hyper:: service:: { make_service_fn, service_fn} ;
15- use hyper:: { Body , Method , Request , Response , Server , StatusCode } ;
16- use hyper_rustls:: TlsAcceptor ;
13+ use http:: { Method , Request , Response , StatusCode } ;
14+ use http_body_util:: { BodyExt , Full } ;
15+ use hyper:: body:: { Bytes , Incoming } ;
16+ use hyper:: service:: service_fn;
17+ use hyper_util:: rt:: { TokioExecutor , TokioIo } ;
18+ use hyper_util:: server:: conn:: auto:: Builder ;
1719use pki_types:: { CertificateDer , PrivateKeyDer } ;
20+ use rustls:: ServerConfig ;
21+ use tokio:: net:: TcpListener ;
22+ use tokio_rustls:: TlsAcceptor ;
1823
1924fn main ( ) {
2025 // Serve an echo service over HTTPS, with proper error handling.
@@ -32,45 +37,70 @@ fn error(err: String) -> io::Error {
3237async fn run_server ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
3338 // First parameter is port number (optional, defaults to 1337)
3439 let port = match env:: args ( ) . nth ( 1 ) {
35- Some ( ref p) => p. to_owned ( ) ,
36- None => " 1337" . to_owned ( ) ,
40+ Some ( ref p) => p. parse ( ) ? ,
41+ None => 1337 ,
3742 } ;
38- let addr = format ! ( "127.0.0.1:{}" , port) . parse ( ) ? ;
43+ let addr = SocketAddr :: new ( Ipv4Addr :: LOCALHOST . into ( ) , port) ;
3944
4045 // Load public certificate.
4146 let certs = load_certs ( "examples/sample.pem" ) ?;
4247 // Load private key.
4348 let key = load_private_key ( "examples/sample.rsa" ) ?;
44- // Build TLS configuration.
49+
50+ println ! ( "Starting to serve on https://{}" , addr) ;
4551
4652 // Create a TCP listener via tokio.
47- let incoming = AddrIncoming :: bind ( & addr) ?;
48- let acceptor = TlsAcceptor :: builder ( )
53+ let incoming = TcpListener :: bind ( & addr) . await ?;
54+
55+ // Build TLS configuration.
56+ let mut server_config = ServerConfig :: builder ( )
57+ . with_no_client_auth ( )
4958 . with_single_cert ( certs, key)
50- . map_err ( |e| error ( format ! ( "{}" , e) ) ) ?
51- . with_all_versions_alpn ( )
52- . with_incoming ( incoming) ;
53- let service = make_service_fn ( |_| async { Ok :: < _ , io:: Error > ( service_fn ( echo) ) } ) ;
54- let server = Server :: builder ( acceptor) . serve ( service) ;
55-
56- // Run the future, keep going until an error occurs.
57- println ! ( "Starting to serve on https://{}." , addr) ;
58- server. await ?;
59- Ok ( ( ) )
59+ . map_err ( |e| error ( e. to_string ( ) ) ) ?;
60+ server_config. alpn_protocols = vec ! [ b"h2" . to_vec( ) , b"http/1.1" . to_vec( ) , b"http/1.0" . to_vec( ) ] ;
61+ let tls_acceptor = TlsAcceptor :: from ( Arc :: new ( server_config) ) ;
62+
63+ let service = service_fn ( echo) ;
64+
65+ loop {
66+ let ( tcp_stream, _remote_addr) = incoming. accept ( ) . await ?;
67+
68+ let tls_acceptor = tls_acceptor. clone ( ) ;
69+ tokio:: spawn ( async move {
70+ let tls_stream = match tls_acceptor. accept ( tcp_stream) . await {
71+ Ok ( tls_stream) => tls_stream,
72+ Err ( err) => {
73+ eprintln ! ( "failed to perform tls handshake: {err:#}" ) ;
74+ return ;
75+ }
76+ } ;
77+ if let Err ( err) = Builder :: new ( TokioExecutor :: new ( ) )
78+ . serve_connection ( TokioIo :: new ( tls_stream) , service)
79+ . await
80+ {
81+ eprintln ! ( "failed to serve connection: {err:#}" ) ;
82+ }
83+ } ) ;
84+ }
6085}
6186
6287// Custom echo service, handling two different routes and a
6388// catch-all 404 responder.
64- async fn echo ( req : Request < Body > ) -> Result < Response < Body > , hyper:: Error > {
65- let mut response = Response :: new ( Body :: empty ( ) ) ;
89+ async fn echo ( req : Request < Incoming > ) -> Result < Response < Full < Bytes > > , hyper:: Error > {
90+ let mut response = Response :: new ( Full :: default ( ) ) ;
6691 match ( req. method ( ) , req. uri ( ) . path ( ) ) {
6792 // Help route.
6893 ( & Method :: GET , "/" ) => {
69- * response. body_mut ( ) = Body :: from ( "Try POST /echo\n " ) ;
94+ * response. body_mut ( ) = Full :: from ( "Try POST /echo\n " ) ;
7095 }
7196 // Echo service route.
7297 ( & Method :: POST , "/echo" ) => {
73- * response. body_mut ( ) = req. into_body ( ) ;
98+ * response. body_mut ( ) = Full :: from (
99+ req. into_body ( )
100+ . collect ( )
101+ . await ?
102+ . to_bytes ( ) ,
103+ ) ;
74104 }
75105 // Catch-all 404.
76106 _ => {
0 commit comments