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:
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"