1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6 
7 #![allow(unused_assignments)]
8 
9 use neqo_common::{event::Provider, Datagram};
10 use neqo_crypto::{AuthenticationStatus, ResumptionToken};
11 use neqo_http3::{
12     Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server,
13     Http3ServerEvent, Http3State, Priority,
14 };
15 use neqo_transport::{ConnectionParameters, StreamType};
16 use std::mem;
17 use test_fixture::*;
18 
19 const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
20 
receive_request(server: &mut Http3Server) -> Option<Http3OrWebTransportStream>21 fn receive_request(server: &mut Http3Server) -> Option<Http3OrWebTransportStream> {
22     while let Some(event) = server.next_event() {
23         if let Http3ServerEvent::Headers {
24             stream,
25             headers,
26             fin,
27         } = event
28         {
29             assert_eq!(
30                 &headers,
31                 &[
32                     Header::new(":method", "GET"),
33                     Header::new(":scheme", "https"),
34                     Header::new(":authority", "something.com"),
35                     Header::new(":path", "/")
36                 ]
37             );
38             assert!(fin);
39 
40             return Some(stream);
41         }
42     }
43     None
44 }
45 
set_response(request: &mut Http3OrWebTransportStream)46 fn set_response(request: &mut Http3OrWebTransportStream) {
47     request
48         .send_headers(&[
49             Header::new(":status", "200"),
50             Header::new("content-length", "3"),
51         ])
52         .unwrap();
53     request.send_data(RESPONSE_DATA).unwrap();
54     request.stream_close_send().unwrap();
55 }
56 
process_server_events(server: &mut Http3Server)57 fn process_server_events(server: &mut Http3Server) {
58     let mut request = receive_request(server).unwrap();
59     set_response(&mut request);
60 }
61 
process_client_events(conn: &mut Http3Client)62 fn process_client_events(conn: &mut Http3Client) {
63     let mut response_header_found = false;
64     let mut response_data_found = false;
65     while let Some(event) = conn.next_event() {
66         match event {
67             Http3ClientEvent::HeaderReady { headers, fin, .. } => {
68                 assert_eq!(
69                     &headers,
70                     &[
71                         Header::new(":status", "200"),
72                         Header::new("content-length", "3"),
73                     ]
74                 );
75                 assert!(!fin);
76                 response_header_found = true;
77             }
78             Http3ClientEvent::DataReadable { stream_id } => {
79                 let mut buf = [0u8; 100];
80                 let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
81                 assert!(fin);
82                 assert_eq!(amount, RESPONSE_DATA.len());
83                 assert_eq!(&buf[..RESPONSE_DATA.len()], RESPONSE_DATA);
84                 response_data_found = true;
85             }
86             _ => {}
87         }
88     }
89     assert!(response_header_found);
90     assert!(response_data_found);
91 }
92 
connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram>93 fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram> {
94     assert_eq!(hconn_c.state(), Http3State::Initializing);
95     let out = hconn_c.process(None, now()); // Initial
96     let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
97     let out = hconn_c.process(out.dgram(), now()); // ACK
98     mem::drop(hconn_s.process(out.dgram(), now())); //consume ACK
99     let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
100     assert!(hconn_c.events().any(authentication_needed));
101     hconn_c.authenticated(AuthenticationStatus::Ok, now());
102     let out = hconn_c.process(None, now()); // Handshake
103     assert_eq!(hconn_c.state(), Http3State::Connected);
104     let out = hconn_s.process(out.dgram(), now()); // Handshake
105     let out = hconn_c.process(out.dgram(), now());
106     let out = hconn_s.process(out.dgram(), now());
107     // assert!(hconn_s.settings_received);
108     let out = hconn_c.process(out.dgram(), now());
109     // assert!(hconn_c.settings_received);
110 
111     out.dgram()
112 }
113 
connect() -> (Http3Client, Http3Server, Option<Datagram>)114 fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
115     let mut hconn_c = default_http3_client();
116     let mut hconn_s = default_http3_server();
117 
118     let out = connect_peers(&mut hconn_c, &mut hconn_s);
119     (hconn_c, hconn_s, out)
120 }
121 
exchange_packets(client: &mut Http3Client, server: &mut Http3Server, out_ex: Option<Datagram>)122 fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server, out_ex: Option<Datagram>) {
123     let mut out = out_ex;
124     loop {
125         out = client.process(out, now()).dgram();
126         out = server.process(out, now()).dgram();
127         if out.is_none() {
128             break;
129         }
130     }
131 }
132 
133 #[test]
test_connect()134 fn test_connect() {
135     let (_hconn_c, _hconn_s, _d) = connect();
136 }
137 
138 #[test]
test_fetch()139 fn test_fetch() {
140     let (mut hconn_c, mut hconn_s, dgram) = connect();
141 
142     eprintln!("-----client");
143     let req = hconn_c
144         .fetch(
145             now(),
146             "GET",
147             &("https", "something.com", "/"),
148             &[],
149             Priority::default(),
150         )
151         .unwrap();
152     assert_eq!(req, 0);
153     hconn_c.stream_close_send(req).unwrap();
154     let out = hconn_c.process(dgram, now());
155     eprintln!("-----server");
156     let out = hconn_s.process(out.dgram(), now());
157     mem::drop(hconn_c.process(out.dgram(), now()));
158     process_server_events(&mut hconn_s);
159     let out = hconn_s.process(None, now());
160 
161     eprintln!("-----client");
162     mem::drop(hconn_c.process(out.dgram(), now()));
163     let out = hconn_s.process(None, now());
164     mem::drop(hconn_c.process(out.dgram(), now()));
165     process_client_events(&mut hconn_c);
166 }
167 
168 #[test]
test_103_response()169 fn test_103_response() {
170     let (mut hconn_c, mut hconn_s, dgram) = connect();
171 
172     let req = hconn_c
173         .fetch(
174             now(),
175             "GET",
176             &("https", "something.com", "/"),
177             &[],
178             Priority::default(),
179         )
180         .unwrap();
181     assert_eq!(req, 0);
182     hconn_c.stream_close_send(req).unwrap();
183     let out = hconn_c.process(dgram, now());
184 
185     let out = hconn_s.process(out.dgram(), now());
186     mem::drop(hconn_c.process(out.dgram(), now()));
187     let mut request = receive_request(&mut hconn_s).unwrap();
188 
189     let info_headers = [
190         Header::new(":status", "103"),
191         Header::new("link", "</style.css>; rel=preload; as=style"),
192     ];
193     // Send 103
194     request.send_headers(&info_headers).unwrap();
195     let out = hconn_s.process(None, now());
196 
197     mem::drop(hconn_c.process(out.dgram(), now()));
198 
199     let info_headers_event = |e| {
200         matches!(e, Http3ClientEvent::HeaderReady { headers,
201                     interim,
202                     fin, .. } if !fin && interim && headers.as_ref() == info_headers)
203     };
204     assert!(hconn_c.events().any(info_headers_event));
205 
206     set_response(&mut request);
207     let out = hconn_s.process(None, now());
208     mem::drop(hconn_c.process(out.dgram(), now()));
209     process_client_events(&mut hconn_c)
210 }
211 
212 #[test]
test_data_writable_events()213 fn test_data_writable_events() {
214     const STREAM_LIMIT: u64 = 5000;
215     const DATA_AMOUNT: usize = 10000;
216 
217     let mut hconn_c = http3_client_with_params(Http3Parameters::default().connection_parameters(
218         ConnectionParameters::default().max_stream_data(StreamType::BiDi, false, STREAM_LIMIT),
219     ));
220     let mut hconn_s = default_http3_server();
221 
222     mem::drop(connect_peers(&mut hconn_c, &mut hconn_s));
223 
224     // Create a request.
225     let req = hconn_c
226         .fetch(
227             now(),
228             "GET",
229             &("https", "something.com", "/"),
230             &[],
231             Priority::default(),
232         )
233         .unwrap();
234     hconn_c.stream_close_send(req).unwrap();
235     exchange_packets(&mut hconn_c, &mut hconn_s, None);
236 
237     let mut request = receive_request(&mut hconn_s).unwrap();
238 
239     request
240         .send_headers(&[
241             Header::new(":status", "200"),
242             Header::new("content-length", DATA_AMOUNT.to_string()),
243         ])
244         .unwrap();
245 
246     // Send a lot of data
247     let buf = &[1; DATA_AMOUNT];
248     let mut sent = request.send_data(buf).unwrap();
249     assert!(sent < DATA_AMOUNT);
250 
251     // Exchange packets and read the data on the client side.
252     exchange_packets(&mut hconn_c, &mut hconn_s, None);
253     let stream_id = request.stream_id();
254     let mut recv_buf = [0_u8; DATA_AMOUNT];
255     let (mut recvd, _) = hconn_c.read_data(now(), stream_id, &mut recv_buf).unwrap();
256     assert_eq!(sent, recvd);
257     exchange_packets(&mut hconn_c, &mut hconn_s, None);
258 
259     let data_writable = |e| {
260         matches!(
261             e,
262             Http3ServerEvent::DataWritable {
263                 stream
264             } if stream.stream_id() == stream_id
265         )
266     };
267     // Make sure we have a DataWritable event.
268     assert!(hconn_s.events().any(data_writable));
269     // Data can be sent again.
270     let s = request.send_data(&buf[sent..]).unwrap();
271     assert!(s > 0);
272     sent += s;
273 
274     // Exchange packets and read the data on the client side.
275     exchange_packets(&mut hconn_c, &mut hconn_s, None);
276     let (r, _) = hconn_c
277         .read_data(now(), stream_id, &mut recv_buf[recvd..])
278         .unwrap();
279     recvd += r;
280     exchange_packets(&mut hconn_c, &mut hconn_s, None);
281     assert_eq!(sent, recvd);
282 
283     // One more DataWritable event.
284     assert!(hconn_s.events().any(data_writable));
285     // Send more data.
286     let s = request.send_data(&buf[sent..]).unwrap();
287     assert!(s > 0);
288     sent += s;
289     assert_eq!(sent, DATA_AMOUNT);
290 
291     exchange_packets(&mut hconn_c, &mut hconn_s, None);
292     let (r, _) = hconn_c
293         .read_data(now(), stream_id, &mut recv_buf[recvd..])
294         .unwrap();
295     recvd += r;
296 
297     // Make sure all data is received by the client.
298     assert_eq!(recvd, DATA_AMOUNT);
299     assert_eq!(&recv_buf, buf);
300 }
301 
get_token(client: &mut Http3Client) -> ResumptionToken302 fn get_token(client: &mut Http3Client) -> ResumptionToken {
303     assert_eq!(client.state(), Http3State::Connected);
304     client
305         .events()
306         .find_map(|e| {
307             if let Http3ClientEvent::ResumptionToken(token) = e {
308                 Some(token)
309             } else {
310                 None
311             }
312         })
313         .unwrap()
314 }
315 
316 #[test]
zerortt()317 fn zerortt() {
318     let (mut hconn_c, _, dgram) = connect();
319     let token = get_token(&mut hconn_c);
320 
321     // Create a new connection with a resumption token.
322     let mut hconn_c = default_http3_client();
323     hconn_c
324         .enable_resumption(now(), &token)
325         .expect("Set resumption token.");
326     let mut hconn_s = default_http3_server();
327 
328     // Create a request.
329     let req = hconn_c
330         .fetch(
331             now(),
332             "GET",
333             &("https", "something.com", "/"),
334             &[],
335             Priority::default(),
336         )
337         .unwrap();
338     hconn_c.stream_close_send(req).unwrap();
339 
340     let out = hconn_c.process(dgram, now());
341     let out = hconn_s.process(out.dgram(), now());
342 
343     let mut request_stream = None;
344     let mut zerortt_state_change = false;
345     while let Some(event) = hconn_s.next_event() {
346         match event {
347             Http3ServerEvent::Headers {
348                 stream,
349                 headers,
350                 fin,
351             } => {
352                 assert_eq!(
353                     &headers,
354                     &[
355                         Header::new(":method", "GET"),
356                         Header::new(":scheme", "https"),
357                         Header::new(":authority", "something.com"),
358                         Header::new(":path", "/")
359                     ]
360                 );
361                 assert!(fin);
362 
363                 request_stream = Some(stream);
364             }
365             Http3ServerEvent::StateChange { state, .. } => {
366                 assert_eq!(state, Http3State::ZeroRtt);
367                 zerortt_state_change = true;
368             }
369             _ => {}
370         }
371     }
372     assert!(zerortt_state_change);
373     let mut request_stream = request_stream.unwrap();
374 
375     // Send a response
376     set_response(&mut request_stream);
377 
378     // Receive the response
379     exchange_packets(&mut hconn_c, &mut hconn_s, out.dgram());
380     process_client_events(&mut hconn_c);
381 }
382