1
- //! Simple HTTPS echo service based on hyper- rustls
1
+ //! Simple HTTPS echo service based on hyper_util and rustls
2
2
//!
3
3
//! First parameter is the mandatory port to use.
4
4
//! Certificate and private key are hardcoded to sample files.
5
5
//! hyper will automatically use HTTP/2 if a client starts talking HTTP/2,
6
6
//! otherwise HTTP/1.1 will be used.
7
7
8
- #! [ cfg ( feature = "acceptor" ) ]
9
-
8
+ use std :: net :: { Ipv4Addr , SocketAddr } ;
9
+ use std :: sync :: Arc ;
10
10
use std:: vec:: Vec ;
11
11
use std:: { env, fs, io} ;
12
12
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 ;
17
19
use pki_types:: { CertificateDer , PrivateKeyDer } ;
20
+ use rustls:: ServerConfig ;
21
+ use tokio:: net:: TcpListener ;
22
+ use tokio_rustls:: TlsAcceptor ;
18
23
19
24
fn main ( ) {
20
25
// Serve an echo service over HTTPS, with proper error handling.
@@ -32,45 +37,70 @@ fn error(err: String) -> io::Error {
32
37
async fn run_server ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
33
38
// First parameter is port number (optional, defaults to 1337)
34
39
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 ,
37
42
} ;
38
- let addr = format ! ( "127.0.0.1:{}" , port) . parse ( ) ? ;
43
+ let addr = SocketAddr :: new ( Ipv4Addr :: LOCALHOST . into ( ) , port) ;
39
44
40
45
// Load public certificate.
41
46
let certs = load_certs ( "examples/sample.pem" ) ?;
42
47
// Load private key.
43
48
let key = load_private_key ( "examples/sample.rsa" ) ?;
44
- // Build TLS configuration.
49
+
50
+ println ! ( "Starting to serve on https://{}" , addr) ;
45
51
46
52
// 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 ( )
49
58
. 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
+ }
60
85
}
61
86
62
87
// Custom echo service, handling two different routes and a
63
88
// 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 ( ) ) ;
66
91
match ( req. method ( ) , req. uri ( ) . path ( ) ) {
67
92
// Help route.
68
93
( & Method :: GET , "/" ) => {
69
- * response. body_mut ( ) = Body :: from ( "Try POST /echo\n " ) ;
94
+ * response. body_mut ( ) = Full :: from ( "Try POST /echo\n " ) ;
70
95
}
71
96
// Echo service route.
72
97
( & 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
+ ) ;
74
104
}
75
105
// Catch-all 404.
76
106
_ => {
0 commit comments