mirror of
https://github.com/telemt/telemt.git
synced 2026-09-05 18:16:06 +03:00
WEB Carrier: https-lanes
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -62,6 +62,7 @@ pub(super) fn rebuild(config: &mut ProxyConfig) -> Result<()> {
|
||||
public_addr: vhost.public_addr,
|
||||
user: profile.user.clone(),
|
||||
secret_mode: profile.secret_mode,
|
||||
carrier: config.web.carrier,
|
||||
capability,
|
||||
max_sessions: profile
|
||||
.max_sessions
|
||||
|
||||
@@ -259,7 +259,7 @@ const LISTENER_CONFIG_KEYS: &[&str] = &[
|
||||
"web_trusted_proxy_cidrs",
|
||||
];
|
||||
|
||||
const WEB_CONFIG_KEYS: &[&str] = &["enabled", "limits", "timeouts", "vhosts"];
|
||||
const WEB_CONFIG_KEYS: &[&str] = &["enabled", "carrier", "limits", "timeouts", "vhosts"];
|
||||
|
||||
const WEB_LIMITS_CONFIG_KEYS: &[&str] = &[
|
||||
"max_header_bytes",
|
||||
|
||||
@@ -59,6 +59,11 @@ pub(super) fn validate(config: &mut ProxyConfig) -> Result<()> {
|
||||
}
|
||||
|
||||
validate_limits(&config.web.limits)?;
|
||||
if config.web.carrier == WebCarrier::HttpsLanes
|
||||
&& config.web.limits.max_http_handlers < 2
|
||||
{
|
||||
return config_error("web.carrier=https-lanes requires web.limits.max_http_handlers >= 2");
|
||||
}
|
||||
validate_timeouts(&config.web.timeouts)?;
|
||||
validate_vhosts(config)?;
|
||||
Ok(())
|
||||
|
||||
@@ -14,6 +14,7 @@ web_trusted_proxy_cidrs = ["127.0.0.1/32"]
|
||||
|
||||
[web]
|
||||
enabled = true
|
||||
carrier = "https-lanes"
|
||||
|
||||
[[web.vhosts]]
|
||||
host = "Proxy.Example.COM"
|
||||
@@ -42,11 +43,22 @@ fn web_config_builds_canonical_runtime_snapshot() {
|
||||
assert_eq!(vhost.profiles.len(), 1);
|
||||
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);
|
||||
}
|
||||
|
||||
#[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.carrier=https-lanes requires"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_listener_requires_an_explicit_trusted_proxy() {
|
||||
let invalid = WEB_CONFIG.replace(
|
||||
@@ -60,8 +72,8 @@ fn web_listener_requires_an_explicit_trusted_proxy() {
|
||||
#[test]
|
||||
fn web_queue_limits_preserve_control_and_uplink_progress() {
|
||||
let invalid = WEB_CONFIG.replace(
|
||||
"[web]\nenabled = true",
|
||||
"[web]\nenabled = true\n\n[web.limits]\ncontrol_bytes_per_session = 1",
|
||||
"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"));
|
||||
@@ -70,9 +82,9 @@ fn web_queue_limits_preserve_control_and_uplink_progress() {
|
||||
#[test]
|
||||
fn web_semaphore_limits_are_rejected_before_runtime_construction() {
|
||||
let invalid = WEB_CONFIG.replace(
|
||||
"[web]\nenabled = true",
|
||||
"carrier = \"https-lanes\"",
|
||||
&format!(
|
||||
"[web]\nenabled = true\n\n[web.limits]\nmax_http_connections = {}",
|
||||
"carrier = \"https-lanes\"\n\n[web.limits]\nmax_http_connections = {}",
|
||||
tokio::sync::Semaphore::MAX_PERMITS + 1,
|
||||
),
|
||||
);
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ pub use server::{
|
||||
};
|
||||
#[allow(unused_imports)]
|
||||
pub use web::{
|
||||
WebConfig, WebDecoyConfig, WebLimitsConfig, WebProfileConfig, WebSecretMode,
|
||||
WebCarrier, WebConfig, WebDecoyConfig, WebLimitsConfig, WebProfileConfig, WebSecretMode,
|
||||
WebTimeoutsConfig, WebVhostConfig,
|
||||
};
|
||||
pub(crate) use web::{
|
||||
|
||||
@@ -16,6 +16,27 @@ pub enum WebSecretMode {
|
||||
Dd,
|
||||
}
|
||||
|
||||
/// HTTP carrier selected for newly issued WEB bridge sessions.
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WebCarrier {
|
||||
/// Serialize all logical streams through one uplink and one downlink sequence.
|
||||
#[default]
|
||||
Https,
|
||||
/// Give every logical stream independent HTTPS sequencing and polling state.
|
||||
HttpsLanes,
|
||||
}
|
||||
|
||||
impl WebCarrier {
|
||||
/// Returns the exact carrier token advertised to the browser bridge.
|
||||
pub(crate) const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Https => "https",
|
||||
Self::HttpsLanes => "https-lanes",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One access user explicitly exposed through a WEB virtual host.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct WebProfileConfig {
|
||||
@@ -273,6 +294,9 @@ pub struct WebConfig {
|
||||
/// Enables issuance of new WEB bridge and session credentials.
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
/// Carrier selected for newly issued WEB bridge sessions.
|
||||
#[serde(default)]
|
||||
pub carrier: WebCarrier,
|
||||
/// Hard process and protocol limits.
|
||||
#[serde(default)]
|
||||
pub limits: WebLimitsConfig,
|
||||
@@ -320,6 +344,8 @@ pub(crate) struct WebRuntimeProfile {
|
||||
pub(crate) user: String,
|
||||
/// Client secret representation and inner protocol policy.
|
||||
pub(crate) secret_mode: WebSecretMode,
|
||||
/// Carrier frozen into bridge and session state at issuance time.
|
||||
pub(crate) carrier: WebCarrier,
|
||||
/// HMAC-derived bridge capability.
|
||||
pub(crate) capability: [u8; 32],
|
||||
/// Per-profile live session ceiling.
|
||||
|
||||
Reference in New Issue
Block a user