tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 633517653eff7920119cf374d2de13f8150ad02e
parent f6d9d8511823d8cdf47bc2a337fd57a882695816
Author: Nicolas Silva <nical@fastmail.com>
Date:   Wed, 15 Oct 2025 15:13:57 +0000

Bug 1992950 - Allow enabling the WR debugger without revendoring. r=gw,supply-chain-reviewers

We currently have to re-vendor rust dependencies to enable the debugger because we would like to avoid vendoring the tiny_http dependency and because we don't want the hazards of having an HTTP server running in proper firefox builds.

To work around this, this patch replaces the tiny_http dependency with hyper which we already vendor, and conditionally adds the debugger feature via mozconfig (--enable-webrender-debugger).

Differential Revision: https://phabricator.services.mozilla.com/D267768

Diffstat:
MCargo.lock | 6++++++
Mgfx/wr/Cargo.lock | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mgfx/wr/servo-tidy.toml | 4++++
Mgfx/wr/webrender/Cargo.toml | 5+++--
Mgfx/wr/webrender/src/debugger.rs | 329++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mgfx/wr/webrender/src/render_api.rs | 6++++++
Mgfx/wr/wrshell/Cargo.lock | 141++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msupply-chain/config.toml | 2++
Mtoolkit/library/rust/shared/Cargo.toml | 1+
9 files changed, 587 insertions(+), 216 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -7758,6 +7758,7 @@ name = "webrender" version = "0.62.0" dependencies = [ "allocator-api2", + "base64 0.22.1", "bincode", "bitflags 2.9.0", "build-parallel", @@ -7769,6 +7770,7 @@ dependencies = [ "gleam", "glean", "glslopt", + "hyper", "lazy_static", "log", "malloc_size_of_derive", @@ -7779,11 +7781,15 @@ dependencies = [ "ron", "rustc-hash 2.1.1", "serde", + "serde_json", + "sha1", "smallvec", "svg_fmt", "swgl", + "tokio", "topological-sort", "tracy-rs", + "url", "webrender_api", "webrender_build", "wr_glyph_rasterizer", diff --git a/gfx/wr/Cargo.lock b/gfx/wr/Cargo.lock @@ -3,12 +3,27 @@ version = 4 [[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] name = "adler32" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -100,12 +115,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -174,6 +183,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide 0.8.9", + "object", + "rustc-demangle", + "windows-link 0.2.1", +] + +[[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -394,16 +418,10 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - -[[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1002,7 +1020,7 @@ dependencies = [ "cfg-if 1.0.0", "crc32fast", "libc", - "miniz_oxide", + "miniz_oxide 0.5.1", ] [[package]] @@ -1121,6 +1139,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1154,6 +1205,12 @@ dependencies = [ ] [[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] name = "gl_generator" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1435,12 +1492,63 @@ dependencies = [ ] [[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1649,6 +1757,17 @@ dependencies = [ ] [[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.4.2", + "cfg-if 1.0.0", + "libc", +] + +[[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1981,6 +2100,15 @@ dependencies = [ ] [[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] name = "mio" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1995,6 +2123,17 @@ dependencies = [ ] [[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] name = "miow" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2202,6 +2341,15 @@ dependencies = [ ] [[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2355,6 +2503,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" [[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2655,6 +2815,12 @@ dependencies = [ ] [[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2852,6 +3018,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2895,6 +3067,26 @@ dependencies = [ ] [[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3096,18 +3288,6 @@ dependencies = [ ] [[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", -] - -[[package]] name = "tinystr" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3118,6 +3298,23 @@ dependencies = [ ] [[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio 1.0.4", + "pin-project-lite", + "slab", + "socket2 0.6.0", + "windows-sys 0.59.0", +] + +[[package]] name = "toml" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3133,6 +3330,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c" [[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] name = "tracy-rs" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3142,6 +3364,12 @@ dependencies = [ ] [[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3337,6 +3565,15 @@ dependencies = [ ] [[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3521,6 +3758,7 @@ dependencies = [ "gleam", "glean", "glslopt", + "hyper", "lazy_static", "log", "malloc_size_of_derive", @@ -3539,7 +3777,7 @@ dependencies = [ "smallvec", "svg_fmt", "swgl", - "tiny_http", + "tokio", "topological-sort", "tracy-rs", "url", @@ -3671,6 +3909,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3689,6 +3933,15 @@ dependencies = [ ] [[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] name = "windows-targets" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3825,7 +4078,7 @@ dependencies = [ "lazy_static", "libc", "log", - "mio", + "mio 0.8.2", "ndk", "ndk-glue", "ndk-sys", diff --git a/gfx/wr/servo-tidy.toml b/gfx/wr/servo-tidy.toml @@ -59,6 +59,10 @@ packages = [ "windows_aarch64_msvc", "windows_i686_msvc", "windows_aarch64_gnullvm", + "miniz_oxide", + "mio", + "socket2", + "windows-link", ] # Files that are ignored for all tidy and lint checks. diff --git a/gfx/wr/webrender/Cargo.toml b/gfx/wr/webrender/Cargo.toml @@ -20,7 +20,7 @@ static_freetype = ["glyph_rasterizer/static_freetype"] leak_checks = [] gecko = ["firefox-on-glean", "glean", "glyph_rasterizer/gecko"] sw_compositor = ["swgl"] -debugger = ["tiny_http", "serde_json", "url", "sha1", "base64", "api/debugger"] +debugger = ["hyper", "tokio", "serde_json", "url", "sha1", "base64", "api/debugger"] [build-dependencies] build-parallel = "0.1.2" @@ -59,7 +59,8 @@ topological-sort = "0.1" peek-poke = { version = "0.3", path = "../peek-poke" } allocator-api2 = { version = "0.2.18", features = ["alloc", "serde"] } zeitstempel = "0.1.2" -tiny_http = { version = "0.12", optional=true } +hyper = { version = "0.14.32", optional = true, features = ["server", "http1", "tcp", "stream"] } +tokio = { version = "1", optional = true, features = ["rt-multi-thread", "net", "io-util"] } serde_json = { optional=true, version="1" } url = { optional=true, version="2.5" } sha1 = { optional=true, version="0.10" } diff --git a/gfx/wr/webrender/src/debugger.rs b/gfx/wr/webrender/src/debugger.rs @@ -1,21 +1,49 @@ /* 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 http://mozilla.org/MPL/2.0/. */ - -use crate::{DebugCommand, RenderApi}; + +use crate::{DebugCommand, RenderApi, ApiMsg}; use crate::profiler::Profiler; use crate::composite::CompositeState; use std::collections::HashMap; +use std::convert::Infallible; use api::crossbeam_channel; +use api::channel::{Sender, unbounded_channel}; use api::DebugFlags; use api::debugger::{DebuggerMessage, SetDebugFlagsMessage, ProfileCounterDescriptor}; use api::debugger::{UpdateProfileCountersMessage, InitProfileCountersMessage, ProfileCounterId}; use api::debugger::{CompositorDebugInfo, CompositorDebugTile}; use std::thread; -use tiny_http::{Server, Response, ReadWrite, Method}; use base64::prelude::*; -use api::channel::Sender; use sha1::{Sha1, Digest}; +use hyper::{Request, Response, Body, service::{make_service_fn, service_fn}, Server}; +use tokio::io::AsyncWriteExt; + +/// A minimal wrapper around RenderApi's channel that can be cloned. +#[derive(Clone)] +struct DebugRenderApi { + api_sender: Sender<ApiMsg>, +} + +impl DebugRenderApi { + fn new(api: &RenderApi) -> Self { + Self { + api_sender: api.get_api_sender(), + } + } + + fn get_debug_flags(&self) -> DebugFlags { + let (tx, rx) = unbounded_channel(); + let msg = ApiMsg::DebugCommand(DebugCommand::GetDebugFlags(tx)); + self.api_sender.send(msg).unwrap(); + rx.recv().unwrap() + } + + fn send_debug_cmd(&self, cmd: DebugCommand) { + let msg = ApiMsg::DebugCommand(cmd); + self.api_sender.send(msg).unwrap(); + } +} /// Implements the WR remote debugger interface, that the `wrshell` application /// can connect to when the cargo feature `debugger` is enabled. There are two @@ -23,9 +51,7 @@ use sha1::{Sha1, Digest}; /// for commands and can act on those and/or return query results about WR /// internal state. Second, a client can optionally connect to the /debugger-socket /// endpoint for real time updates. This will be upgraded to a websocket connection -/// allowing the WR instance to stream information to client(s) as appropriate. To -/// ensure that we take on minimal dependencies in to Gecko, we use the tiny_http -/// library, and manually perform the websocket connection upgrade below. +/// allowing the WR instance to stream information to client(s) as appropriate. /// Details about the type of debug query being requested #[derive(Clone)] @@ -50,7 +76,7 @@ pub struct DebugQuery { /// A remote debugging client. These are stored with a stream that can publish /// realtime events to (such as debug flag changes, profile counter updates etc). pub struct DebuggerClient { - stream: Box<dyn ReadWrite + Send>, + tx: tokio::sync::mpsc::UnboundedSender<Vec<u8>>, } impl DebuggerClient { @@ -62,13 +88,7 @@ impl DebuggerClient { let data = serde_json::to_string(&msg).expect("bug"); let data = construct_server_ws_frame(&data); - if let Ok(..) = self.stream.write(&data) { - if let Ok(..) = self.stream.flush() { - return true; - } - } - - false + self.tx.send(data).is_ok() } } @@ -137,7 +157,7 @@ impl Debugger { clients_to_keep.push(client); } } - } + } self.clients = clients_to_keep; } @@ -145,138 +165,187 @@ impl Debugger { /// Start the debugger thread that listens for requests from clients. pub fn start(api: RenderApi) { - let address = "localhost:3583"; - let base_url = url::Url::parse(&format!("http://{}", address)).expect("bad url"); + let address = "127.0.0.1:3583"; + + println!("Start WebRender debugger server on http://{}", address); - println!("Start debug server on {}", base_url); + let api = DebugRenderApi::new(&api); thread::spawn(move || { - let server = match Server::http(address) { - Ok(server) => server, - Err(..) => { - println!("\tUnable to bind WR debug server (another process may already be listening)"); + let runtime = match tokio::runtime::Runtime::new() { + Ok(rt) => rt, + Err(e) => { + println!("\tUnable to create tokio runtime for the webrender debugger: {}", e); return; } }; - for mut request in server.incoming_requests() { - let url = base_url.join(request.url()).expect("bad url"); - let args: HashMap<String, String> = url.query_pairs().into_owned().collect(); - - match url.path() { - "/ping" => { - // Client can check if server is online and accepting connections - request.respond(Response::from_string("pong")).ok(); - } - "/debug-flags" => { - // Get or set the current debug flags - match request.method() { - Method::Get => { - let debug_flags = api.get_debug_flags(); - let result = serde_json::to_string(&debug_flags).unwrap(); - request.respond(Response::from_string(result)).ok(); - } - Method::Post => { - let mut content = String::new(); - request.as_reader().read_to_string(&mut content).unwrap(); - - let flags = serde_json::from_str(&content).expect("bug"); - api.send_debug_cmd( - DebugCommand::SetFlags(flags) - ); - request.respond(Response::from_string(format!("flags = {:?}", flags))).ok(); - } - _ => { - request.respond(Response::empty(403)).ok(); - } - } + runtime.block_on(async { + let make_svc = make_service_fn(move |_conn| { + let api = api.clone(); + async move { + Ok::<_, Infallible>(service_fn(move |req| { + handle_request(req, api.clone()) + })) } - "/generate-frame" => { - // Force generate a frame-build and composite - api.send_debug_cmd( - DebugCommand::GenerateFrame - ); - request.respond(Response::empty(200)).ok(); + }); + + let addr = address.parse().unwrap(); + let server = match Server::try_bind(&addr) { + Ok(s) => s, + Err(e) => { + eprintln!("WebRender debugger could not bind: {addr}: {e:?}"); + return; } - "/query" => { - // Query internal state about WR. - let (tx, rx) = crossbeam_channel::unbounded(); - - let kind = match args.get("type").map(|s| s.as_str()) { - Some("spatial-tree") => DebugQueryKind::SpatialTree {}, - Some("composite-view") => DebugQueryKind::CompositorView {}, - Some("composite-config") => DebugQueryKind::CompositorConfig {}, - _ => { - request.respond(Response::from_string("Unknown query")).ok(); - return; - } - }; - - let query = DebugQuery { - result: tx, - kind, - }; - api.send_debug_cmd( - DebugCommand::Query(query) - ); - let result = match rx.recv() { - Ok(result) => result, - Err(..) => "No response received from WR".into(), - }; - request.respond(Response::from_string(result)).ok(); - } - "/debugger-socket" => { - // Connect to a realtime stream of events from WR. This is handled - // by upgrading the HTTP request to a websocket. - - match request - .headers() - .iter() - .find(|h| h.field.equiv(&"Upgrade")) { - Some(h) if h.value == "websocket" => {} - _ => { - request.respond(Response::empty(404)).ok(); - return; - } - } + }; - let key = match request - .headers() - .iter() - .find(|h| h.field.equiv(&"Sec-WebSocket-Key")) - .map(|h| &h.value) - { - Some(k) => k, - None => { - request.respond(Response::empty(400)).ok(); - return; - } - }; - - // 101 Switching Protocols response - let response = tiny_http::Response::new_empty(tiny_http::StatusCode(101)) - .with_header("Upgrade: websocket".parse::<tiny_http::Header>().unwrap()) - .with_header("Connection: Upgrade".parse::<tiny_http::Header>().unwrap()) - .with_header( - format!("Sec-WebSocket-Accept: {}", convert_ws_key(key.as_str())) - .parse::<tiny_http::Header>() - .unwrap(), - ); - let stream = request.upgrade("websocket", response); + if let Err(e) = server.serve(make_svc).await { + eprintln!("WebRender debugger error: {:?}", e); + } + }); + }); +} + +async fn request_to_string(request: Request<Body>) -> Result<String, hyper::Error> { + let body_bytes = hyper::body::to_bytes(request.into_body()).await?; + Ok(String::from_utf8_lossy(&body_bytes).to_string()) +} + +fn string_response<S: Into<String>>(string: S) -> Response<Body> { + Response::new(Body::from(string.into())) +} + +fn status_response(status: u16) -> Response<Body> { + Response::builder().status(status).body(Body::from("")).unwrap() +} - // Send the upgraded connection to WR so it can start streaming +async fn handle_request( + request: Request<Body>, + api: DebugRenderApi, +) -> Result<Response<Body>, Infallible> { + let path = request.uri().path(); + let query = request.uri().query().unwrap_or(""); + let args: HashMap<String, String> = url::form_urlencoded::parse(query.as_bytes()) + .into_owned() + .collect(); + + match path { + "/ping" => { + // Client can check if server is online and accepting connections + Ok(string_response("pong")) + } + "/debug-flags" => { + // Get or set the current debug flags + match request.method() { + &hyper::Method::GET => { + let debug_flags = api.get_debug_flags(); + let result = serde_json::to_string(&debug_flags).unwrap(); + Ok(string_response(result)) + } + &hyper::Method::POST => { + let content = request_to_string(request).await.unwrap(); + let flags = serde_json::from_str(&content).expect("bug"); api.send_debug_cmd( - DebugCommand::AddDebugClient(DebuggerClient { - stream, - }) + DebugCommand::SetFlags(flags) ); + Ok(string_response(format!("flags = {:?}", flags))) } _ => { - request.respond(Response::empty(404)).ok(); + Ok(status_response(403)) } } } - }); + "/generate-frame" => { + // Force generate a frame-build and composite + api.send_debug_cmd( + DebugCommand::GenerateFrame + ); + Ok(status_response(200)) + } + "/query" => { + // Query internal state about WR. + let (tx, rx) = crossbeam_channel::unbounded(); + + let kind = match args.get("type").map(|s| s.as_str()) { + Some("spatial-tree") => DebugQueryKind::SpatialTree {}, + Some("composite-view") => DebugQueryKind::CompositorView {}, + Some("composite-config") => DebugQueryKind::CompositorConfig {}, + _ => { + return Ok(string_response("Unknown query")); + } + }; + + let query = DebugQuery { + result: tx, + kind, + }; + api.send_debug_cmd( + DebugCommand::Query(query) + ); + let result = match rx.recv() { + Ok(result) => result, + Err(..) => "No response received from WR".into(), + }; + Ok(string_response(result)) + } + "/debugger-socket" => { + // Connect to a realtime stream of events from WR. This is handled + // by upgrading the HTTP request to a websocket. + + let upgrade_header = request.headers().get("upgrade"); + if upgrade_header.is_none() || upgrade_header.unwrap() != "websocket" { + return Ok(status_response(404)); + } + + let key = match request.headers().get("sec-websocket-key") { + Some(k) => k.to_str().unwrap_or(""), + None => { + return Ok(status_response(400)); + } + }; + + let accept_key = convert_ws_key(key); + + tokio::spawn(async move { + match hyper::upgrade::on(request).await { + Ok(upgraded) => { + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<Vec<u8>>(); + + // Spawn a task to handle writing to the WebSocket stream + tokio::spawn(async move { + let mut stream = upgraded; + while let Some(data) = rx.recv().await { + if stream.write_all(&data).await.is_err() { + break; + } + if stream.flush().await.is_err() { + break; + } + } + }); + + api.send_debug_cmd( + DebugCommand::AddDebugClient(DebuggerClient { + tx, + }) + ); + } + Err(e) => eprintln!("Upgrade error: {}", e), + } + }); + + Ok(Response::builder() + .status(101) + .header("upgrade", "websocket") + .header("connection", "upgrade") + .header("sec-websocket-accept", accept_key) + .body(Body::from("")) + .unwrap()) + } + _ => { + Ok(status_response(404)) + } + } } /// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-WebSocket-Key diff --git a/gfx/wr/webrender/src/render_api.rs b/gfx/wr/webrender/src/render_api.rs @@ -1114,6 +1114,12 @@ impl RenderApi { self.namespace_id } + /// Returns a clone of the API message sender for internal use + #[allow(unused)] + pub(crate) fn get_api_sender(&self) -> Sender<ApiMsg> { + self.api_sender.clone() + } + /// pub fn create_sender(&self) -> RenderApiSender { RenderApiSender::new( diff --git a/gfx/wr/wrshell/Cargo.lock b/gfx/wr/wrshell/Cargo.lock @@ -128,12 +128,6 @@ dependencies = [ ] [[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -244,12 +238,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - -[[package]] name = "clap" version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -731,6 +719,17 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" @@ -742,12 +741,23 @@ dependencies = [ [[package]] name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.3.1", ] [[package]] @@ -758,8 +768,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] @@ -777,6 +787,29 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" @@ -785,8 +818,8 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -807,14 +840,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "tokio", "tower-service", "tracing", @@ -1460,10 +1493,10 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.7.0", "hyper-util", "js-sys", "log", @@ -1485,19 +1518,6 @@ dependencies = [ [[package]] name = "ron" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f" -dependencies = [ - "base64", - "bitflags 2.9.2", - "serde", - "serde_derive", - "unicode-ident", -] - -[[package]] -name = "ron" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db09040cc89e461f1a265139777a2bde7f8d8c67c4936f700c63ce3e2904d468" @@ -1713,6 +1733,16 @@ dependencies = [ [[package]] name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" @@ -1834,18 +1864,6 @@ dependencies = [ ] [[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", -] - -[[package]] name = "tinystr" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1862,12 +1880,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", + "bytes", "io-uring", "libc", "mio", "pin-project-lite", "slab", - "socket2", + "socket2 0.6.0", "windows-sys 0.59.0", ] @@ -1901,8 +1920,8 @@ dependencies = [ "bitflags 2.9.2", "bytes", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -1961,7 +1980,7 @@ checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.3.1", "httparse", "log", "rand", @@ -2149,6 +2168,7 @@ dependencies = [ "euclid", "gleam", "glslopt", + "hyper 0.14.32", "lazy_static", "log", "malloc_size_of_derive", @@ -2156,14 +2176,14 @@ dependencies = [ "peek-poke", "plane-split", "rayon", - "ron 0.10.1", + "ron", "rustc-hash", "serde", "serde_json", "sha1", "smallvec", "svg_fmt", - "tiny_http", + "tokio", "topological-sort", "tracy-rs", "url", @@ -2230,6 +2250,15 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" @@ -2440,7 +2469,7 @@ dependencies = [ "imgui-sdl3", "repl-ng", "reqwest", - "ron 0.11.0", + "ron", "sdl3", "serde", "serde_json", diff --git a/supply-chain/config.toml b/supply-chain/config.toml @@ -270,6 +270,8 @@ notes = "This is a first-party crate which is also published to crates.io. We ce [policy.webrender] audit-as-crates-io = false +dependency-criteria = { hyper = "safe-to-run", tokio = "safe-to-run" } +notes = "the hyper and tokio dependencies are only enabled in local debug builds, and are not shipped to users" [policy.webrender_api] audit-as-crates-io = false diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml @@ -160,6 +160,7 @@ for_xul = [ # `libmozsqlite` that we distribute. "rusqlite/in_gecko" ] +webrender_debugger = ["webrender_bindings/debugger"] [lib] path = "lib.rs"