97 lines
3.4 KiB
Rust
97 lines
3.4 KiB
Rust
#[path = "../src/transport/http3.rs"]
|
|
mod http3;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use http3::{
|
|
decode_capsule, decode_http_datagram, encode_auth_challenge, encode_auth_response,
|
|
encode_capsule, encode_http_datagram, validate_connect_udp_request, AuthChallenge,
|
|
ConnectUdpRequest, Http3Error, CONNECT_UDP_CONTEXT_ID,
|
|
};
|
|
|
|
#[test]
|
|
fn validates_extended_connect_request() {
|
|
validate_connect_udp_request("CONNECT", "connect-udp", "/tunnel", "/tunnel").unwrap();
|
|
ConnectUdpRequest::new("/tunnel")
|
|
.validate("/tunnel")
|
|
.unwrap();
|
|
assert!(matches!(
|
|
validate_connect_udp_request("POST", "connect-udp", "/tunnel", "/tunnel"),
|
|
Err(Http3Error::InvalidRequest("method must be CONNECT"))
|
|
));
|
|
assert!(matches!(
|
|
validate_connect_udp_request("CONNECT", "webtransport", "/tunnel", "/tunnel"),
|
|
Err(Http3Error::InvalidRequest(":protocol must be connect-udp"))
|
|
));
|
|
assert!(validate_connect_udp_request("CONNECT", "connect-udp", "/other", "/tunnel").is_err());
|
|
assert!(validate_connect_udp_request("CONNECT", "connect-udp", "tunnel", "tunnel").is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn http_datagram_uses_context_id_and_preserves_opaque_payload() {
|
|
for context in [0, 63, 64, 16_383, 16_384, (1 << 30) - 1, 1 << 30] {
|
|
let encoded = encode_http_datagram(context, b"opaque", 1200).unwrap();
|
|
assert_eq!(
|
|
decode_http_datagram(&encoded, context, 1200).unwrap(),
|
|
b"opaque"[..]
|
|
);
|
|
}
|
|
assert!(matches!(
|
|
decode_http_datagram(
|
|
&encode_http_datagram(7, b"x", 1200).unwrap(),
|
|
CONNECT_UDP_CONTEXT_ID,
|
|
1200
|
|
),
|
|
Err(Http3Error::ContextMismatch { .. })
|
|
));
|
|
assert!(matches!(
|
|
encode_http_datagram(CONNECT_UDP_CONTEXT_ID, &[0; 1201], 1200),
|
|
Err(Http3Error::Oversized {
|
|
length: 1201,
|
|
maximum: 1200
|
|
})
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn capsule_round_trip_and_truncation_are_checked() {
|
|
let encoded = encode_capsule(0x2a, b"challenge").unwrap();
|
|
assert_eq!(
|
|
decode_capsule(&encoded).unwrap(),
|
|
(0x2a, bytes::Bytes::from_static(b"challenge"))
|
|
);
|
|
assert!(matches!(
|
|
decode_capsule(&encoded[..encoded.len() - 1]),
|
|
Err(Http3Error::Truncated)
|
|
));
|
|
let mut extra = encoded.to_vec();
|
|
extra.push(0);
|
|
assert!(matches!(
|
|
decode_capsule(&extra),
|
|
Err(Http3Error::InvalidCapsule)
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn authentication_is_completed_before_session_activation() {
|
|
let challenge = AuthChallenge::random();
|
|
let nonce = [5u8; 16];
|
|
let secret = [7u8; 32];
|
|
let challenge_capsule = encode_auth_challenge(&challenge).unwrap();
|
|
assert_eq!(
|
|
decode_capsule(&challenge_capsule).unwrap().0,
|
|
http3::AUTH_CHALLENGE_CAPSULE
|
|
);
|
|
let response = encode_auth_response(&challenge, "laptop", &nonce, &secret).unwrap();
|
|
let mut clients = HashMap::new();
|
|
clients.insert("laptop".to_owned(), secret.to_vec());
|
|
let client = http3::verify_auth_response(&challenge, &response, &clients).unwrap();
|
|
assert_eq!(client.id, "laptop");
|
|
assert_eq!(client.nonce, nonce);
|
|
|
|
let bad = encode_auth_response(&challenge, "laptop", &nonce, &[8u8; 32]).unwrap();
|
|
assert!(http3::verify_auth_response(&challenge, &bad, &clients).is_err());
|
|
assert!(http3::is_auth_accept(&http3::encode_auth_accept().unwrap()).unwrap());
|
|
assert!(!http3::is_auth_accept(&http3::encode_auth_reject().unwrap()).unwrap());
|
|
}
|