Files
servo/components/devtools/network_handler.rs
Brent Schroeter c94722d3da devtools: wrap TcpStream to synchronize network operations (#43472)
Introduces a new type `DevtoolsConnection`, which implements the
`JsonPacketStream` trait with proper coordination of I/O across threads.
This replaces the implementation of `JsonPacketStream` for raw
`TcpStream`s, which was susceptible to interleaving writes when cloned
across threads.

`DevtoolsConnection` also defensively synchronizes read operations.
These are less likely to cause issues: in practice actors should never
independently pull incoming messages without centralized coordination.

Testing: No new tests, as interleaving writes are difficult to evoke
deterministically. Removing the `JsonPacketStream` implementation for
`TcpStream` should discourage regressions due to improper use of raw
streams.

---------

Signed-off-by: Brent Schroeter <contact@brentsch.com>
Co-authored-by: eri <eri@igalia.com>
2026-03-26 08:43:04 +00:00

98 lines
3.2 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::sync::Arc;
use devtools_traits::NetworkEvent;
use serde::Serialize;
use crate::actor::{ActorEncode, ActorRegistry};
use crate::actors::network_event::NetworkEventActor;
use crate::actors::watcher::WatcherActor;
use crate::protocol::DevtoolsConnection;
use crate::resource::{ResourceArrayType, ResourceAvailable};
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Cause {
#[serde(rename = "type")]
pub type_: String,
pub loading_document_uri: Option<String>,
}
pub(crate) fn handle_network_event(
registry: Arc<ActorRegistry>,
netevent_actor_name: String,
mut connections: Vec<DevtoolsConnection>,
network_event: NetworkEvent,
) {
let actor = registry.find::<NetworkEventActor>(&netevent_actor_name);
let watcher = registry.find::<WatcherActor>(&actor.watcher);
match network_event {
NetworkEvent::HttpRequest(httprequest) => {
actor.add_request(httprequest);
let msg = actor.encode(&registry);
let resource = actor.resource_updates(&registry);
for stream in &mut connections {
watcher.resource_array(
msg.clone(),
"network-event".to_string(),
ResourceArrayType::Available,
stream,
);
// Also push initial resource update (request headers, cookies)
watcher.resource_array(
resource.clone(),
"network-event".to_string(),
ResourceArrayType::Updated,
stream,
);
}
},
NetworkEvent::HttpRequestUpdate(httprequest) => {
actor.add_request(httprequest);
let resource = actor.resource_updates(&registry);
for stream in &mut connections {
watcher.resource_array(
resource.clone(),
"network-event".to_string(),
ResourceArrayType::Updated,
stream,
);
}
},
NetworkEvent::HttpResponse(httpresponse) => {
actor.add_response(httpresponse);
let resource = actor.resource_updates(&registry);
for stream in &mut connections {
watcher.resource_array(
resource.clone(),
"network-event".to_string(),
ResourceArrayType::Updated,
stream,
);
}
},
NetworkEvent::SecurityInfo(update) => {
actor.add_security_info(update.security_info);
let resource = actor.resource_updates(&registry);
for stream in &mut connections {
watcher.resource_array(
resource.clone(),
"network-event".to_string(),
ResourceArrayType::Updated,
stream,
);
}
},
}
}