use url::Url;
use super::{EndpointError, resolve_endpoint, validate_stream_url};
const BASE: &str = "https://good-host.example/sse";
fn base() -> Url {
Url::parse(BASE).expect("base URL should parse")
}
fn resolve(raw: &str) -> Result<Url, EndpointError> {
resolve_endpoint(&base(), raw)
}
#[test]
fn resolves_an_absolute_path_against_the_stream_url() {
let endpoint = resolve("/messages/?session_id=abc").expect("same-origin path is allowed");
assert_eq!(
endpoint.as_str(),
"https://good-host.example/messages/?session_id=abc"
);
}
#[test]
fn resolves_a_relative_path_against_the_stream_url() {
let base = Url::parse("https://good-host.example/mcp/sse").expect("base should parse");
let endpoint = resolve_endpoint(&base, "messages?session_id=abc").expect("relative is allowed");
assert_eq!(
endpoint.as_str(),
"https://good-host.example/mcp/messages?session_id=abc"
);
}
#[test]
fn accepts_an_absolute_url_on_the_same_origin() {
let endpoint =
resolve("https://good-host.example/messages/").expect("same-origin absolute is allowed");
assert_eq!(endpoint.as_str(), "https://good-host.example/messages/");
}
#[test]
fn accepts_an_explicit_default_port_matching_the_implicit_one() {
let endpoint = resolve("https://good-host.example:443/messages/")
.expect("default port is the same origin");
assert_eq!(endpoint.as_str(), "https://good-host.example/messages/");
}
#[test]
fn accepts_an_implicit_default_port_matching_an_explicit_one() {
let base = Url::parse("https://good-host.example:443/sse").expect("base should parse");
let endpoint = resolve_endpoint(&base, "https://good-host.example/messages/")
.expect("implicit port is the same origin");
assert_eq!(endpoint.as_str(), "https://good-host.example/messages/");
}
#[test]
fn accepts_a_matching_non_default_port() {
let base = Url::parse("http://127.0.0.1:8080/sse").expect("base should parse");
let endpoint =
resolve_endpoint(&base, "/messages/?session_id=abc").expect("same port is allowed");
assert_eq!(
endpoint.as_str(),
"http://127.0.0.1:8080/messages/?session_id=abc"
);
}
#[test]
fn accepts_a_host_differing_only_by_case() {
let endpoint =
resolve("https://GOOD-HOST.EXAMPLE/messages/").expect("host case is not significant");
assert_eq!(endpoint.as_str(), "https://good-host.example/messages/");
}
#[test]
fn accepts_a_plain_http_origin_when_the_stream_is_plain_http() {
let base = Url::parse("http://localhost:3000/sse").expect("base should parse");
let endpoint = resolve_endpoint(&base, "/messages/").expect("http is an allowed scheme");
assert_eq!(endpoint.as_str(), "http://localhost:3000/messages/");
}
#[test]
fn preserves_the_query_string_carrying_the_session_id() {
let endpoint = resolve("/messages/?session_id=6c8f2a&foo=bar").expect("query is preserved");
assert_eq!(endpoint.query(), Some("session_id=6c8f2a&foo=bar"));
}
#[test]
fn rejects_an_absolute_url_on_a_different_host() {
let error = resolve("https://evil.example/steal").expect_err("cross-host must be rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_protocol_relative_url_that_replaces_the_authority() {
let error = resolve("//evil.example/steal").expect_err("protocol-relative must be rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_backslash_authority_that_url_normalizes_to_a_new_host() {
let error = resolve("/\\evil.example/steal").expect_err("backslash authority must be rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_scheme_downgrade_to_plain_http() {
let error =
resolve("http://good-host.example/messages/").expect_err("downgrade must be rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_scheme_upgrade_to_https() {
let base = Url::parse("http://good-host.example/sse").expect("base should parse");
let error = resolve_endpoint(&base, "https://good-host.example/messages/")
.expect_err("scheme change must be rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_different_explicit_port() {
let error =
resolve("https://good-host.example:8443/messages/").expect_err("port change is rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_trailing_dot_host_that_resolves_to_the_same_name() {
let error =
resolve("https://good-host.example./messages/").expect_err("trailing dot is rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_punycode_homograph_host() {
let error = resolve("https://g\u{f6}\u{f6}d-host.example/messages/")
.expect_err("homograph host is rejected");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_subdomain_of_the_configured_host() {
let error = resolve("https://evil.good-host.example/messages/")
.expect_err("subdomains are a different origin");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_a_suffix_extension_of_the_configured_host() {
let error = resolve("https://good-host.example.evil.test/messages/")
.expect_err("suffix extension is a different origin");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn rejects_userinfo_even_on_the_matching_origin() {
let error = resolve("https://attacker@good-host.example/messages/")
.expect_err("userinfo must be rejected");
assert!(matches!(error, EndpointError::CredentialsInUrl));
}
#[test]
fn rejects_a_password_in_the_endpoint_url() {
let error = resolve("https://user:secret@good-host.example/messages/")
.expect_err("password must be rejected");
assert!(matches!(error, EndpointError::CredentialsInUrl));
}
#[test]
fn rejects_a_javascript_scheme() {
let error = resolve("javascript:alert(1)").expect_err("javascript must be rejected");
assert!(matches!(error, EndpointError::UnsupportedScheme { .. }));
}
#[test]
fn rejects_a_data_scheme() {
let error = resolve("data:text/plain,hi").expect_err("data must be rejected");
assert!(matches!(error, EndpointError::UnsupportedScheme { .. }));
}
#[test]
fn rejects_a_file_scheme() {
let error = resolve("file:///etc/passwd").expect_err("file must be rejected");
assert!(matches!(error, EndpointError::UnsupportedScheme { .. }));
}
#[test]
fn rejects_an_empty_endpoint_payload() {
let error = resolve("").expect_err("an empty endpoint must be rejected");
assert!(matches!(error, EndpointError::Empty));
}
#[test]
fn rejects_a_whitespace_only_endpoint_payload() {
let error = resolve(" ").expect_err("a blank endpoint must be rejected");
assert!(matches!(error, EndpointError::Empty));
}
#[test]
fn rejects_an_unparseable_endpoint() {
let error = resolve("http://[not-an-address/x").expect_err("garbage must be rejected");
assert!(matches!(error, EndpointError::Malformed(_)));
}
#[test]
fn trims_surrounding_whitespace_before_resolving() {
let endpoint = resolve(" /messages/?session_id=abc ").expect("padding is trimmed");
assert_eq!(
endpoint.as_str(),
"https://good-host.example/messages/?session_id=abc"
);
}
#[test]
fn rejects_a_padded_cross_origin_endpoint() {
let error =
resolve(" https://evil.example/steal ").expect_err("padding does not bypass the check");
assert!(matches!(error, EndpointError::CrossOrigin { .. }));
}
#[test]
fn accepts_an_https_stream_url() {
let url = validate_stream_url("https://good-host.example/sse").expect("https is allowed");
assert_eq!(url.scheme(), "https");
}
#[test]
fn accepts_an_http_stream_url() {
let url = validate_stream_url("http://127.0.0.1:9000/sse").expect("http is allowed");
assert_eq!(url.scheme(), "http");
}
#[test]
fn rejects_a_stream_url_with_an_unsupported_scheme() {
let error = validate_stream_url("ws://good-host.example/sse").expect_err("ws is rejected");
assert!(matches!(error, EndpointError::UnsupportedScheme { .. }));
}
#[test]
fn rejects_a_stream_url_with_embedded_credentials() {
let error = validate_stream_url("https://user:pass@good-host.example/sse")
.expect_err("credentials are rejected");
assert!(matches!(error, EndpointError::CredentialsInUrl));
}
#[test]
fn rejects_a_stream_url_without_a_host() {
let error = validate_stream_url("file:///tmp/sse").expect_err("a hostless URL is rejected");
assert!(matches!(
error,
EndpointError::UnsupportedScheme { .. } | EndpointError::MissingHost
));
}
#[test]
fn rejects_an_unparseable_stream_url() {
let error = validate_stream_url("not a url").expect_err("garbage is rejected");
assert!(matches!(error, EndpointError::Malformed(_)));
}
#[test]
fn the_cross_origin_error_does_not_retain_either_origin() {
let error =
resolve("https://remote-canary.invalid/steal").expect_err("cross-origin is rejected");
let rendered = error.to_string();
let debug = format!("{error:?}");
for origin in ["remote-canary.invalid", "good-host.example"] {
assert!(!rendered.contains(origin), "got {rendered}");
assert!(!debug.contains(origin), "got {debug}");
}
}
#[test]
fn unsupported_scheme_errors_do_not_retain_the_scheme() {
let error = resolve("remote-canary:payload").expect_err("the scheme is unsupported");
let rendered = error.to_string();
let debug = format!("{error:?}");
assert!(!rendered.contains("remote-canary"), "got {rendered}");
assert!(!debug.contains("remote-canary"), "got {debug}");
}
#[test]
fn malformed_endpoint_errors_do_not_retain_the_payload() {
let error = resolve("http://[remote-canary.invalid").expect_err("the endpoint is malformed");
let rendered = error.to_string();
let debug = format!("{error:?}");
assert!(!rendered.contains("remote-canary"), "got {rendered}");
assert!(!debug.contains("remote-canary"), "got {debug}");
}
#[test]
fn the_credentials_error_does_not_echo_the_credentials() {
let error = resolve("https://user:hunter2@good-host.example/messages/")
.expect_err("credentials are rejected");
let rendered = error.to_string();
assert!(
!rendered.contains("hunter2"),
"the error must not echo a secret: {rendered}"
);
}