devtools: Allow specifiying an address to listen to and default to localhost (#42502)

Previously we listened to 0.0.0.0. which means any connection coming to
a specific port. That seems a bit ill advised as not everybody has a
good firewall setup. Now we default listen only on 127.0.0.1 but
optionally can describe a full SocketAddr such as "192.168.1.23:1234".

Side note: Cleaned up the ipc-channel syntax.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>

Testing: Currently we don't have an automatic way to test this. Manually
run devtools and it connects.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
Narfinger
2026-02-19 12:24:56 +09:00
committed by GitHub
parent 07b120e0d0
commit 00fa5d3088
5 changed files with 30 additions and 18 deletions

View File

@@ -111,7 +111,7 @@ icu_segmenter = "1.5.0"
image = { version = "0.25", default-features = false, features = ["avif", "rayon", "bmp", "gif", "ico", "jpeg", "png", "webp"] }
imsz = "0.4"
indexmap = { version = "2.11.4", features = ["std"] }
ipc-channel = { version = "0.21" }
ipc-channel = "0.21"
itertools = "0.14"
js = { package = "mozjs", version = "=0.15.0", default-features = false, features = ["libz-sys", "intl"] }
keyboard-types = { version = "0.8.3", features = ["serde", "webdriver"] }

View File

@@ -87,9 +87,8 @@ pub struct Preferences {
pub css_animations_testing_enabled: bool,
/// Start the devtools server at startup
pub devtools_server_enabled: bool,
/// Port number to start a server to listen to remote Firefox devtools connections.
/// 0 for random port.
pub devtools_server_port: i64,
/// The address +port the devtools server listens to, default to 127.0.0.1:7000.
pub devtools_server_listen_address: String,
// feature: WebGPU | #24706 | Web/API/WebGPU_API
pub dom_webgpu_enabled: bool,
/// List of comma-separated backends to be used by wgpu.
@@ -342,7 +341,7 @@ impl Preferences {
Self {
css_animations_testing_enabled: false,
devtools_server_enabled: false,
devtools_server_port: 0,
devtools_server_listen_address: String::new(),
dom_abort_controller_enabled: true,
dom_adoptedstylesheet_enabled: false,
dom_allow_scripts_to_close_windows: false,

View File

@@ -14,7 +14,8 @@
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::io::Read;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::net::{Ipv4Addr, Shutdown, SocketAddr, TcpListener, TcpStream};
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;
@@ -36,6 +37,7 @@ use rand::{RngCore, rng};
use resource::{ResourceArrayType, ResourceAvailable};
use rustc_hash::FxHashMap;
use serde::Serialize;
use servo_config::pref;
use crate::actor::{Actor, ActorError, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor;
@@ -110,7 +112,6 @@ pub(crate) struct ActorMsg {
/// Spin up a devtools server that listens for connections on the specified port.
pub fn start_server(
port: u16,
embedder: EmbedderProxy,
mem_profiler_chan: ProfilerChan,
) -> Sender<DevtoolsControlMsg> {
@@ -123,8 +124,7 @@ pub fn start_server(
.spawn(move || {
mem_profiler_chan.run_with_memory_reporting(
|| {
if let Some(instance) =
DevtoolsInstance::create(sender, receiver, port, embedder)
if let Some(instance) = DevtoolsInstance::create(sender, receiver, embedder)
{
instance.run()
}
@@ -172,10 +172,20 @@ impl DevtoolsInstance {
fn create(
sender: Sender<DevtoolsControlMsg>,
receiver: Receiver<DevtoolsControlMsg>,
port: u16,
embedder: EmbedderProxy,
) -> Option<Self> {
let bound = TcpListener::bind(("0.0.0.0", port)).ok().and_then(|l| {
let address = if pref!(devtools_server_listen_address).is_empty() {
SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 7000)
} else if let Ok(addr) = SocketAddr::from_str(&pref!(devtools_server_listen_address)) {
addr
} else if let Ok(port) = pref!(devtools_server_listen_address).parse() {
SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), port)
} else {
SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 7000)
};
println!("Binding devtools to {address}");
let bound = TcpListener::bind(address).ok().and_then(|l| {
l.local_addr()
.map(|addr| addr.port())
.ok()
@@ -183,7 +193,11 @@ impl DevtoolsInstance {
});
// A token shared with the embedder to bypass permission prompt.
let port = if bound.is_some() { Ok(port) } else { Err(()) };
let port = if bound.is_some() {
Ok(address.port())
} else {
Err(())
};
let token = format!("{:X}", rng().next_u32());
embedder.send(EmbedderMsg::OnDevtoolsStarted(port, token.clone()));

View File

@@ -769,7 +769,6 @@ impl Servo {
let devtools_sender = if pref!(devtools_server_enabled) {
Some(devtools::start_server(
pref!(devtools_server_port) as u16,
embedder_proxy.clone(),
mem_profiler_chan.clone(),
))

View File

@@ -407,9 +407,9 @@ struct CmdArgs {
#[bpaf(argument("1.0"))]
device_pixel_ratio: Option<f32>,
/// Start remote devtools server on port.
#[bpaf(argument("0"))]
devtools: Option<u16>,
/// Start remote devtools server on port listening on this address. <address>:<port> and <port> are valid values.
#[bpaf(argument("127.0.0.1:7000"))]
devtools: Option<String>,
///
/// Whether or not to enable experimental web platform features.
@@ -569,9 +569,9 @@ fn update_preferences_from_command_line_arguemnts(
preferences: &mut Preferences,
cmd_args: &CmdArgs,
) {
if let Some(port) = cmd_args.devtools {
if let Some(listen_address) = &cmd_args.devtools {
preferences.devtools_server_enabled = true;
preferences.devtools_server_port = port as i64;
preferences.devtools_server_listen_address = listen_address.clone();
}
if cmd_args.enable_experimental_web_platform_features {