// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![expect(clippy::unwrap_used, reason = "OK in test code.")] use neqo_common::{event::Provider as _, header::HeadersExt as _}; use neqo_http3::{Header, Http3ClientEvent, Http3ServerEvent, Priority}; use test_fixture::{default_http3_client, default_http3_server, exchange_packets, now}; fn echo_header(request_header_name: &str, response_header_name: &str, test_data: &[u8]) { // Connect a client and a server. let mut client = default_http3_client(); let mut server = default_http3_server(); let out = test_fixture::connect_peers(&mut client, &mut server); assert_eq!(server.process(out, now()).dgram(), None); // Ignore all events so far. drop(server.events()); // Create a header with the test data let custom_header = Header::new(request_header_name, test_data); // Have client send a GET request with the custom header let stream_id = client .fetch( now(), "GET", ("https", "something.com", "/"), &[custom_header], Priority::default(), ) .unwrap(); client.stream_close_send(stream_id, now()).unwrap(); exchange_packets(&mut client, &mut server, false, None); // Server receives the request - loop through events to find Headers let mut received_stream = None; let mut received_headers = None; while let Some(event) = server.next_event() { if let Http3ServerEvent::Headers { stream, headers, .. } = event { received_stream = Some(stream); received_headers = Some(headers); break; } } let stream = received_stream.expect("No Headers event received from server"); let headers = received_headers.expect("No headers received"); // Verify the server received the header correctly let received_header = headers .find_header(request_header_name) .expect("Custom header not found"); assert_eq!(received_header.value(), test_data); // Server echoes the value back in a different header stream .send_headers(&[ Header::new(":status", "200"), Header::new(response_header_name, received_header.value()), ]) .unwrap(); stream.stream_close_send(now()).unwrap(); exchange_packets(&mut client, &mut server, false, None); // Client receives the response let mut response_headers = None; while let Some(event) = client.next_event() { if let Http3ClientEvent::HeaderReady { headers, .. } = event { response_headers = Some(headers); break; } } let headers = response_headers.expect("No response headers received"); // Verify the echoed header contains the original data let echoed_header = headers .find_header(response_header_name) .expect("Echoed header not found"); assert_eq!(echoed_header.value(), test_data); } #[test] fn extended_ascii_non_utf8_header_echo() { // Create a header with binary data let test_bytes: Vec = vec![0xE4]; // "รค" in extended ASCII (ISO-8859-1), invalid UTF-8 echo_header("x-custom-data", "x-echoed-data", &test_bytes); } #[test] fn non_ascii_emoji_header_echo() { // Create a header with non-ASCII but valid UTF-8 (emojis: rocket + star + laptop) let emoji_data = b"\xF0\x9F\x9A\x80\xF0\x9F\x8C\x9F\xF0\x9F\x92\xBB"; echo_header("x-emoji-data", "x-echoed-emoji", emoji_data); }