1- use  std:: sync:: Arc ; 
2- use  std:: time:: SystemTime ; 
1+ use  std:: { path:: PathBuf ,  sync:: Arc } ; 
32
43use  futures:: future; 
5- use  h3_quinn:: quinn; 
6- use  rustls:: { self ,  client:: ServerCertVerified } ; 
7- use  rustls:: { Certificate ,  ServerName } ; 
84use  structopt:: StructOpt ; 
9- use  tokio:: { self ,  io:: AsyncWriteExt } ; 
5+ use  tokio:: io:: AsyncWriteExt ; 
6+ use  tracing:: { error,  info} ; 
107
11- use  h3_quinn:: { self ,   quinn:: crypto :: rustls :: Error } ; 
8+ use  h3_quinn:: quinn; 
129
1310static  ALPN :  & [ u8 ]  = b"h3" ; 
1411
1512#[ derive( StructOpt ,  Debug ) ]  
1613#[ structopt( name = "server" ) ]  
1714struct  Opt  { 
18-     #[ structopt( long) ]  
19-     pub  insecure :  bool , 
15+     #[ structopt(  
16+         long,  
17+         short,  
18+         default_value = "examples/ca.cert" ,  
19+         help = "Certificate of CA who issues the server certificate"  
20+     ) ]  
21+     pub  ca :  PathBuf , 
2022
2123    #[ structopt( name = "keylogfile" ,  long) ]  
2224    pub  key_log_file :  bool , 
@@ -31,76 +33,86 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3133        . with_env_filter ( tracing_subscriber:: EnvFilter :: from_default_env ( ) ) 
3234        . with_span_events ( tracing_subscriber:: fmt:: format:: FmtSpan :: FULL ) 
3335        . with_writer ( std:: io:: stderr) 
36+         . with_max_level ( tracing:: Level :: INFO ) 
3437        . init ( ) ; 
3538
3639    let  opt = Opt :: from_args ( ) ; 
3740
38-     let  dest = opt . uri . parse :: < http :: Uri > ( ) ? ; 
41+     // DNS lookup 
3942
40-     if  dest. scheme ( )  != Some ( & http:: uri:: Scheme :: HTTPS )  { 
41-         Err ( "destination scheme must be 'https'" ) ?; 
43+     let  uri = opt. uri . parse :: < http:: Uri > ( ) ?; 
44+ 
45+     if  uri. scheme ( )  != Some ( & http:: uri:: Scheme :: HTTPS )  { 
46+         Err ( "uri scheme must be 'https'" ) ?; 
4247    } 
4348
44-     let  auth = dest
45-         . authority ( ) 
46-         . ok_or ( "destination must have a host" ) ?
47-         . clone ( ) ; 
49+     let  auth = uri. authority ( ) . ok_or ( "uri must have a host" ) ?. clone ( ) ; 
4850
4951    let  port = auth. port_u16 ( ) . unwrap_or ( 443 ) ; 
5052
51-     // dns me! 
5253    let  addr = tokio:: net:: lookup_host ( ( auth. host ( ) ,  port) ) 
5354        . await ?
5455        . next ( ) 
5556        . ok_or ( "dns found no addresses" ) ?; 
5657
57-     eprintln ! ( "DNS Lookup  for {:?}: {:?}" ,  dest ,  addr) ; 
58+     info ! ( "DNS lookup  for {:?}: {:?}" ,  uri ,  addr) ; 
5859
59-     // quinn setup 
60-     let  tls_config_builder = rustls:: ClientConfig :: builder ( ) 
61-         . with_safe_default_cipher_suites ( ) 
62-         . with_safe_default_kx_groups ( ) 
63-         . with_protocol_versions ( & [ & rustls:: version:: TLS13 ] ) ?; 
64-     let  mut  tls_config = if  !opt. insecure  { 
65-         let  mut  roots = rustls:: RootCertStore :: empty ( ) ; 
66-         match  rustls_native_certs:: load_native_certs ( )  { 
67-             Ok ( certs)  => { 
68-                 for  cert in  certs { 
69-                     if  let  Err ( e)  = roots. add ( & rustls:: Certificate ( cert. 0 ) )  { 
70-                         eprintln ! ( "failed to parse trust anchor: {}" ,  e) ; 
71-                     } 
60+     // create quinn client endpoint 
61+ 
62+     // load CA certificates stored in the system 
63+     let  mut  roots = rustls:: RootCertStore :: empty ( ) ; 
64+     match  rustls_native_certs:: load_native_certs ( )  { 
65+         Ok ( certs)  => { 
66+             for  cert in  certs { 
67+                 if  let  Err ( e)  = roots. add ( & rustls:: Certificate ( cert. 0 ) )  { 
68+                     error ! ( "failed to parse trust anchor: {}" ,  e) ; 
7269                } 
7370            } 
74-             Err ( e)  => { 
75-                 eprintln ! ( "couldn't load any default trust roots: {}" ,  e) ; 
76-             } 
77-         } ; 
78-         tls_config_builder
79-             . with_root_certificates ( roots) 
80-             . with_no_client_auth ( ) 
81-     }  else  { 
82-         tls_config_builder
83-             . with_custom_certificate_verifier ( Arc :: new ( YesVerifier ) ) 
84-             . with_no_client_auth ( ) 
71+         } 
72+         Err ( e)  => { 
73+             error ! ( "couldn't load any default trust roots: {}" ,  e) ; 
74+         } 
8575    } ; 
76+ 
77+     // load certificate of CA who issues the server certificate 
78+     // NOTE that this should be used for dev only 
79+     if  let  Err ( e)  = roots. add ( & rustls:: Certificate ( std:: fs:: read ( opt. ca ) ?) )  { 
80+         error ! ( "failed to parse trust anchor: {}" ,  e) ; 
81+     } 
82+ 
83+     let  mut  tls_config = rustls:: ClientConfig :: builder ( ) 
84+         . with_safe_default_cipher_suites ( ) 
85+         . with_safe_default_kx_groups ( ) 
86+         . with_protocol_versions ( & [ & rustls:: version:: TLS13 ] ) ?
87+         . with_root_certificates ( roots) 
88+         . with_no_client_auth ( ) ; 
89+ 
8690    tls_config. enable_early_data  = true ; 
8791    tls_config. alpn_protocols  = vec ! [ ALPN . into( ) ] ; 
8892
93+     // optional debugging support 
8994    if  opt. key_log_file  { 
9095        // Write all Keys to a file if SSLKEYLOGFILE is set 
9196        // WARNING, we enable this for the example, you should think carefully about enabling in your own code 
9297        tls_config. key_log  = Arc :: new ( rustls:: KeyLogFile :: new ( ) ) ; 
9398    } 
9499
95-     let  client_config = quinn:: ClientConfig :: new ( Arc :: new ( tls_config) ) ; 
96- 
97100    let  mut  client_endpoint = h3_quinn:: quinn:: Endpoint :: client ( "[::]:0" . parse ( ) . unwrap ( ) ) ?; 
101+ 
102+     let  client_config = quinn:: ClientConfig :: new ( Arc :: new ( tls_config) ) ; 
98103    client_endpoint. set_default_client_config ( client_config) ; 
99-     let  quinn_conn = h3_quinn:: Connection :: new ( client_endpoint. connect ( addr,  auth. host ( ) ) ?. await ?) ; 
100104
101-     eprintln ! ( "QUIC connected ..." ) ; 
105+     let  conn = client_endpoint. connect ( addr,  auth. host ( ) ) ?. await ?; 
106+ 
107+     info ! ( "QUIC connection established" ) ; 
108+ 
109+     // create h3 client 
110+ 
111+     // h3 is designed to work with different QUIC implementations via 
112+     // a generic interface, that is, the [`quic::Connection`] trait. 
113+     // h3_quinn implements the trait w/ quinn to make it work with h3. 
114+     let  quinn_conn = h3_quinn:: Connection :: new ( conn) ; 
102115
103-     // generic h3 
104116    let  ( mut  driver,  mut  send_request)  = h3:: client:: new ( quinn_conn) . await ?; 
105117
106118    let  drive = async  move  { 
@@ -115,48 +127,41 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
115127    //             So we "move" it. 
116128    //                  vvvv 
117129    let  request = async  move  { 
118-         eprintln ! ( "Sending  request ..." ) ; 
130+         info ! ( "sending  request ..." ) ; 
119131
120-         let  req = http:: Request :: builder ( ) . uri ( dest ) . body ( ( ) ) ?; 
132+         let  req = http:: Request :: builder ( ) . uri ( uri ) . body ( ( ) ) ?; 
121133
134+         // sending request results in a bidirectional stream, 
135+         // which is also used for receiving response 
122136        let  mut  stream = send_request. send_request ( req) . await ?; 
137+ 
138+         // finish on the sending side 
123139        stream. finish ( ) . await ?; 
124140
125-         eprintln ! ( "Receiving response ..." ) ; 
141+         info ! ( "receiving response ..." ) ; 
142+ 
126143        let  resp = stream. recv_response ( ) . await ?; 
127144
128-         eprintln ! ( "Response : {:?} {}" ,  resp. version( ) ,  resp. status( ) ) ; 
129-         eprintln ! ( "Headers : {:#?}" ,  resp. headers( ) ) ; 
145+         info ! ( "response : {:?} {}" ,  resp. version( ) ,  resp. status( ) ) ; 
146+         info ! ( "headers : {:#?}" ,  resp. headers( ) ) ; 
130147
148+         // `recv_data()` must be called after `recv_response()` for 
149+         // receiving potential response body 
131150        while  let  Some ( mut  chunk)  = stream. recv_data ( ) . await ? { 
132151            let  mut  out = tokio:: io:: stdout ( ) ; 
133152            out. write_all_buf ( & mut  chunk) . await ?; 
134153            out. flush ( ) . await ?; 
135154        } 
155+ 
136156        Ok :: < _ ,  Box < dyn  std:: error:: Error > > ( ( ) ) 
137157    } ; 
138158
139159    let  ( req_res,  drive_res)  = tokio:: join!( request,  drive) ; 
140160    req_res?; 
141161    drive_res?; 
142162
163+     // wait for the connection to be closed before exiting 
143164    client_endpoint. wait_idle ( ) . await ; 
144165
145166    Ok ( ( ) ) 
146167} 
147- 
148- struct  YesVerifier ; 
149- 
150- impl  rustls:: client:: ServerCertVerifier  for  YesVerifier  { 
151-     fn  verify_server_cert ( 
152-         & self , 
153-         _end_entity :  & Certificate , 
154-         _intermediates :  & [ Certificate ] , 
155-         _server_name :  & ServerName , 
156-         _scts :  & mut  dyn  Iterator < Item  = & [ u8 ] > , 
157-         _ocsp_response :  & [ u8 ] , 
158-         _now :  SystemTime , 
159-     )  -> Result < ServerCertVerified ,  Error >  { 
160-         Ok ( ServerCertVerified :: assertion ( ) ) 
161-     } 
162- } 
0 commit comments