mirror of
https://github.com/telemt/telemt.git
synced 2026-09-26 04:25:58 +03:00
Rustfmt
This commit is contained in:
@@ -85,10 +85,7 @@ pub(super) fn push_body(
|
|||||||
html.push_str("</pre>");
|
html.push_str("</pre>");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn push_lifecycle(
|
pub(super) fn push_lifecycle(html: &mut String, event: &crate::web::trace::TraceLifecycleRecord) {
|
||||||
html: &mut String,
|
|
||||||
event: &crate::web::trace::TraceLifecycleRecord,
|
|
||||||
) {
|
|
||||||
html.push_str("<pre>event: ");
|
html.push_str("<pre>event: ");
|
||||||
html.push_str(event.event.as_str());
|
html.push_str(event.event.as_str());
|
||||||
html.push_str("\nstream: ");
|
html.push_str("\nstream: ");
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ pub(super) fn validate(timeouts: &WebTimeoutsConfig) -> Result<()> {
|
|||||||
return config_error("web.timeouts.websocket_open_secs must be within [1, 300]");
|
return config_error("web.timeouts.websocket_open_secs must be within [1, 300]");
|
||||||
}
|
}
|
||||||
if timeouts.lane_open_wait_secs > timeouts.long_poll_secs {
|
if timeouts.lane_open_wait_secs > timeouts.long_poll_secs {
|
||||||
return config_error(
|
return config_error("web.timeouts.lane_open_wait_secs must not exceed long_poll_secs");
|
||||||
"web.timeouts.lane_open_wait_secs must not exceed long_poll_secs",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if timeouts.carrier_health_secs > timeouts.reconnect_grace_secs {
|
if timeouts.carrier_health_secs > timeouts.reconnect_grace_secs {
|
||||||
return config_error(
|
return config_error(
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ fn web_config_builds_canonical_runtime_snapshot() {
|
|||||||
assert_eq!(vhost.profiles[0].key_fingerprint.len(), 16);
|
assert_eq!(vhost.profiles[0].key_fingerprint.len(), 16);
|
||||||
assert_ne!(vhost.profiles[0].key_fingerprint, "0001020304050607");
|
assert_ne!(vhost.profiles[0].key_fingerprint, "0001020304050607");
|
||||||
assert!(!vhost.profiles[0].carrier_negotiation_enabled);
|
assert!(!vhost.profiles[0].carrier_negotiation_enabled);
|
||||||
assert_eq!(vhost.profiles[0].carriers.as_ref(), [WebCarrier::HttpsLanes]);
|
assert_eq!(
|
||||||
|
vhost.profiles[0].carriers.as_ref(),
|
||||||
|
[WebCarrier::HttpsLanes]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -95,11 +98,7 @@ fn web_carrier_array_enables_ordered_negotiation_and_appends_fallback() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn web_carriers_reject_true_empty_and_duplicates() {
|
fn web_carriers_reject_true_empty_and_duplicates() {
|
||||||
for value in [
|
for value in ["true", "[]", "[\"https\", \"https\"]"] {
|
||||||
"true",
|
|
||||||
"[]",
|
|
||||||
"[\"https\", \"https\"]",
|
|
||||||
] {
|
|
||||||
let invalid = WEB_CONFIG.replace(
|
let invalid = WEB_CONFIG.replace(
|
||||||
"carrier = \"https-lanes\"",
|
"carrier = \"https-lanes\"",
|
||||||
&format!("carrier = \"https-lanes\"\ncarriers = {value}"),
|
&format!("carrier = \"https-lanes\"\ncarriers = {value}"),
|
||||||
|
|||||||
+2
-2
@@ -56,12 +56,12 @@ pub use web::{
|
|||||||
WebCarrierNegotiationAggressiveness, WebConfig, WebDecoyConfig, WebLimitsConfig,
|
WebCarrierNegotiationAggressiveness, WebConfig, WebDecoyConfig, WebLimitsConfig,
|
||||||
WebProfileConfig, WebSecretMode, WebTimeoutsConfig, WebVhostConfig,
|
WebProfileConfig, WebSecretMode, WebTimeoutsConfig, WebVhostConfig,
|
||||||
};
|
};
|
||||||
#[allow(unused_imports)]
|
|
||||||
pub use web_carrier::{WebCarrier, WebCarriers};
|
|
||||||
pub(crate) use web::{
|
pub(crate) use web::{
|
||||||
WebRuntimeConfig, WebRuntimeDecoy, WebRuntimeProfile, WebRuntimeVhost, WebStaticAsset,
|
WebRuntimeConfig, WebRuntimeDecoy, WebRuntimeProfile, WebRuntimeVhost, WebStaticAsset,
|
||||||
WebStaticSite,
|
WebStaticSite,
|
||||||
};
|
};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub use web_carrier::{WebCarrier, WebCarriers};
|
||||||
pub(crate) use web_debug::web_debug_fits_limits;
|
pub(crate) use web_debug::web_debug_fits_limits;
|
||||||
pub use web_debug::{WebDebugBodyCapture, WebDebugConfig};
|
pub use web_debug::{WebDebugBodyCapture, WebDebugConfig};
|
||||||
|
|
||||||
|
|||||||
@@ -234,8 +234,7 @@ impl Default for WebLimitsConfig {
|
|||||||
websocket_admission_watermark_pct: default_web_websocket_admission_watermark_pct(),
|
websocket_admission_watermark_pct: default_web_websocket_admission_watermark_pct(),
|
||||||
websocket_eviction_watermark_pct: default_web_websocket_eviction_watermark_pct(),
|
websocket_eviction_watermark_pct: default_web_websocket_eviction_watermark_pct(),
|
||||||
websocket_http_connection_reserve: default_web_websocket_http_connection_reserve(),
|
websocket_http_connection_reserve: default_web_websocket_http_connection_reserve(),
|
||||||
max_websocket_evictions_in_flight:
|
max_websocket_evictions_in_flight: default_web_max_websocket_evictions_in_flight(),
|
||||||
default_web_max_websocket_evictions_in_flight(),
|
|
||||||
max_carrier_learning_entries: default_web_max_carrier_learning_entries(),
|
max_carrier_learning_entries: default_web_max_carrier_learning_entries(),
|
||||||
max_body_readers: default_web_max_body_readers(),
|
max_body_readers: default_web_max_body_readers(),
|
||||||
max_body_bytes_global: default_web_max_body_bytes_global(),
|
max_body_bytes_global: default_web_max_body_bytes_global(),
|
||||||
@@ -348,8 +347,7 @@ impl Default for WebTimeoutsConfig {
|
|||||||
websocket_write_secs: default_web_websocket_write_secs(),
|
websocket_write_secs: default_web_websocket_write_secs(),
|
||||||
websocket_backpressure_secs: default_web_websocket_backpressure_secs(),
|
websocket_backpressure_secs: default_web_websocket_backpressure_secs(),
|
||||||
websocket_eviction_secs: default_web_websocket_eviction_secs(),
|
websocket_eviction_secs: default_web_websocket_eviction_secs(),
|
||||||
carrier_negotiation_deadlines_secs:
|
carrier_negotiation_deadlines_secs: default_web_carrier_negotiation_deadlines_secs(),
|
||||||
default_web_carrier_negotiation_deadlines_secs(),
|
|
||||||
carrier_learning_secs: default_web_carrier_learning_secs(),
|
carrier_learning_secs: default_web_carrier_learning_secs(),
|
||||||
bootstrap_lifetime_secs: default_web_bootstrap_lifetime_secs(),
|
bootstrap_lifetime_secs: default_web_bootstrap_lifetime_secs(),
|
||||||
reconnect_grace_secs: default_web_reconnect_grace_secs(),
|
reconnect_grace_secs: default_web_reconnect_grace_secs(),
|
||||||
@@ -436,8 +434,7 @@ impl Default for WebConfig {
|
|||||||
carrier: WebCarrier::default(),
|
carrier: WebCarrier::default(),
|
||||||
carriers: WebCarriers::default(),
|
carriers: WebCarriers::default(),
|
||||||
carrier_learning: default_web_carrier_learning(),
|
carrier_learning: default_web_carrier_learning(),
|
||||||
carrier_negotiation_aggressiveness:
|
carrier_negotiation_aggressiveness: WebCarrierNegotiationAggressiveness::default(),
|
||||||
WebCarrierNegotiationAggressiveness::default(),
|
|
||||||
limits: WebLimitsConfig::default(),
|
limits: WebLimitsConfig::default(),
|
||||||
debug: WebDebugConfig::default(),
|
debug: WebDebugConfig::default(),
|
||||||
timeouts: WebTimeoutsConfig::default(),
|
timeouts: WebTimeoutsConfig::default(),
|
||||||
|
|||||||
+26
-22
@@ -16,10 +16,7 @@ fn render_page(bootstrap: &str, candidate_count: usize) -> BridgePage {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rendered_page_contains_bounded_negotiation_contract() {
|
fn rendered_page_contains_bounded_negotiation_contract() {
|
||||||
let page = render_page(
|
let page = render_page("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 4);
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
||||||
4,
|
|
||||||
);
|
|
||||||
assert!(!page.body.contains("__"));
|
assert!(!page.body.contains("__"));
|
||||||
assert!(!page.body.contains("bridge="));
|
assert!(!page.body.contains("bridge="));
|
||||||
assert!(page.body.contains("X-Carrier-Capabilities"));
|
assert!(page.body.contains("X-Carrier-Capabilities"));
|
||||||
@@ -40,17 +37,23 @@ fn rendered_page_contains_bounded_negotiation_contract() {
|
|||||||
fn rendered_page_preserves_the_ios_bootstrap_literal() {
|
fn rendered_page_preserves_the_ios_bootstrap_literal() {
|
||||||
let bootstrap = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
|
let bootstrap = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
|
||||||
let page = render_page(bootstrap, 2);
|
let page = render_page(bootstrap, 2);
|
||||||
assert!(page.body.contains(&format!("const bootstrap=\"{bootstrap}\"")));
|
assert!(
|
||||||
|
page.body
|
||||||
|
.contains(&format!("const bootstrap=\"{bootstrap}\""))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn effective_deadline_formula_uses_the_final_checkpoint() {
|
fn effective_deadline_formula_uses_the_final_checkpoint() {
|
||||||
let page = render_page(
|
let page = render_page("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", 3);
|
||||||
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
|
assert!(
|
||||||
3,
|
page.body
|
||||||
|
.contains("negotiatedFinalDeadline=candidateDeadlines[3]")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
page.body
|
||||||
|
.contains("carrierAttempt>=negotiatedCandidateCount?negotiatedFinalDeadline")
|
||||||
);
|
);
|
||||||
assert!(page.body.contains("negotiatedFinalDeadline=candidateDeadlines[3]"));
|
|
||||||
assert!(page.body.contains("carrierAttempt>=negotiatedCandidateCount?negotiatedFinalDeadline"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -69,18 +72,19 @@ fn disabled_negotiation_does_not_arm_a_carrier_deadline() {
|
|||||||
assert!(page.body.contains(
|
assert!(page.body.contains(
|
||||||
"if(negotiationEnabled){negotiationStartedAt=Date.now();armCarrierDeadline(attemptEpoch)}"
|
"if(negotiationEnabled){negotiationStartedAt=Date.now();armCarrierDeadline(attemptEpoch)}"
|
||||||
));
|
));
|
||||||
assert!(page.body.contains(
|
assert!(
|
||||||
"negotiationEnabled?'tproxy-auto-v1.':'tproxy-v1.'"
|
page.body
|
||||||
));
|
.contains("negotiationEnabled?'tproxy-auto-v1.':'tproxy-v1.'")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn retry_and_attempt_state_are_frozen_before_fetch() {
|
fn retry_and_attempt_state_are_frozen_before_fetch() {
|
||||||
let page = render_page(
|
let page = render_page("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", 4);
|
||||||
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
|
assert!(
|
||||||
4,
|
page.body
|
||||||
|
.contains("async function request(path,frozenOptions)")
|
||||||
);
|
);
|
||||||
assert!(page.body.contains("async function request(path,frozenOptions)"));
|
|
||||||
assert!(!page.body.contains("makeOptions"));
|
assert!(!page.body.contains("makeOptions"));
|
||||||
assert!(
|
assert!(
|
||||||
page.body
|
page.body
|
||||||
@@ -93,14 +97,14 @@ fn retry_and_attempt_state_are_frozen_before_fetch() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ambiguous_commit_is_resolved_before_carrier_advance() {
|
fn ambiguous_commit_is_resolved_before_carrier_advance() {
|
||||||
let page = render_page(
|
let page = render_page("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 4);
|
||||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
|
||||||
4,
|
|
||||||
);
|
|
||||||
assert!(page.body.contains("resolveAttempt(reason,epoch,snapshot)"));
|
assert!(page.body.contains("resolveAttempt(reason,epoch,snapshot)"));
|
||||||
assert!(page.body.contains(
|
assert!(page.body.contains(
|
||||||
"sessionEcho(response,snapshot.attempt,['provisional','committed','healthy'],true)"
|
"sessionEcho(response,snapshot.attempt,['provisional','committed','healthy'],true)"
|
||||||
));
|
));
|
||||||
assert!(page.body.contains("if(echo.state!=='provisional'){switching=false;fail();return}"));
|
assert!(
|
||||||
|
page.body
|
||||||
|
.contains("if(echo.state!=='provisional'){switching=false;fail();return}")
|
||||||
|
);
|
||||||
assert!(page.body.contains("const token=cleanupToken||sessionToken"));
|
assert!(page.body.contains("const token=cleanupToken||sessionToken"));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -356,11 +356,7 @@ async fn handle_up(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(trace) = request_trace(&request) {
|
if let Some(trace) = request_trace(&request) {
|
||||||
trace.record_frames(
|
trace.record_frames(TraceDirection::Request, &body, session.limits());
|
||||||
TraceDirection::Request,
|
|
||||||
&body,
|
|
||||||
session.limits(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let result = match lane_id {
|
let result = match lane_id {
|
||||||
Some(lane_id) => session.process_up_lane(lane_id, sequence, &body),
|
Some(lane_id) => session.process_up_lane(lane_id, sequence, &body),
|
||||||
|
|||||||
@@ -89,11 +89,7 @@ pub(super) async fn handle_down(
|
|||||||
}
|
}
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if let Some(trace) = request_trace(&request) {
|
if let Some(trace) = request_trace(&request) {
|
||||||
trace.record_frames(
|
trace.record_frames(TraceDirection::Response, &result.body, session.limits());
|
||||||
TraceDirection::Response,
|
|
||||||
&result.body,
|
|
||||||
session.limits(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let mut response = full_response(StatusCode::OK, result.body);
|
let mut response = full_response(StatusCode::OK, result.body);
|
||||||
carrier_headers(&mut response);
|
carrier_headers(&mut response);
|
||||||
|
|||||||
@@ -130,13 +130,7 @@ async fn metadata_free_native_client_can_use_each_fixed_carrier() {
|
|||||||
let response = request(
|
let response = request(
|
||||||
&listener,
|
&listener,
|
||||||
&runtime,
|
&runtime,
|
||||||
create_request_with_headers(
|
create_request_with_headers(&bootstrap, &hello, None, None, NATIVE_USER_AGENT_HEADER),
|
||||||
&bootstrap,
|
|
||||||
&hello,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
NATIVE_USER_AGENT_HEADER,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let (headers, _) = split_response(&response);
|
let (headers, _) = split_response(&response);
|
||||||
@@ -170,13 +164,7 @@ async fn metadata_free_native_client_uses_fallback_when_candidates_are_enabled()
|
|||||||
let response = request(
|
let response = request(
|
||||||
&listener,
|
&listener,
|
||||||
&runtime,
|
&runtime,
|
||||||
create_request_with_headers(
|
create_request_with_headers(&bootstrap, &hello, None, None, NATIVE_USER_AGENT_HEADER),
|
||||||
&bootstrap,
|
|
||||||
&hello,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
NATIVE_USER_AGENT_HEADER,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let (headers, _) = split_response(&response);
|
let (headers, _) = split_response(&response);
|
||||||
@@ -209,13 +197,7 @@ async fn explicit_native_capabilities_participate_in_automatic_selection() {
|
|||||||
let response = request(
|
let response = request(
|
||||||
&listener,
|
&listener,
|
||||||
&runtime,
|
&runtime,
|
||||||
create_request_with_headers(
|
create_request_with_headers(&bootstrap, &hello, Some(1), None, NATIVE_USER_AGENT_HEADER),
|
||||||
&bootstrap,
|
|
||||||
&hello,
|
|
||||||
Some(1),
|
|
||||||
None,
|
|
||||||
NATIVE_USER_AGENT_HEADER,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let (headers, _) = split_response(&response);
|
let (headers, _) = split_response(&response);
|
||||||
@@ -261,9 +243,18 @@ async fn negotiation_replays_replaces_and_freezes_after_carrier_commit() {
|
|||||||
|
|
||||||
let replay = request(&listener, &runtime, first_request).await;
|
let replay = request(&listener, &runtime, first_request).await;
|
||||||
let (replay_headers, _) = split_response(&replay);
|
let (replay_headers, _) = split_response(&replay);
|
||||||
assert_eq!(response_header(replay_headers, "x-session-token"), first_token);
|
assert_eq!(
|
||||||
assert_eq!(response_header(replay_headers, "x-carrier-candidate-count"), "3");
|
response_header(replay_headers, "x-session-token"),
|
||||||
assert_eq!(response_header(replay_headers, "x-carrier-state"), "provisional");
|
first_token
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
response_header(replay_headers, "x-carrier-candidate-count"),
|
||||||
|
"3"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
response_header(replay_headers, "x-carrier-state"),
|
||||||
|
"provisional"
|
||||||
|
);
|
||||||
|
|
||||||
let second_request = create_request(&bootstrap, &hello, Some(2), Some("timeout"));
|
let second_request = create_request(&bootstrap, &hello, Some(2), Some("timeout"));
|
||||||
let second = request(&listener, &runtime, second_request.clone()).await;
|
let second = request(&listener, &runtime, second_request.clone()).await;
|
||||||
@@ -346,11 +337,20 @@ async fn negotiation_replays_replaces_and_freezes_after_carrier_commit() {
|
|||||||
let (third_headers, _) = split_response(&third);
|
let (third_headers, _) = split_response(&third);
|
||||||
assert!(third_headers.starts_with(b"HTTP/1.1 409"));
|
assert!(third_headers.starts_with(b"HTTP/1.1 409"));
|
||||||
assert!(optional_response_header(third_headers, "x-session-token").is_none());
|
assert!(optional_response_header(third_headers, "x-session-token").is_none());
|
||||||
assert_eq!(response_header(third_headers, "x-carrier-mode"), "https-lanes");
|
assert_eq!(
|
||||||
|
response_header(third_headers, "x-carrier-mode"),
|
||||||
|
"https-lanes"
|
||||||
|
);
|
||||||
assert_eq!(response_header(third_headers, "x-carrier-attempt"), "2");
|
assert_eq!(response_header(third_headers, "x-carrier-attempt"), "2");
|
||||||
assert_eq!(response_header(third_headers, "x-carrier-candidate-count"), "3");
|
assert_eq!(
|
||||||
|
response_header(third_headers, "x-carrier-candidate-count"),
|
||||||
|
"3"
|
||||||
|
);
|
||||||
assert_eq!(response_header(third_headers, "x-carrier-deadline"), "12");
|
assert_eq!(response_header(third_headers, "x-carrier-deadline"), "12");
|
||||||
assert_eq!(response_header(third_headers, "x-carrier-state"), "committed");
|
assert_eq!(
|
||||||
|
response_header(third_headers, "x-carrier-state"),
|
||||||
|
"committed"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
runtime
|
runtime
|
||||||
.get_session(token_hash(&second_token), "proxy.example.com")
|
.get_session(token_hash(&second_token), "proxy.example.com")
|
||||||
@@ -397,7 +397,10 @@ async fn timed_out_attempt_replays_before_successor_own_deadline() {
|
|||||||
response_header(replay_headers, "x-session-token"),
|
response_header(replay_headers, "x-session-token"),
|
||||||
first_token
|
first_token
|
||||||
);
|
);
|
||||||
assert_eq!(response_header(replay_headers, "x-carrier-state"), "provisional");
|
assert_eq!(
|
||||||
|
response_header(replay_headers, "x-carrier-state"),
|
||||||
|
"provisional"
|
||||||
|
);
|
||||||
|
|
||||||
let second = request(
|
let second = request(
|
||||||
&listener,
|
&listener,
|
||||||
@@ -453,9 +456,8 @@ async fn https_lane_downlink_can_arrive_before_its_uplink_open() {
|
|||||||
.into_bytes();
|
.into_bytes();
|
||||||
let down_listener = Arc::clone(&listener);
|
let down_listener = Arc::clone(&listener);
|
||||||
let down_runtime = Arc::clone(&runtime);
|
let down_runtime = Arc::clone(&runtime);
|
||||||
let down = tokio::spawn(async move {
|
let down =
|
||||||
request(&down_listener, &down_runtime, down_request).await
|
tokio::spawn(async move { request(&down_listener, &down_runtime, down_request).await });
|
||||||
});
|
|
||||||
tokio::task::yield_now().await;
|
tokio::task::yield_now().await;
|
||||||
|
|
||||||
let open = frame::encode(FrameType::Open, 7, &[]);
|
let open = frame::encode(FrameType::Open, 7, &[]);
|
||||||
@@ -477,10 +479,7 @@ async fn https_lane_downlink_can_arrive_before_its_uplink_open() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (down_headers, _) = split_response(&down);
|
let (down_headers, _) = split_response(&down);
|
||||||
assert!(
|
assert!(down_headers.starts_with(b"HTTP/1.1 200") || down_headers.starts_with(b"HTTP/1.1 204"));
|
||||||
down_headers.starts_with(b"HTTP/1.1 200")
|
|
||||||
|| down_headers.starts_with(b"HTTP/1.1 204")
|
|
||||||
);
|
|
||||||
assert!(optional_response_header(down_headers, "x-down-cursor").is_some());
|
assert!(optional_response_header(down_headers, "x-down-cursor").is_some());
|
||||||
|
|
||||||
runtime.shutdown().await;
|
runtime.shutdown().await;
|
||||||
|
|||||||
+8
-15
@@ -15,9 +15,7 @@ const USER_AGENT_CONTEXT: &[u8] = b"telemt-web-carrier-user-agent-v1\0";
|
|||||||
|
|
||||||
// Canonical host and forwarded-address provenance remain isolated from credentials.
|
// Canonical host and forwarded-address provenance remain isolated from credentials.
|
||||||
mod identity;
|
mod identity;
|
||||||
pub(super) use identity::{
|
pub(super) use identity::{canonical_request_host, carrier_ip_learning_eligible, client_ip};
|
||||||
canonical_request_host, carrier_ip_learning_eligible, client_ip,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Decodes an exact canonical bridge query without allocating credential strings.
|
/// Decodes an exact canonical bridge query without allocating credential strings.
|
||||||
pub(super) fn bridge_candidate(query: Option<&str>) -> ([u8; 32], bool) {
|
pub(super) fn bridge_candidate(query: Option<&str>) -> ([u8; 32], bool) {
|
||||||
@@ -205,17 +203,13 @@ fn parse_capabilities(value: &str) -> Option<CarrierCapabilities> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn strict_browser_hint<B>(request: &Request<B>, host: &str) -> bool {
|
fn strict_browser_hint<B>(request: &Request<B>, host: &str) -> bool {
|
||||||
single_header(request, header::ORIGIN)
|
single_header(request, header::ORIGIN).is_some_and(|value| value == format!("https://{host}"))
|
||||||
.is_some_and(|value| value == format!("https://{host}"))
|
|
||||||
&& single_header(request, "sec-fetch-site") == Some("same-origin")
|
&& single_header(request, "sec-fetch-site") == Some("same-origin")
|
||||||
&& single_header(request, "sec-fetch-mode") == Some("cors")
|
&& single_header(request, "sec-fetch-mode") == Some("cors")
|
||||||
&& single_header(request, "sec-fetch-dest") == Some("empty")
|
&& single_header(request, "sec-fetch-dest") == Some("empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optional_canonical_u8_header<B>(
|
fn optional_canonical_u8_header<B>(request: &Request<B>, name: &'static str) -> Option<Option<u8>> {
|
||||||
request: &Request<B>,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Option<Option<u8>> {
|
|
||||||
if !request.headers().contains_key(name) {
|
if !request.headers().contains_key(name) {
|
||||||
return Some(None);
|
return Some(None);
|
||||||
}
|
}
|
||||||
@@ -452,9 +446,11 @@ mod tests {
|
|||||||
.header(header::USER_AGENT, "Native")
|
.header(header::USER_AGENT, "Native")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(!carrier_request(&legacy, "proxy.example.com")
|
assert!(
|
||||||
|
!carrier_request(&legacy, "proxy.example.com")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_automatic());
|
.is_automatic()
|
||||||
|
);
|
||||||
|
|
||||||
let reordered = Request::builder()
|
let reordered = Request::builder()
|
||||||
.header("x-carrier-capabilities", "websocket,https")
|
.header("x-carrier-capabilities", "websocket,https")
|
||||||
@@ -479,10 +475,7 @@ mod tests {
|
|||||||
assert!(!parsed.uses_capabilities());
|
assert!(!parsed.uses_capabilities());
|
||||||
|
|
||||||
let automatic = Request::builder()
|
let automatic = Request::builder()
|
||||||
.header(
|
.header("x-carrier-capabilities", "https,https-lanes")
|
||||||
"x-carrier-capabilities",
|
|
||||||
"https,https-lanes",
|
|
||||||
)
|
|
||||||
.header("x-carrier-attempt", "1")
|
.header("x-carrier-attempt", "1")
|
||||||
.header(
|
.header(
|
||||||
header::USER_AGENT,
|
header::USER_AGENT,
|
||||||
|
|||||||
@@ -152,12 +152,9 @@ pub(super) async fn handle_session(
|
|||||||
}
|
}
|
||||||
Err(ManagerError::Committed) => {
|
Err(ManagerError::Committed) => {
|
||||||
let mut response = carrier_empty(StatusCode::CONFLICT);
|
let mut response = carrier_empty(StatusCode::CONFLICT);
|
||||||
if let Some(echo) = runtime.carrier_echo(
|
if let Some(echo) =
|
||||||
token_hash,
|
runtime.carrier_echo(token_hash, &vhost.host, client_ip, carrier_request)
|
||||||
&vhost.host,
|
{
|
||||||
client_ip,
|
|
||||||
carrier_request,
|
|
||||||
) {
|
|
||||||
response.headers_mut().insert(
|
response.headers_mut().insert(
|
||||||
HeaderName::from_static("x-carrier-mode"),
|
HeaderName::from_static("x-carrier-mode"),
|
||||||
HeaderValue::from_static(echo.carrier.as_str()),
|
HeaderValue::from_static(echo.carrier.as_str()),
|
||||||
|
|||||||
@@ -134,8 +134,7 @@ fn runtime_config_with_carriers_and_deadlines(
|
|||||||
WebCarriers::Disabled
|
WebCarriers::Disabled
|
||||||
};
|
};
|
||||||
config.web.carrier_learning = carrier_learning;
|
config.web.carrier_learning = carrier_learning;
|
||||||
config.web.timeouts.carrier_negotiation_deadlines_secs =
|
config.web.timeouts.carrier_negotiation_deadlines_secs = carrier_negotiation_deadlines_secs;
|
||||||
carrier_negotiation_deadlines_secs;
|
|
||||||
config.web.limits.max_bootstraps_per_ip = 1;
|
config.web.limits.max_bootstraps_per_ip = 1;
|
||||||
config.web.timeouts.shutdown_secs = 1;
|
config.web.timeouts.shutdown_secs = 1;
|
||||||
config.web.runtime = Some(Arc::new(WebRuntimeConfig {
|
config.web.runtime = Some(Arc::new(WebRuntimeConfig {
|
||||||
@@ -260,9 +259,11 @@ async fn https_carrier_bootstraps_and_closes_one_session() {
|
|||||||
.windows(11)
|
.windows(11)
|
||||||
.any(|value| value == b"bootstrap=\"")
|
.any(|value| value == b"bootstrap=\"")
|
||||||
);
|
);
|
||||||
assert!(next_root_body
|
assert!(
|
||||||
|
next_root_body
|
||||||
.windows(b"const negotiationEnabled=false".len())
|
.windows(b"const negotiationEnabled=false".len())
|
||||||
.any(|value| value == b"const negotiationEnabled=false"));
|
.any(|value| value == b"const negotiationEnabled=false")
|
||||||
|
);
|
||||||
|
|
||||||
let close = format!(
|
let close = format!(
|
||||||
"DELETE /api/v1/session HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\nAuthorization: Bearer {session}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
"DELETE /api/v1/session HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\nAuthorization: Bearer {session}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
||||||
|
|||||||
@@ -389,9 +389,8 @@ fn parse_upgrade<B>(request: &Request<B>) -> Option<ParsedUpgrade> {
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (token, carrier, acknowledge_commit) = if let Some(token) =
|
let (token, carrier, acknowledge_commit) =
|
||||||
protocol.strip_prefix("tproxy-auto-v1.")
|
if let Some(token) = protocol.strip_prefix("tproxy-auto-v1.") {
|
||||||
{
|
|
||||||
(token, ParsedCarrier::Multiplex, true)
|
(token, ParsedCarrier::Multiplex, true)
|
||||||
} else if let Some(lane) = protocol.strip_prefix("tproxy-auto-lane-v1.") {
|
} else if let Some(lane) = protocol.strip_prefix("tproxy-auto-lane-v1.") {
|
||||||
let (token, lane_id) = parse_lane_protocol(lane)?;
|
let (token, lane_id) = parse_lane_protocol(lane)?;
|
||||||
@@ -441,10 +440,7 @@ fn parse_lane_protocol(value: &str) -> Option<(&str, u32)> {
|
|||||||
Some((token, lane_id))
|
Some((token, lane_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_header<B>(
|
fn single_header<B>(request: &Request<B>, name: impl hyper::header::AsHeaderName) -> Option<&str> {
|
||||||
request: &Request<B>,
|
|
||||||
name: impl hyper::header::AsHeaderName,
|
|
||||||
) -> Option<&str> {
|
|
||||||
let mut values = request.headers().get_all(name).iter();
|
let mut values = request.headers().get_all(name).iter();
|
||||||
let value = values.next()?.to_str().ok()?;
|
let value = values.next()?.to_str().ok()?;
|
||||||
values.next().is_none().then_some(value)
|
values.next().is_none().then_some(value)
|
||||||
|
|||||||
@@ -8,12 +8,8 @@ use tokio_tungstenite::tungstenite::protocol::{Message, Role, WebSocketConfig};
|
|||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use super::ConnectionIo;
|
use super::ConnectionIo;
|
||||||
use crate::web::manager::{
|
use crate::web::manager::{WebProcessRuntime, WebSocketBudgetLease, WebSocketConnection};
|
||||||
WebProcessRuntime, WebSocketBudgetLease, WebSocketConnection,
|
use crate::web::session::{WebSession, WebSocketLaneReservation, WebSocketProbeReservation};
|
||||||
};
|
|
||||||
use crate::web::session::{
|
|
||||||
WebSession, WebSocketLaneReservation, WebSocketProbeReservation,
|
|
||||||
};
|
|
||||||
use crate::web::trace::{TraceDirection, TraceWebSocketContext};
|
use crate::web::trace::{TraceDirection, TraceWebSocketContext};
|
||||||
|
|
||||||
const READ_BUFFER_BYTES: usize = 64 * 1024;
|
const READ_BUFFER_BYTES: usize = 64 * 1024;
|
||||||
@@ -126,8 +122,7 @@ async fn run_multiplex(
|
|||||||
let mut next_ping = Instant::now() + liveness_interval;
|
let mut next_ping = Instant::now() + liveness_interval;
|
||||||
let open_deadline =
|
let open_deadline =
|
||||||
Instant::now() + Duration::from_secs(session.timeouts().websocket_open_secs);
|
Instant::now() + Duration::from_secs(session.timeouts().websocket_open_secs);
|
||||||
let backpressure_timeout =
|
let backpressure_timeout = Duration::from_secs(session.timeouts().websocket_backpressure_secs);
|
||||||
Duration::from_secs(session.timeouts().websocket_backpressure_secs);
|
|
||||||
let write_timeout = Duration::from_secs(session.timeouts().websocket_write_secs);
|
let write_timeout = Duration::from_secs(session.timeouts().websocket_write_secs);
|
||||||
let maximum_message = session.limits().carrier_batch_bytes;
|
let maximum_message = session.limits().carrier_batch_bytes;
|
||||||
let mut active = false;
|
let mut active = false;
|
||||||
@@ -317,13 +312,7 @@ async fn run_multiplex(
|
|||||||
started,
|
started,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
send(
|
send(socket, Message::Binary(body), &cancellation, write_timeout).await?;
|
||||||
socket,
|
|
||||||
Message::Binary(body),
|
|
||||||
&cancellation,
|
|
||||||
write_timeout,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
connection.mark_progress();
|
connection.mark_progress();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,16 +24,8 @@ pub(super) async fn read_message(
|
|||||||
ready = socket.get_ref().readable() => ready.map_err(|_| ())?,
|
ready = socket.get_ref().readable() => ready.map_err(|_| ())?,
|
||||||
}
|
}
|
||||||
if retained_budget.is_none() {
|
if retained_budget.is_none() {
|
||||||
*retained_budget = Some(
|
*retained_budget =
|
||||||
reserve_data(
|
Some(reserve_data(runtime, owner, maximum, cancellation, backpressure_timeout).await?);
|
||||||
runtime,
|
|
||||||
owner,
|
|
||||||
maximum,
|
|
||||||
cancellation,
|
|
||||||
backpressure_timeout,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let message = tokio::select! {
|
let message = tokio::select! {
|
||||||
_ = cancellation.cancelled() => return Err(()),
|
_ = cancellation.cancelled() => return Err(()),
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ use tokio_util::sync::CancellationToken;
|
|||||||
|
|
||||||
use super::CarrierSocket;
|
use super::CarrierSocket;
|
||||||
use super::io::{flush, process_lane, read_message, record_message, reserve_data, send};
|
use super::io::{flush, process_lane, read_message, record_message, reserve_data, send};
|
||||||
use crate::web::manager::{
|
use crate::web::manager::{WebProcessRuntime, WebSocketBudgetLease, WebSocketConnection};
|
||||||
WebProcessRuntime, WebSocketBudgetLease, WebSocketConnection,
|
|
||||||
};
|
|
||||||
use crate::web::session::{WebSession, WebSocketLaneReservation};
|
use crate::web::session::{WebSession, WebSocketLaneReservation};
|
||||||
use crate::web::trace::{TraceDirection, TraceWebSocketContext};
|
use crate::web::trace::{TraceDirection, TraceWebSocketContext};
|
||||||
|
|
||||||
@@ -32,8 +30,7 @@ pub(super) async fn run_lane(
|
|||||||
let mut next_ping = Instant::now() + liveness_interval;
|
let mut next_ping = Instant::now() + liveness_interval;
|
||||||
let open_deadline =
|
let open_deadline =
|
||||||
Instant::now() + Duration::from_secs(session.timeouts().websocket_open_secs);
|
Instant::now() + Duration::from_secs(session.timeouts().websocket_open_secs);
|
||||||
let backpressure_timeout =
|
let backpressure_timeout = Duration::from_secs(session.timeouts().websocket_backpressure_secs);
|
||||||
Duration::from_secs(session.timeouts().websocket_backpressure_secs);
|
|
||||||
let write_timeout = Duration::from_secs(session.timeouts().websocket_write_secs);
|
let write_timeout = Duration::from_secs(session.timeouts().websocket_write_secs);
|
||||||
let maximum_message = session.limits().carrier_batch_bytes;
|
let maximum_message = session.limits().carrier_batch_bytes;
|
||||||
let mut active = false;
|
let mut active = false;
|
||||||
@@ -232,13 +229,7 @@ pub(super) async fn run_lane(
|
|||||||
started,
|
started,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
send(
|
send(socket, Message::Binary(body), &cancellation, write_timeout).await?;
|
||||||
socket,
|
|
||||||
Message::Binary(body),
|
|
||||||
&cancellation,
|
|
||||||
write_timeout,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
connection.mark_progress();
|
connection.mark_progress();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,8 +452,7 @@ async fn failed_automatic_multiplex_socket_remains_supersedable() {
|
|||||||
Arc::from([WebCarrier::Websocket, WebCarrier::Https]),
|
Arc::from([WebCarrier::Websocket, WebCarrier::Https]),
|
||||||
);
|
);
|
||||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||||
let (bootstrap_hash, hello, session, session_hash) =
|
let (bootstrap_hash, hello, session, session_hash) = create_automatic_session(&live.runtime);
|
||||||
create_automatic_session(&live.runtime);
|
|
||||||
let protocol = format!("tproxy-auto-v1.{session}");
|
let protocol = format!("tproxy-auto-v1.{session}");
|
||||||
let mut socket = upgrade(&listener, &live.runtime, &protocol).await;
|
let mut socket = upgrade(&listener, &live.runtime, &protocol).await;
|
||||||
socket.close(None).await.unwrap();
|
socket.close(None).await.unwrap();
|
||||||
|
|||||||
+2
-5
@@ -39,10 +39,10 @@ mod budget;
|
|||||||
mod websocket;
|
mod websocket;
|
||||||
pub(crate) use budget::WebSocketBudgetLease;
|
pub(crate) use budget::WebSocketBudgetLease;
|
||||||
use budget::{WebDataBudget, WebSocketBudgetClass};
|
use budget::{WebDataBudget, WebSocketBudgetClass};
|
||||||
use state::{ManagerState, StreamAdmissionState};
|
|
||||||
pub(crate) use negotiation::{
|
pub(crate) use negotiation::{
|
||||||
CarrierCapabilities, CarrierClientClass, CarrierFailure, CarrierLearningContext, CarrierRequest,
|
CarrierCapabilities, CarrierClientClass, CarrierFailure, CarrierLearningContext, CarrierRequest,
|
||||||
};
|
};
|
||||||
|
use state::{ManagerState, StreamAdmissionState};
|
||||||
pub(crate) use websocket::{WebSocketConnection, WebSocketKind};
|
pub(crate) use websocket::{WebSocketConnection, WebSocketKind};
|
||||||
|
|
||||||
const TOKEN_BYTES: usize = 32;
|
const TOKEN_BYTES: usize = 32;
|
||||||
@@ -327,10 +327,7 @@ impl WebProcessRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reserves transient bytes while one downlink batch replaces queued frames.
|
/// Reserves transient bytes while one downlink batch replaces queued frames.
|
||||||
pub(crate) fn try_downlink_staging_budget(
|
pub(crate) fn try_downlink_staging_budget(&self, bytes: usize) -> Option<OwnedSemaphorePermit> {
|
||||||
&self,
|
|
||||||
bytes: usize,
|
|
||||||
) -> Option<OwnedSemaphorePermit> {
|
|
||||||
let bytes = u32::try_from(bytes).ok()?;
|
let bytes = u32::try_from(bytes).ok()?;
|
||||||
let permit = Arc::clone(&self.body_bytes)
|
let permit = Arc::clone(&self.body_bytes)
|
||||||
.try_acquire_many_owned(bytes)
|
.try_acquire_many_owned(bytes)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
use super::negotiation::{CarrierClientClass, CarrierLearningContext};
|
|
||||||
use super::ProfileKey;
|
use super::ProfileKey;
|
||||||
|
use super::negotiation::{CarrierClientClass, CarrierLearningContext};
|
||||||
use crate::config::{WebCarrier, WebCarrierNegotiationAggressiveness};
|
use crate::config::{WebCarrier, WebCarrierNegotiationAggressiveness};
|
||||||
|
|
||||||
const PROFILE_WEIGHT: i16 = 32;
|
const PROFILE_WEIGHT: i16 = 32;
|
||||||
@@ -85,9 +85,7 @@ impl Evidence {
|
|||||||
}
|
}
|
||||||
aggregate.outcomes = aggregate.outcomes.saturating_add(bucket.outcomes);
|
aggregate.outcomes = aggregate.outcomes.saturating_add(bucket.outcomes);
|
||||||
for (score, value) in aggregate.scores.iter_mut().zip(bucket.scores) {
|
for (score, value) in aggregate.scores.iter_mut().zip(bucket.scores) {
|
||||||
*score = score
|
*score = score.saturating_add(value).clamp(SCORE_MIN, SCORE_MAX);
|
||||||
.saturating_add(value)
|
|
||||||
.clamp(SCORE_MIN, SCORE_MAX);
|
|
||||||
}
|
}
|
||||||
for cohort in bucket.cohorts.iter().flatten() {
|
for cohort in bucket.cohorts.iter().flatten() {
|
||||||
if !aggregate.cohorts.contains(&Some(*cohort))
|
if !aggregate.cohorts.contains(&Some(*cohort))
|
||||||
@@ -262,10 +260,9 @@ impl CarrierLearning {
|
|||||||
let user_agent_ready = user_agent
|
let user_agent_ready = user_agent
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|entry| entry.outcomes >= thresholds.user_agent);
|
.is_some_and(|entry| entry.outcomes >= thresholds.user_agent);
|
||||||
let ip_ready = thresholds.ip.is_some_and(|minimum| {
|
let ip_ready = thresholds
|
||||||
ip.as_ref()
|
.ip
|
||||||
.is_some_and(|entry| entry.outcomes >= minimum)
|
.is_some_and(|minimum| ip.as_ref().is_some_and(|entry| entry.outcomes >= minimum));
|
||||||
});
|
|
||||||
let mut scores = [0i16; 4];
|
let mut scores = [0i16; 4];
|
||||||
for carrier in WebCarrier::ALL {
|
for carrier in WebCarrier::ALL {
|
||||||
let index = carrier.index();
|
let index = carrier.index();
|
||||||
@@ -274,11 +271,9 @@ impl CarrierLearning {
|
|||||||
* PROFILE_WEIGHT;
|
* PROFILE_WEIGHT;
|
||||||
}
|
}
|
||||||
if user_agent_ready {
|
if user_agent_ready {
|
||||||
scores[index] += i16::from(
|
scores[index] +=
|
||||||
user_agent
|
i16::from(user_agent.as_ref().map_or(0, |value| value.scores[index]))
|
||||||
.as_ref()
|
* USER_AGENT_WEIGHT;
|
||||||
.map_or(0, |value| value.scores[index]),
|
|
||||||
) * USER_AGENT_WEIGHT;
|
|
||||||
}
|
}
|
||||||
if ip_ready {
|
if ip_ready {
|
||||||
scores[index] +=
|
scores[index] +=
|
||||||
@@ -362,7 +357,11 @@ impl CarrierLearning {
|
|||||||
if !current {
|
if !current {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if self.entries.get(&key).is_some_and(|entry| entry.is_live(slot)) {
|
if self
|
||||||
|
.entries
|
||||||
|
.get(&key)
|
||||||
|
.is_some_and(|entry| entry.is_live(slot))
|
||||||
|
{
|
||||||
self.insertion_order.push_back((key, sequence));
|
self.insertion_order.push_back((key, sequence));
|
||||||
} else {
|
} else {
|
||||||
self.entries.remove(&key);
|
self.entries.remove(&key);
|
||||||
@@ -411,8 +410,7 @@ impl CarrierLearning {
|
|||||||
let Some(insertion_sequence) = self.next_insertion_sequence() else {
|
let Some(insertion_sequence) = self.next_insertion_sequence() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.entries
|
self.entries.insert(key, Evidence::new(insertion_sequence));
|
||||||
.insert(key, Evidence::new(insertion_sequence));
|
|
||||||
self.insertion_order.push_back((key, insertion_sequence));
|
self.insertion_order.push_back((key, insertion_sequence));
|
||||||
if let Some(entry) = self.entries.get_mut(&key) {
|
if let Some(entry) = self.entries.get_mut(&key) {
|
||||||
entry.update(slot, deltas, cohort);
|
entry.update(slot, deltas, cohort);
|
||||||
|
|||||||
@@ -189,9 +189,7 @@ impl CarrierRequest {
|
|||||||
|
|
||||||
/// Checks the complete idempotent identity of one exact attempt request.
|
/// Checks the complete idempotent identity of one exact attempt request.
|
||||||
pub(crate) fn matches_attempt(self, other: Self) -> bool {
|
pub(crate) fn matches_attempt(self, other: Self) -> bool {
|
||||||
self.matches_client(other)
|
self.matches_client(other) && self.attempt == other.attempt && self.failure == other.failure
|
||||||
&& self.attempt == other.attempt
|
|
||||||
&& self.failure == other.failure
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capabilities_bits(self) -> Option<u8> {
|
fn capabilities_bits(self) -> Option<u8> {
|
||||||
@@ -252,7 +250,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn invalid_candidate_or_attempt_counts_have_no_deadline_slot() {
|
fn invalid_candidate_or_attempt_counts_have_no_deadline_slot() {
|
||||||
for (candidate_count, attempt) in [(0, 1), (5, 1), (1, 0), (1, 2), (3, 4)] {
|
for (candidate_count, attempt) in [(0, 1), (5, 1), (1, 0), (1, 2), (3, 4)] {
|
||||||
assert_eq!(carrier_attempt_deadline_index(candidate_count, attempt), None);
|
assert_eq!(
|
||||||
|
carrier_attempt_deadline_index(candidate_count, attempt),
|
||||||
|
None
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,15 @@ use sha2::{Digest, Sha256};
|
|||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
use super::negotiation::carrier_attempt_deadline_index;
|
||||||
|
use super::session_admission::admit_initial;
|
||||||
use super::state::{
|
use super::state::{
|
||||||
CarrierChainPhase, decrement_map, matching_profile, new_unique_token, profile_key,
|
CarrierChainPhase, decrement_map, matching_profile, new_unique_token, profile_key,
|
||||||
remember_closed_token_locked, remove_expired_locked,
|
remember_closed_token_locked, remove_expired_locked,
|
||||||
};
|
};
|
||||||
use super::negotiation::carrier_attempt_deadline_index;
|
|
||||||
use super::session_admission::admit_initial;
|
|
||||||
use super::{
|
use super::{
|
||||||
CarrierLearningContext, CarrierRequest, CreateResult, ManagerError, TokenHash, WebProcessRuntime,
|
CarrierLearningContext, CarrierRequest, CreateResult, ManagerError, TokenHash,
|
||||||
|
WebProcessRuntime,
|
||||||
};
|
};
|
||||||
use crate::config::{WebCarrier, WebRuntimeProfile};
|
use crate::config::{WebCarrier, WebRuntimeProfile};
|
||||||
use crate::web::frame;
|
use crate::web::frame;
|
||||||
@@ -62,7 +63,9 @@ impl WebProcessRuntime {
|
|||||||
return Err(ManagerError::Authentication);
|
return Err(ManagerError::Authentication);
|
||||||
}
|
}
|
||||||
if entry.used {
|
if entry.used {
|
||||||
if entry.carrier_deadline_at.is_some_and(|deadline| now >= deadline)
|
if entry
|
||||||
|
.carrier_deadline_at
|
||||||
|
.is_some_and(|deadline| now >= deadline)
|
||||||
&& entry
|
&& entry
|
||||||
.session
|
.session
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -112,9 +115,8 @@ impl WebProcessRuntime {
|
|||||||
token: entry.session_token.as_str().to_owned(),
|
token: entry.session_token.as_str().to_owned(),
|
||||||
carrier: session.carrier(),
|
carrier: session.carrier(),
|
||||||
attempt: carrier_request.attempt(),
|
attempt: carrier_request.attempt(),
|
||||||
candidate_count: automatic.then(|| {
|
candidate_count: automatic
|
||||||
u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)
|
.then(|| u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)),
|
||||||
}),
|
|
||||||
deadline_secs: automatic
|
deadline_secs: automatic
|
||||||
.then_some(entry.profile.carrier_negotiation_deadlines_secs[3]),
|
.then_some(entry.profile.carrier_negotiation_deadlines_secs[3]),
|
||||||
carrier_state: automatic.then_some(carrier_state),
|
carrier_state: automatic.then_some(carrier_state),
|
||||||
@@ -139,14 +141,16 @@ impl WebProcessRuntime {
|
|||||||
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
|
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return Err(if matches!(
|
return Err(
|
||||||
|
if matches!(
|
||||||
entry.carrier_phase,
|
entry.carrier_phase,
|
||||||
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
|
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
|
||||||
) {
|
) {
|
||||||
ManagerError::Committed
|
ManagerError::Committed
|
||||||
} else {
|
} else {
|
||||||
ManagerError::Protocol
|
ManagerError::Protocol
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let Some(carrier) = entry
|
let Some(carrier) = entry
|
||||||
.carrier_candidates
|
.carrier_candidates
|
||||||
@@ -155,8 +159,8 @@ impl WebProcessRuntime {
|
|||||||
else {
|
else {
|
||||||
return Err(ManagerError::Protocol);
|
return Err(ManagerError::Protocol);
|
||||||
};
|
};
|
||||||
let candidate_count = u8::try_from(entry.carrier_candidates.len())
|
let candidate_count =
|
||||||
.map_err(|_| ManagerError::Protocol)?;
|
u8::try_from(entry.carrier_candidates.len()).map_err(|_| ManagerError::Protocol)?;
|
||||||
let deadline_index = carrier_attempt_deadline_index(candidate_count, next_attempt)
|
let deadline_index = carrier_attempt_deadline_index(candidate_count, next_attempt)
|
||||||
.ok_or(ManagerError::Protocol)?;
|
.ok_or(ManagerError::Protocol)?;
|
||||||
if entry.carrier_started_at.is_some_and(|started| {
|
if entry.carrier_started_at.is_some_and(|started| {
|
||||||
@@ -211,8 +215,8 @@ impl WebProcessRuntime {
|
|||||||
if carrier_request.is_automatic() && !profile.carrier_negotiation_enabled {
|
if carrier_request.is_automatic() && !profile.carrier_negotiation_enabled {
|
||||||
return Err(ManagerError::Protocol);
|
return Err(ManagerError::Protocol);
|
||||||
}
|
}
|
||||||
let capability_selection = carrier_request.uses_capabilities()
|
let capability_selection =
|
||||||
&& profile.carrier_negotiation_enabled;
|
carrier_request.uses_capabilities() && profile.carrier_negotiation_enabled;
|
||||||
let learning_policy = (
|
let learning_policy = (
|
||||||
config.web.carrier_negotiation_enabled() && config.web.carrier_learning,
|
config.web.carrier_negotiation_enabled() && config.web.carrier_learning,
|
||||||
config.web.carrier_negotiation_aggressiveness,
|
config.web.carrier_negotiation_aggressiveness,
|
||||||
@@ -222,11 +226,9 @@ impl WebProcessRuntime {
|
|||||||
&& profile.carrier_learning
|
&& profile.carrier_learning
|
||||||
{
|
{
|
||||||
let learning = self.learning.lock();
|
let learning = self.learning.lock();
|
||||||
if let Some(epoch) = learning.epoch_for_policy(
|
if let Some(epoch) =
|
||||||
learning_policy.0,
|
learning.epoch_for_policy(learning_policy.0, learning_policy.1, learning_policy.2)
|
||||||
learning_policy.1,
|
{
|
||||||
learning_policy.2,
|
|
||||||
) {
|
|
||||||
let (candidates, scores) = learning.rank(
|
let (candidates, scores) = learning.rank(
|
||||||
now,
|
now,
|
||||||
&profile.carriers,
|
&profile.carriers,
|
||||||
@@ -259,8 +261,7 @@ impl WebProcessRuntime {
|
|||||||
[0; 4],
|
[0; 4],
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
} else if carrier_request.uses_capabilities()
|
} else if carrier_request.uses_capabilities() && !carrier_request.supports(profile.carrier)
|
||||||
&& !carrier_request.supports(profile.carrier)
|
|
||||||
{
|
{
|
||||||
return Err(ManagerError::Protocol);
|
return Err(ManagerError::Protocol);
|
||||||
} else {
|
} else {
|
||||||
@@ -276,9 +277,9 @@ impl WebProcessRuntime {
|
|||||||
self.limit_hits.fetch_add(1, Ordering::Relaxed);
|
self.limit_hits.fetch_add(1, Ordering::Relaxed);
|
||||||
return Err(ManagerError::Limit);
|
return Err(ManagerError::Limit);
|
||||||
};
|
};
|
||||||
let carrier_deadline_at = carrier_request.is_automatic().then_some(
|
let carrier_deadline_at = carrier_request
|
||||||
now + Duration::from_secs(profile.carrier_negotiation_deadlines_secs[3]),
|
.is_automatic()
|
||||||
);
|
.then_some(now + Duration::from_secs(profile.carrier_negotiation_deadlines_secs[3]));
|
||||||
let learning_context = learning_epoch.map(|epoch| CarrierLearningContext {
|
let learning_context = learning_epoch.map(|epoch| CarrierLearningContext {
|
||||||
profile_key,
|
profile_key,
|
||||||
client_ip,
|
client_ip,
|
||||||
@@ -336,9 +337,7 @@ impl WebProcessRuntime {
|
|||||||
token: session_token,
|
token: session_token,
|
||||||
carrier,
|
carrier,
|
||||||
attempt: carrier_request.attempt(),
|
attempt: carrier_request.attempt(),
|
||||||
candidate_count: carrier_request
|
candidate_count: carrier_request.is_automatic().then_some(candidate_count),
|
||||||
.is_automatic()
|
|
||||||
.then_some(candidate_count),
|
|
||||||
deadline_secs: carrier_request
|
deadline_secs: carrier_request
|
||||||
.is_automatic()
|
.is_automatic()
|
||||||
.then_some(profile.carrier_negotiation_deadlines_secs[3]),
|
.then_some(profile.carrier_negotiation_deadlines_secs[3]),
|
||||||
@@ -494,9 +493,7 @@ impl WebProcessRuntime {
|
|||||||
token: session_token,
|
token: session_token,
|
||||||
carrier: replacement.carrier,
|
carrier: replacement.carrier,
|
||||||
attempt: Some(replacement.attempt),
|
attempt: Some(replacement.attempt),
|
||||||
candidate_count: Some(
|
candidate_count: Some(u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)),
|
||||||
u8::try_from(entry.carrier_candidates.len()).unwrap_or(4),
|
|
||||||
),
|
|
||||||
deadline_secs: Some(entry.profile.carrier_negotiation_deadlines_secs[3]),
|
deadline_secs: Some(entry.profile.carrier_negotiation_deadlines_secs[3]),
|
||||||
carrier_state: Some(CarrierChainPhase::Provisional.as_str()),
|
carrier_state: Some(CarrierChainPhase::Provisional.as_str()),
|
||||||
};
|
};
|
||||||
@@ -512,7 +509,10 @@ impl WebProcessRuntime {
|
|||||||
replacement.old_session.carrier(),
|
replacement.old_session.carrier(),
|
||||||
replacement.attempt - 1,
|
replacement.attempt - 1,
|
||||||
replacement.scores,
|
replacement.scores,
|
||||||
replacement.request.failure().map(|failure| failure.as_str()),
|
replacement
|
||||||
|
.request
|
||||||
|
.failure()
|
||||||
|
.map(|failure| failure.as_str()),
|
||||||
);
|
);
|
||||||
self.trace.record_carrier_lifecycle(
|
self.trace.record_carrier_lifecycle(
|
||||||
client_ip,
|
client_ip,
|
||||||
@@ -522,7 +522,10 @@ impl WebProcessRuntime {
|
|||||||
replacement.old_session.carrier(),
|
replacement.old_session.carrier(),
|
||||||
replacement.attempt - 1,
|
replacement.attempt - 1,
|
||||||
replacement.scores,
|
replacement.scores,
|
||||||
replacement.request.failure().map(|failure| failure.as_str()),
|
replacement
|
||||||
|
.request
|
||||||
|
.failure()
|
||||||
|
.map(|failure| failure.as_str()),
|
||||||
);
|
);
|
||||||
self.trace.record_carrier_lifecycle(
|
self.trace.record_carrier_lifecycle(
|
||||||
client_ip,
|
client_ip,
|
||||||
@@ -540,7 +543,10 @@ impl WebProcessRuntime {
|
|||||||
identity,
|
identity,
|
||||||
TraceLifecycleEvent::SessionCreated,
|
TraceLifecycleEvent::SessionCreated,
|
||||||
None,
|
None,
|
||||||
replacement.request.failure().map(|failure| failure.as_str()),
|
replacement
|
||||||
|
.request
|
||||||
|
.failure()
|
||||||
|
.map(|failure| failure.as_str()),
|
||||||
);
|
);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,9 +357,7 @@ fn select_victim(
|
|||||||
let requester_usage = runtime.data_budget.owner_usage(owner);
|
let requester_usage = runtime.data_budget.owner_usage(owner);
|
||||||
let now = runtime.websocket_tick();
|
let now = runtime.websocket_tick();
|
||||||
let mut registry = runtime.websockets.lock();
|
let mut registry = runtime.websockets.lock();
|
||||||
if claim
|
if claim && registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight {
|
||||||
&& registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let selected = registry
|
let selected = registry
|
||||||
@@ -408,9 +406,7 @@ fn select_pressure_victim(
|
|||||||
claim: bool,
|
claim: bool,
|
||||||
) -> Option<Arc<WebSocketEntry>> {
|
) -> Option<Arc<WebSocketEntry>> {
|
||||||
let mut registry = runtime.websockets.lock();
|
let mut registry = runtime.websockets.lock();
|
||||||
if claim
|
if claim && registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight {
|
||||||
&& registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let selected = registry
|
let selected = registry
|
||||||
@@ -447,8 +443,7 @@ fn claim_stale_victims(runtime: &WebProcessRuntime, now: u64) -> Vec<Arc<WebSock
|
|||||||
.values()
|
.values()
|
||||||
.filter(|entry| !entry.closing.load(Ordering::Acquire))
|
.filter(|entry| !entry.closing.load(Ordering::Acquire))
|
||||||
.filter(|entry| {
|
.filter(|entry| {
|
||||||
now.saturating_sub(entry.last_peer_tick.load(Ordering::Acquire))
|
now.saturating_sub(entry.last_peer_tick.load(Ordering::Acquire)) >= dead_after(entry)
|
||||||
>= dead_after(entry)
|
|
||||||
})
|
})
|
||||||
.take(available)
|
.take(available)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|||||||
@@ -482,7 +482,6 @@ impl WebSession {
|
|||||||
.upgrade()
|
.upgrade()
|
||||||
.map(|manager| manager.budget_notify())
|
.map(|manager| manager.budget_notify())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inbound_queue_cost(queue: &VecDeque<InboundChunk>) -> (usize, usize) {
|
fn inbound_queue_cost(queue: &VecDeque<InboundChunk>) -> (usize, usize) {
|
||||||
|
|||||||
@@ -156,10 +156,8 @@ impl WebSession {
|
|||||||
let fits = if control {
|
let fits = if control {
|
||||||
bytes <= self.limits.control_bytes_per_session
|
bytes <= self.limits.control_bytes_per_session
|
||||||
&& items <= item_reserve
|
&& items <= item_reserve
|
||||||
&& pending_bytes
|
&& pending_bytes <= self.limits.pending_bytes_per_session.saturating_sub(bytes)
|
||||||
<= self.limits.pending_bytes_per_session.saturating_sub(bytes)
|
&& pending_items <= self.limits.pending_items_per_session.saturating_sub(items)
|
||||||
&& pending_items
|
|
||||||
<= self.limits.pending_items_per_session.saturating_sub(items)
|
|
||||||
&& pending_control_bytes
|
&& pending_control_bytes
|
||||||
<= self.limits.control_bytes_per_session.saturating_sub(bytes)
|
<= self.limits.control_bytes_per_session.saturating_sub(bytes)
|
||||||
&& pending_control_items <= item_reserve.saturating_sub(items)
|
&& pending_control_items <= item_reserve.saturating_sub(items)
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use std::sync::Arc;
|
|||||||
use arc_swap::ArcSwap;
|
use arc_swap::ArcSwap;
|
||||||
|
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
ProxyConfig, WebCarrier, WebLimitsConfig, WebRuntimeProfile, WebSecretMode,
|
ProxyConfig, WebCarrier, WebLimitsConfig, WebRuntimeProfile, WebSecretMode, WebTimeoutsConfig,
|
||||||
WebTimeoutsConfig,
|
|
||||||
};
|
};
|
||||||
use crate::maestro::generation::test_runtime_generation;
|
use crate::maestro::generation::test_runtime_generation;
|
||||||
use crate::web::manager::WebProcessRuntime;
|
use crate::web::manager::WebProcessRuntime;
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ impl WebSession {
|
|||||||
&& only_late_frames(&frames)
|
&& only_late_frames(&frames)
|
||||||
{
|
{
|
||||||
return if self.automatic_carrier
|
return if self.automatic_carrier
|
||||||
&& state.negotiation_phase
|
&& state.negotiation_phase != super::SessionNegotiationPhase::Committed
|
||||||
!= super::SessionNegotiationPhase::Committed
|
|
||||||
{
|
{
|
||||||
Err(ManagerError::Backpressure)
|
Err(ManagerError::Backpressure)
|
||||||
} else {
|
} else {
|
||||||
@@ -154,8 +153,7 @@ impl WebSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if applied {
|
if applied {
|
||||||
(committed, healthy) =
|
(committed, healthy) = self.record_uplink_progress_locked(&mut state, progress);
|
||||||
self.record_uplink_progress_locked(&mut state, progress);
|
|
||||||
}
|
}
|
||||||
applied.then_some(sequence).ok_or(ManagerError::Closed)
|
applied.then_some(sequence).ok_or(ManagerError::Closed)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,8 +119,7 @@ impl WebSession {
|
|||||||
return Err(ManagerError::Closed);
|
return Err(ManagerError::Closed);
|
||||||
}
|
}
|
||||||
let carrier_health_eligible = lane_id != 0
|
let carrier_health_eligible = lane_id != 0
|
||||||
&& state.negotiation_phase
|
&& state.negotiation_phase == super::SessionNegotiationPhase::Committed;
|
||||||
== super::SessionNegotiationPhase::Committed;
|
|
||||||
let Some(lane) = state.carrier_lanes.get_mut(&lane_id) else {
|
let Some(lane) = state.carrier_lanes.get_mut(&lane_id) else {
|
||||||
return Ok(PollResult {
|
return Ok(PollResult {
|
||||||
body: Bytes::new(),
|
body: Bytes::new(),
|
||||||
@@ -231,11 +230,7 @@ impl WebSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_lane_open(
|
async fn wait_for_lane_open(&self, lane_id: u32, cursor: u64) -> Result<bool, ManagerError> {
|
||||||
&self,
|
|
||||||
lane_id: u32,
|
|
||||||
cursor: u64,
|
|
||||||
) -> Result<bool, ManagerError> {
|
|
||||||
let wait = {
|
let wait = {
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
if state.closed {
|
if state.closed {
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use bytes::BytesMut;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
ProxyConfig, WebCarrier, WebLimitsConfig, WebRuntimeProfile, WebSecretMode,
|
ProxyConfig, WebCarrier, WebLimitsConfig, WebRuntimeProfile, WebSecretMode, WebTimeoutsConfig,
|
||||||
WebTimeoutsConfig,
|
|
||||||
};
|
};
|
||||||
use crate::maestro::generation::test_runtime_generation;
|
use crate::maestro::generation::test_runtime_generation;
|
||||||
use crate::web::manager::WebProcessRuntime;
|
use crate::web::manager::WebProcessRuntime;
|
||||||
@@ -187,7 +186,9 @@ fn lane_uplink_sequences_are_independent_and_exactly_once() {
|
|||||||
{
|
{
|
||||||
let mut state = session.state.lock();
|
let mut state = session.state.lock();
|
||||||
for lane_id in [51, 52] {
|
for lane_id in [51, 52] {
|
||||||
state.carrier_lanes.insert(lane_id, CarrierLane::new(u64::from(lane_id)));
|
state
|
||||||
|
.carrier_lanes
|
||||||
|
.insert(lane_id, CarrierLane::new(u64::from(lane_id)));
|
||||||
state.closed_streams.insert(lane_id);
|
state.closed_streams.insert(lane_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,11 +275,8 @@ fn tombstone_eviction_releases_lane_budget_and_accepts_late_frames() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn automatic_lane_does_not_ack_a_missing_lane_without_real_progress() {
|
fn automatic_lane_does_not_ack_a_missing_lane_without_real_progress() {
|
||||||
let session = new_session_with_automatic(
|
let session =
|
||||||
WebLimitsConfig::default(),
|
new_session_with_automatic(WebLimitsConfig::default(), std::sync::Weak::new(), true);
|
||||||
std::sync::Weak::new(),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
let late = frame::encode(FrameType::Data, 7, b"late");
|
let late = frame::encode(FrameType::Data, 7, b"late");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -138,12 +138,7 @@ impl WebSession {
|
|||||||
if let Some(batch) = state.unacked.take() {
|
if let Some(batch) = state.unacked.take() {
|
||||||
batch.lease.detach();
|
batch.lease.detach();
|
||||||
self.release_local_locked(&mut state, batch.data_bytes, batch.data_items, false);
|
self.release_local_locked(&mut state, batch.data_bytes, batch.data_items, false);
|
||||||
self.release_local_locked(
|
self.release_local_locked(&mut state, batch.control_bytes, batch.control_items, true);
|
||||||
&mut state,
|
|
||||||
batch.control_bytes,
|
|
||||||
batch.control_items,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let mut lane_data_bytes = 0usize;
|
let mut lane_data_bytes = 0usize;
|
||||||
let mut lane_data_items = 0usize;
|
let mut lane_data_items = 0usize;
|
||||||
@@ -160,12 +155,7 @@ impl WebSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.release_local_locked(&mut state, lane_data_bytes, lane_data_items, false);
|
self.release_local_locked(&mut state, lane_data_bytes, lane_data_items, false);
|
||||||
self.release_local_locked(
|
self.release_local_locked(&mut state, lane_control_bytes, lane_control_items, true);
|
||||||
&mut state,
|
|
||||||
lane_control_bytes,
|
|
||||||
lane_control_items,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
state.carrier_lanes.clear();
|
state.carrier_lanes.clear();
|
||||||
let control_bytes = state.pending_control_bytes;
|
let control_bytes = state.pending_control_bytes;
|
||||||
let control_items = state.pending_control_items;
|
let control_items = state.pending_control_items;
|
||||||
|
|||||||
@@ -93,9 +93,8 @@ impl WebSession {
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let committed = if state.negotiation_phase == SessionNegotiationPhase::Uncommitted {
|
let committed = if state.negotiation_phase == SessionNegotiationPhase::Uncommitted {
|
||||||
state.negotiation_phase = SessionNegotiationPhase::Committed;
|
state.negotiation_phase = SessionNegotiationPhase::Committed;
|
||||||
state.carrier_health_due_at = Some(
|
state.carrier_health_due_at =
|
||||||
now + Duration::from_secs(self.timeouts.carrier_health_secs),
|
Some(now + Duration::from_secs(self.timeouts.carrier_health_secs));
|
||||||
);
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|||||||
@@ -43,8 +43,10 @@ impl ResidentCounters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add(&self, counts: PendingCounts) {
|
fn add(&self, counts: PendingCounts) {
|
||||||
self.data_bytes.fetch_add(counts.data_bytes, Ordering::AcqRel);
|
self.data_bytes
|
||||||
self.data_items.fetch_add(counts.data_items, Ordering::AcqRel);
|
.fetch_add(counts.data_bytes, Ordering::AcqRel);
|
||||||
|
self.data_items
|
||||||
|
.fetch_add(counts.data_items, Ordering::AcqRel);
|
||||||
self.control_bytes
|
self.control_bytes
|
||||||
.fetch_add(counts.control_bytes, Ordering::AcqRel);
|
.fetch_add(counts.control_bytes, Ordering::AcqRel);
|
||||||
self.control_items
|
self.control_items
|
||||||
@@ -52,8 +54,10 @@ impl ResidentCounters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, counts: PendingCounts) {
|
fn remove(&self, counts: PendingCounts) {
|
||||||
self.data_bytes.fetch_sub(counts.data_bytes, Ordering::AcqRel);
|
self.data_bytes
|
||||||
self.data_items.fetch_sub(counts.data_items, Ordering::AcqRel);
|
.fetch_sub(counts.data_bytes, Ordering::AcqRel);
|
||||||
|
self.data_items
|
||||||
|
.fetch_sub(counts.data_items, Ordering::AcqRel);
|
||||||
self.control_bytes
|
self.control_bytes
|
||||||
.fetch_sub(counts.control_bytes, Ordering::AcqRel);
|
.fetch_sub(counts.control_bytes, Ordering::AcqRel);
|
||||||
self.control_items
|
self.control_items
|
||||||
|
|||||||
@@ -139,8 +139,7 @@ impl WebSession {
|
|||||||
} else {
|
} else {
|
||||||
state.last_up_sequence = sequence;
|
state.last_up_sequence = sequence;
|
||||||
state.last_up_digest = digest;
|
state.last_up_digest = digest;
|
||||||
(committed, healthy) =
|
(committed, healthy) = self.record_uplink_progress_locked(&mut state, progress);
|
||||||
self.record_uplink_progress_locked(&mut state, progress);
|
|
||||||
Ok((sequence, progress.any()))
|
Ok((sequence, progress.any()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -532,7 +531,10 @@ mod tests {
|
|||||||
let session = session_with_automatic(true);
|
let session = session_with_automatic(true);
|
||||||
let body = frame::encode(FrameType::Pong, 0, &[]);
|
let body = frame::encode(FrameType::Pong, 0, &[]);
|
||||||
|
|
||||||
assert_eq!(session.process_up(1, &body), Err(ManagerError::Backpressure));
|
assert_eq!(
|
||||||
|
session.process_up(1, &body),
|
||||||
|
Err(ManagerError::Backpressure)
|
||||||
|
);
|
||||||
assert!(!session.is_carrier_committed());
|
assert!(!session.is_carrier_committed());
|
||||||
assert!(!session.state.lock().closed);
|
assert!(!session.state.lock().closed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,8 +273,7 @@ impl WebSession {
|
|||||||
}
|
}
|
||||||
state.last_activity = Instant::now();
|
state.last_activity = Instant::now();
|
||||||
if applied {
|
if applied {
|
||||||
(committed, healthy) =
|
(committed, healthy) = self.record_uplink_progress_locked(&mut state, progress);
|
||||||
self.record_uplink_progress_locked(&mut state, progress);
|
|
||||||
}
|
}
|
||||||
applied
|
applied
|
||||||
.then_some(progress.any())
|
.then_some(progress.any())
|
||||||
|
|||||||
Reference in New Issue
Block a user