mirror of
https://github.com/telemt/telemt.git
synced 2026-10-10 03:15:58 +03:00
fca6506449
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
546 lines
19 KiB
Rust
546 lines
19 KiB
Rust
use super::*;
|
|
|
|
#[path = "web_tests/base_path_tests.rs"]
|
|
mod base_path_tests;
|
|
|
|
// Method selection must not alter capability identity or accepted config literals.
|
|
#[path = "web_tests/carrier_method_tests.rs"]
|
|
mod carrier_method_tests;
|
|
|
|
const WEB_CONFIG: &str = r#"
|
|
[access.users]
|
|
alice = "000102030405060708090a0b0c0d0e0f"
|
|
|
|
[[server.listeners]]
|
|
ip = "127.0.0.1"
|
|
port = 18080
|
|
transport = "web"
|
|
proxy_protocol = false
|
|
web_client_ip_source = "x_forwarded_for"
|
|
web_trusted_proxy_cidrs = ["127.0.0.1/32"]
|
|
|
|
[web]
|
|
enabled = true
|
|
carrier = "https-lanes"
|
|
|
|
[[web.vhosts]]
|
|
host = "Proxy.Example.COM"
|
|
public_addr = "203.0.113.10:443"
|
|
|
|
[web.vhosts.decoy]
|
|
mode = "http_upstream"
|
|
upstream = "http://127.0.0.1:18081"
|
|
|
|
[[web.vhosts.profiles]]
|
|
user = "alice"
|
|
secret_mode = "dd"
|
|
max_sessions = 4
|
|
max_streams = 64
|
|
max_streams_per_session = 16
|
|
"#;
|
|
|
|
#[test]
|
|
fn web_config_builds_canonical_runtime_snapshot() {
|
|
let config = load_config_from_temp_toml(WEB_CONFIG);
|
|
let runtime = config.web.runtime.expect("WEB runtime snapshot");
|
|
let vhost = runtime
|
|
.vhosts
|
|
.get("proxy.example.com")
|
|
.expect("canonical WEB vhost");
|
|
assert_eq!(vhost.base, "/");
|
|
assert_eq!(vhost.profiles.len(), 1);
|
|
assert_eq!(vhost.capabilities.len(), vhost.profiles.len());
|
|
assert_eq!(vhost.capabilities[0], vhost.profiles[0].capability);
|
|
assert_eq!(runtime.capabilities.as_ref(), vhost.capabilities.as_ref());
|
|
assert_eq!(vhost.decoy_fasttrack_mode, WebDecoyFastTrackMode::Off);
|
|
assert_eq!(vhost.profiles[0].user, "alice");
|
|
assert_eq!(vhost.profiles[0].secret_mode, WebSecretMode::Dd);
|
|
assert_eq!(vhost.profiles[0].carrier, WebCarrier::HttpsLanes);
|
|
assert_eq!(vhost.profiles[0].max_sessions, 4);
|
|
assert_eq!(vhost.profiles[0].max_streams, 64);
|
|
assert_eq!(vhost.profiles[0].max_streams_per_session, 16);
|
|
assert_eq!(vhost.profiles[0].key_fingerprint.len(), 16);
|
|
assert_ne!(vhost.profiles[0].key_fingerprint, "0001020304050607");
|
|
assert!(!vhost.profiles[0].carrier_negotiation_enabled);
|
|
assert_eq!(
|
|
vhost.profiles[0].carriers.as_ref(),
|
|
[WebCarrier::HttpsLanes]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_base_path_is_canonical_and_precomputed() {
|
|
let maximum = "a".repeat(128);
|
|
for base_path in ["a", "a/b/c9_x-y", "Dobry-Cola/super_app", maximum.as_str()] {
|
|
let configured = WEB_CONFIG.replace(
|
|
"host = \"Proxy.Example.COM\"",
|
|
&format!("host = \"Proxy.Example.COM\"\nbase_path = \"{base_path}\""),
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
assert_eq!(config.web.vhosts[0].base_path, base_path);
|
|
assert_eq!(
|
|
config.web.runtime.as_ref().unwrap().vhosts["proxy.example.com"].base,
|
|
format!("/{base_path}/")
|
|
);
|
|
}
|
|
|
|
let strict = format!(
|
|
"[general]\nconfig_strict = true\n{}",
|
|
WEB_CONFIG.replace(
|
|
"host = \"Proxy.Example.COM\"",
|
|
"host = \"Proxy.Example.COM\"\nbase_path = \"relay\"",
|
|
)
|
|
);
|
|
assert_eq!(
|
|
load_config_from_temp_toml(&strict).web.vhosts[0].base_path,
|
|
"relay"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_base_path_rejects_noncanonical_forms() {
|
|
let oversized = "a".repeat(129);
|
|
for base_path in [
|
|
"/relay",
|
|
"relay/",
|
|
"relay//nested",
|
|
"-relay",
|
|
"_relay",
|
|
"a/-lead",
|
|
"a/_lead",
|
|
"dot.ted",
|
|
"..",
|
|
"/",
|
|
"relay/.hidden",
|
|
"relay/%2fhidden",
|
|
"relay path",
|
|
"relay/тест",
|
|
oversized.as_str(),
|
|
] {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"host = \"Proxy.Example.COM\"",
|
|
&format!("host = \"Proxy.Example.COM\"\nbase_path = \"{base_path}\""),
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&invalid).contains("web.vhosts[0].base_path"),
|
|
"base path {base_path:?} was accepted"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn web_decoy_fasttrack_mode_is_typed_and_defaults_off() {
|
|
let defaults = ProxyConfig::default();
|
|
assert_eq!(
|
|
defaults.web.decoy_fasttrack_mode,
|
|
WebDecoyFastTrackMode::Off
|
|
);
|
|
|
|
for (token, expected) in [
|
|
("shadow", WebDecoyFastTrackMode::Shadow),
|
|
("enforce", WebDecoyFastTrackMode::Enforce),
|
|
] {
|
|
let configured = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
&format!("carrier = \"https-lanes\"\ndecoy_fasttrack_mode = \"{token}\""),
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
assert_eq!(config.web.decoy_fasttrack_mode, expected);
|
|
assert_eq!(
|
|
config.web.runtime.as_ref().unwrap().vhosts["proxy.example.com"].decoy_fasttrack_mode,
|
|
expected
|
|
);
|
|
}
|
|
|
|
let invalid = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\ndecoy_fasttrack_mode = \"automatic\"",
|
|
);
|
|
assert!(load_config_error_from_temp_toml(&invalid).contains("decoy_fasttrack_mode"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_http_connection_capacity_policy_is_bounded_and_configurable() {
|
|
let configured = WEB_CONFIG
|
|
.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\nhttp_connection_capacity_action = \"wait\"",
|
|
)
|
|
.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.limits]\nmax_http_overload_connections = 23\n\n[web.timeouts]\nhttp_overload_timeout_ms = 731\n\n[[web.vhosts]]",
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
|
|
assert_eq!(
|
|
config.web.http_connection_capacity_action,
|
|
WebHttpConnectionCapacityAction::Wait
|
|
);
|
|
assert_eq!(config.web.limits.max_http_overload_connections, 23);
|
|
assert_eq!(config.web.timeouts.http_overload_timeout_ms, 731);
|
|
|
|
let defaults = ProxyConfig::default();
|
|
assert_eq!(
|
|
defaults.web.http_connection_capacity_action,
|
|
WebHttpConnectionCapacityAction::Drop
|
|
);
|
|
assert_eq!(defaults.web.limits.max_http_overload_connections, 64);
|
|
assert_eq!(defaults.web.timeouts.http_overload_timeout_ms, 250);
|
|
}
|
|
|
|
#[test]
|
|
fn web_http_connection_capacity_policy_rejects_unknown_or_unbounded_values() {
|
|
let unknown = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\nhttp_connection_capacity_action = \"queue\"",
|
|
);
|
|
assert!(load_config_error_from_temp_toml(&unknown).contains("http_connection_capacity_action"));
|
|
|
|
for timeout in [0, 60_001] {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
&format!("[web.timeouts]\nhttp_overload_timeout_ms = {timeout}\n\n[[web.vhosts]]"),
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&invalid)
|
|
.contains("web.timeouts.http_overload_timeout_ms")
|
|
);
|
|
}
|
|
|
|
let no_overload_slots = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.limits]\nmax_http_overload_connections = 0\n\n[[web.vhosts]]",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&no_overload_slots)
|
|
.contains("web.limits.max_http_overload_connections")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_decoy_rejects_direct_and_wildcard_listener_loops() {
|
|
let direct = WEB_CONFIG.replace("http://127.0.0.1:18081", "http://127.0.0.1:18080");
|
|
assert!(
|
|
load_config_error_from_temp_toml(&direct).contains("decoy upstream overlaps WEB listener")
|
|
);
|
|
|
|
let wildcard = direct.replace("ip = \"127.0.0.1\"", "ip = \"0.0.0.0\"");
|
|
assert!(
|
|
load_config_error_from_temp_toml(&wildcard)
|
|
.contains("decoy upstream overlaps WEB listener")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_profile_user_labels_are_bounded_for_runtime_status() {
|
|
let user = "a".repeat(65);
|
|
let invalid = WEB_CONFIG.replace("alice", &user);
|
|
|
|
assert!(
|
|
load_config_error_from_temp_toml(&invalid)
|
|
.contains("web.vhosts[0].profiles[0].user must contain 1..64 bytes")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_carriers_missing_or_false_disable_negotiation() {
|
|
let missing = load_config_from_temp_toml(WEB_CONFIG);
|
|
assert!(!missing.web.carrier_negotiation_enabled());
|
|
assert!(!missing.web.runtime.unwrap().profiles[0].carrier_learning);
|
|
|
|
let disabled = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\ncarriers = false",
|
|
);
|
|
let disabled = load_config_from_temp_toml(&disabled);
|
|
assert!(!disabled.web.carrier_negotiation_enabled());
|
|
assert!(!disabled.web.runtime.as_ref().unwrap().profiles[0].carrier_learning);
|
|
assert_eq!(
|
|
disabled.web.runtime.unwrap().profiles[0].carriers.as_ref(),
|
|
[WebCarrier::HttpsLanes]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_carrier_array_enables_ordered_negotiation_and_appends_fallback() {
|
|
let configured = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\ncarriers = [\"websocket\", \"https\"]\ncarrier_learning = false",
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
assert!(config.web.carrier_negotiation_enabled());
|
|
assert!(!config.web.carrier_learning);
|
|
let profile = &config.web.runtime.unwrap().profiles[0];
|
|
assert_eq!(
|
|
profile.carriers.as_ref(),
|
|
[
|
|
WebCarrier::Websocket,
|
|
WebCarrier::Https,
|
|
WebCarrier::HttpsLanes
|
|
]
|
|
);
|
|
assert!(!profile.carrier_learning);
|
|
}
|
|
|
|
#[test]
|
|
fn web_carriers_reject_true_empty_and_duplicates() {
|
|
for value in ["true", "[]", "[\"https\", \"https\"]"] {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
&format!("carrier = \"https-lanes\"\ncarriers = {value}"),
|
|
);
|
|
assert!(load_config_error_from_temp_toml(&invalid).contains("web.carriers"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn web_carrier_and_bridge_deadlines_are_configurable() {
|
|
let configured = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.timeouts]\ncarrier_negotiation_deadlines_secs = [1, 2, 4, 9]\ncarrier_learning_secs = 30\nbridge_request_secs = 7\nbridge_retry_secs = 41\nbridge_recovery_secs = 13\ncarrier_probe_coalesce_ms = 4\n\n[[web.vhosts]]",
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
assert_eq!(
|
|
config.web.timeouts.carrier_negotiation_deadlines_secs,
|
|
[1, 2, 4, 9]
|
|
);
|
|
assert_eq!(config.web.timeouts.carrier_learning_secs, 30);
|
|
assert_eq!(config.web.timeouts.bridge_request_secs, 7);
|
|
assert_eq!(config.web.timeouts.bridge_retry_secs, 41);
|
|
assert_eq!(config.web.timeouts.bridge_recovery_secs, 13);
|
|
assert_eq!(config.web.timeouts.carrier_probe_coalesce_ms, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn web_bridge_deadlines_are_known_in_strict_mode() {
|
|
let configured = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.timeouts]\nbridge_request_secs = 7\nbridge_retry_secs = 41\nbridge_recovery_secs = 13\ncarrier_probe_coalesce_ms = 4\n\n[[web.vhosts]]",
|
|
);
|
|
let configured = format!("[general]\nconfig_strict = true\n{configured}");
|
|
let config = load_config_from_temp_toml(&configured);
|
|
|
|
assert_eq!(config.web.timeouts.bridge_request_secs, 7);
|
|
assert_eq!(config.web.timeouts.bridge_retry_secs, 41);
|
|
assert_eq!(config.web.timeouts.bridge_recovery_secs, 13);
|
|
assert_eq!(config.web.timeouts.carrier_probe_coalesce_ms, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn web_bridge_deadlines_are_bounded_and_ordered() {
|
|
for (field, value) in [
|
|
("bridge_request_secs", "0"),
|
|
("bridge_request_secs", "61"),
|
|
("bridge_retry_secs", "0"),
|
|
("bridge_retry_secs", "301"),
|
|
("bridge_recovery_secs", "0"),
|
|
("bridge_recovery_secs", "61"),
|
|
("carrier_probe_coalesce_ms", "11"),
|
|
] {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
&format!("[web.timeouts]\n{field} = {value}\n\n[[web.vhosts]]"),
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&invalid).contains(&format!("web.timeouts.{field}"))
|
|
);
|
|
}
|
|
|
|
let reversed = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.timeouts]\nbridge_request_secs = 20\nbridge_retry_secs = 10\n\n[[web.vhosts]]",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&reversed)
|
|
.contains("bridge_request_secs must not exceed bridge_retry_secs")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_carrier_learning_capacity_must_remain_nonzero() {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.limits]\nmax_carrier_learning_entries = 0\n\n[[web.vhosts]]",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&invalid)
|
|
.contains("web.limits.max_carrier_learning_entries")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn web_debug_table_uses_debug_name_and_bounded_defaults() {
|
|
assert!(!crate::config::WebDebugConfig::default().sideband);
|
|
let mut ineffective = crate::config::WebDebugConfig {
|
|
enabled: true,
|
|
sideband: true,
|
|
..Default::default()
|
|
};
|
|
ineffective.capture_lifecycle = false;
|
|
assert!(!ineffective.bridge_diagnostics_enabled());
|
|
|
|
let configured = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.debug]\nenabled = true\nsideband = true\nbody_capture = \"prefix\"\nbody_prefix_bytes = 2048\ndefault_window_secs = 180\nmax_window_secs = 900\n\n[[web.vhosts]]",
|
|
);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
assert!(config.web.debug.enabled);
|
|
assert!(config.web.debug.sideband);
|
|
assert!(config.web.debug.bridge_diagnostics_enabled());
|
|
assert_eq!(config.web.debug.body_capture, WebDebugBodyCapture::Prefix);
|
|
assert_eq!(config.web.debug.body_prefix_bytes, 2048);
|
|
assert_eq!(config.web.debug.default_window_secs, 180);
|
|
assert_eq!(config.web.debug.max_window_secs, 900);
|
|
|
|
let strict = format!("[general]\nconfig_strict = true\n{configured}");
|
|
assert!(load_config_from_temp_toml(&strict).web.debug.sideband);
|
|
|
|
let old_name = format!(
|
|
"[general]\nconfig_strict = true\n{}",
|
|
WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.trace]\nenabled = true\n\n[[web.vhosts]]",
|
|
)
|
|
);
|
|
let error = load_config_error_from_temp_toml(&old_name);
|
|
assert!(error.contains("web.trace"));
|
|
|
|
let old_parameter = format!(
|
|
"[general]\nconfig_strict = true\n{}",
|
|
WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.debug]\nbridge_diagnostics = true\n\n[[web.vhosts]]",
|
|
)
|
|
);
|
|
let error = load_config_error_from_temp_toml(&old_parameter);
|
|
assert!(error.contains("web.debug.bridge_diagnostics"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_debug_prefix_and_window_validation_fail_closed() {
|
|
let oversized_prefix = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.debug]\nenabled = true\nbody_prefix_bytes = 2097153\n\n[[web.vhosts]]",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&oversized_prefix);
|
|
assert!(error.contains("web.debug.body_prefix_bytes"));
|
|
|
|
let reversed_window = WEB_CONFIG.replace(
|
|
"[[web.vhosts]]",
|
|
"[web.debug]\nenabled = true\ndefault_window_secs = 181\nmax_window_secs = 180\n\n[[web.vhosts]]",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&reversed_window);
|
|
assert!(error.contains("web.debug windows"));
|
|
|
|
let undersized_store = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\n\n[web.limits]\ndebug_bytes_global = 4095",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&undersized_store);
|
|
assert!(error.contains("debug_bytes_global must be at least 4096"));
|
|
}
|
|
|
|
#[test]
|
|
fn https_lanes_requires_separate_poll_and_control_handler_capacity() {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\n\n[web.limits]\nmax_http_handlers = 1\nmax_body_readers = 1",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&invalid);
|
|
assert!(error.contains("WEB https-lanes candidates require"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_listener_requires_an_explicit_trusted_proxy() {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"web_trusted_proxy_cidrs = [\"127.0.0.1/32\"]",
|
|
"web_trusted_proxy_cidrs = []",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&invalid);
|
|
assert!(error.contains("web_trusted_proxy_cidrs must be non-empty"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_queue_limits_preserve_control_and_uplink_progress() {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"https-lanes\"\n\n[web.limits]\ncontrol_bytes_per_session = 1",
|
|
);
|
|
let error = load_config_error_from_temp_toml(&invalid);
|
|
assert!(error.contains("control reserves must cover bounded control frames"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_semaphore_limits_are_rejected_before_runtime_construction() {
|
|
let invalid = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
&format!(
|
|
"carrier = \"https-lanes\"\n\n[web.limits]\nmax_http_connections = {}",
|
|
tokio::sync::Semaphore::MAX_PERMITS + 1,
|
|
),
|
|
);
|
|
let error = load_config_error_from_temp_toml(&invalid);
|
|
assert!(error.contains("exceeds Tokio semaphore capacity"));
|
|
}
|
|
|
|
#[test]
|
|
fn web_ipv6_decoy_uses_a_valid_http_authority() {
|
|
let ipv6 = WEB_CONFIG.replace("http://127.0.0.1:18081", "http://[::1]:18081");
|
|
let config = load_config_from_temp_toml(&ipv6);
|
|
let runtime = config.web.runtime.expect("WEB runtime snapshot");
|
|
let vhost = runtime.vhosts.get("proxy.example.com").unwrap();
|
|
let WebRuntimeDecoy::HttpUpstream { authority, .. } = &vhost.decoy else {
|
|
panic!("expected HTTP decoy");
|
|
};
|
|
assert_eq!(authority, "[::1]:18081");
|
|
}
|
|
|
|
#[test]
|
|
fn websocket_carriers_build_runtime_profiles_with_bounded_defaults() {
|
|
for (name, carrier) in [
|
|
("websocket", WebCarrier::Websocket),
|
|
("websocket-lanes", WebCarrier::WebsocketLanes),
|
|
] {
|
|
let configured = WEB_CONFIG.replace("https-lanes", name);
|
|
let config = load_config_from_temp_toml(&configured);
|
|
let profile = &config.web.runtime.unwrap().profiles[0];
|
|
assert_eq!(profile.carrier, carrier);
|
|
assert_eq!(config.web.limits.websocket_bytes_global, 256 * 1024 * 1024);
|
|
assert_eq!(config.web.limits.websocket_admission_watermark_pct, 75);
|
|
assert_eq!(config.web.limits.websocket_eviction_watermark_pct, 90);
|
|
assert_eq!(config.web.limits.websocket_http_connection_reserve, 64);
|
|
assert_eq!(config.web.timeouts.websocket_write_secs, 30);
|
|
assert_eq!(config.web.timeouts.websocket_backpressure_secs, 30);
|
|
assert_eq!(config.web.timeouts.websocket_eviction_secs, 1);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn websocket_limits_reject_ambiguous_or_nonprogressing_policy() {
|
|
let reversed_watermarks = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"websocket\"\n\n[web.limits]\nwebsocket_admission_watermark_pct = 90\nwebsocket_eviction_watermark_pct = 75",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&reversed_watermarks).contains("WebSocket watermarks")
|
|
);
|
|
|
|
let no_http_reserve = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"websocket\"\n\n[web.limits]\nwebsocket_http_connection_reserve = 0",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&no_http_reserve)
|
|
.contains("websocket_http_connection_reserve")
|
|
);
|
|
|
|
let oversized_batch = WEB_CONFIG.replace(
|
|
"carrier = \"https-lanes\"",
|
|
"carrier = \"websocket\"\n\n[web.limits]\nmax_body_bytes = 4194304\ncarrier_batch_bytes = 4194304\nmax_body_readers = 16",
|
|
);
|
|
assert!(
|
|
load_config_error_from_temp_toml(&oversized_batch)
|
|
.contains("carrier_batch_bytes <= 2097152")
|
|
);
|
|
}
|