bug 1543115: remote, toolkit: bootstrap from Rust; r=remote-protocol-reviewers,maja_zf

This bootstraps the remote agent from Rust so that we have access
to write to stderr using the eprintln!() macro.  There is a future
intention to expand Rust usage in the remote agent by delegating
CDP and WebDriver Bi-Di protocol schema validation to serde.

The Rust port is faithful to the JS version in terms of functionality,
and in some places improves on the original design by enforcing
a strict division between flag handling code on one hand, and the
remote agent server on the other.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Tolfsen 2019-11-22 08:03:21 +00:00
parent 4a8b5c26b8
commit 36f394af15
20 changed files with 509 additions and 118 deletions

14
Cargo.lock generated
View File

@ -1460,6 +1460,7 @@ dependencies = [
"nsstring 0.1.0",
"prefs_parser 0.0.1",
"profiler_helper 0.1.0",
"remote 0.1.0",
"rlbox_lucet_sandbox 0.1.0 (git+https://github.com/PLSysSec/rlbox_lucet_sandbox/?rev=997c648eb0eaeaaa7a00a9eee20431f750b4e190)",
"rsdparsa_capi 0.1.0",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3052,6 +3053,19 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "remote"
version = "0.1.0"
dependencies = [
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0",
"xpcom 0.1.0",
]
[[package]]
name = "remove_dir_all"
version = "0.5.2"

15
remote/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "remote"
version = "0.1.0"
[lib]
path = "lib.rs"
[dependencies]
failure = { version = "0.1", default_features = false, features = ["derive"] }
http = "0.1"
libc = "0.2"
log = "0.4"
nserror = { path = "../xpcom/rust/nserror" }
nsstring = { path = "../xpcom/rust/nsstring" }
xpcom = { path = "../xpcom/rust/xpcom" }

View File

@ -1,30 +0,0 @@
/* 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 strict";
var EXPORTED_SYMBOLS = ["Observer"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class Observer {
static observe(type, observer) {
Services.obs.addObserver(observer, type);
}
static unobserve(type, observer) {
Services.obs.removeObserver(observer, type);
}
static once(type, observer = () => {}) {
return new Promise(resolve => {
const wrappedObserver = (first, ...rest) => {
Observer.unobserve(type, wrappedObserver);
observer.call(first, ...rest);
resolve();
};
Observer.observe(type, wrappedObserver);
});
}
}

View File

@ -12,12 +12,9 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
FatalError: "chrome://remote/content/Error.jsm",
HttpServer: "chrome://remote/content/server/HTTPD.jsm",
JSONHandler: "chrome://remote/content/JSONHandler.jsm",
Log: "chrome://remote/content/Log.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
Observer: "chrome://remote/content/Observer.jsm",
Preferences: "resource://gre/modules/Preferences.jsm",
RecommendedPreferences: "chrome://remote/content/RecommendedPreferences.jsm",
Targets: "chrome://remote/content/targets/Targets.jsm",
@ -27,8 +24,6 @@ XPCOMUtils.defineLazyGetter(this, "log", Log.get);
const ENABLED = "remote.enabled";
const FORCE_LOCAL = "remote.force-local";
const DEFAULT_HOST = "localhost";
const DEFAULT_PORT = 9222;
const LOOPBACKS = ["localhost", "127.0.0.1", "[::1]"];
class RemoteAgentClass {
@ -90,7 +85,6 @@ class RemoteAgentClass {
const mainTarget = this.targets.getMainProcessTarget();
this.server._start(port, host);
dump(`DevTools listening on ${mainTarget.wsDebuggerURL}\n`);
Services.obs.notifyObservers(
null,
"remote-listening",
@ -148,83 +142,10 @@ class RemoteAgentClass {
return this.server.identity.primaryPort;
}
// nsICommandLineHandler
async handle(cmdLine) {
function flag(name) {
const caseSensitive = true;
try {
return cmdLine.handleFlagWithParam(name, caseSensitive);
} catch (e) {
return cmdLine.handleFlag(name, caseSensitive);
}
}
const remoteDebugger = flag("remote-debugger");
const remoteDebuggingPort = flag("remote-debugging-port");
if (remoteDebugger && remoteDebuggingPort) {
log.fatal(
"Conflicting flags --remote-debugger and --remote-debugging-port"
);
cmdLine.preventDefault = true;
return;
}
if (!remoteDebugger && !remoteDebuggingPort) {
return;
}
let host, port;
if (typeof remoteDebugger == "string") {
[host, port] = remoteDebugger.split(":");
} else if (typeof remoteDebuggingPort == "string") {
port = remoteDebuggingPort;
}
let addr;
try {
addr = NetUtil.newURI(
`http://${host || DEFAULT_HOST}:${port || DEFAULT_PORT}/`
);
} catch (e) {
log.fatal(
`Expected address syntax [<host>]:<port>: ${remoteDebugger ||
remoteDebuggingPort}`
);
cmdLine.preventDefault = true;
return;
}
await Observer.once("sessionstore-windows-restored");
try {
this.listen(addr);
} catch (e) {
this.close();
throw new FatalError(
`Unable to start remote agent on ${addr.spec}: ${e.message}`,
e
);
}
}
get helpInfo() {
return (
" --remote-debugger [<host>][:<port>]\n" +
" --remote-debugging-port <port> Start the Firefox remote agent, which is \n" +
" a low-level debugging interface based on the CDP protocol.\n" +
" Defaults to listen on localhost:9222.\n"
);
}
// XPCOM
get QueryInterface() {
return ChromeUtils.generateQI([
Ci.nsICommandLineHandler,
Ci.nsIRemoteAgent,
]);
return ChromeUtils.generateQI([Ci.nsIRemoteAgent]);
}
}

View File

@ -1,15 +1,19 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
Classes = [
{
'cid': '{8f685a9d-8181-46d6-a71d-869289099c6d}',
'contract_ids': ['@mozilla.org/remote/agent'],
'jsm': 'chrome://remote/content/RemoteAgent.jsm',
'constructor': 'RemoteAgentFactory',
'categories': {'command-line-handler': 'm-remote'},
"cid": "{8f685a9d-8181-46d6-a71d-869289099c6d}",
"contract_ids": ["@mozilla.org/remote/agent;1"],
"jsm": "chrome://remote/content/RemoteAgent.jsm",
"constructor": "RemoteAgentFactory",
},
{
"cid": "{0d1bb02e-ac91-4904-b61d-97da83ebf6fb}",
"contract_ids": ["@mozilla.org/commandlinehandler/general-startup;1?type=remote"],
"categories": {"command-line-handler": "m-remote"},
"headers": ["RemoteAgentHandler.h"],
"constructor": "GetRemoteAgentHandler",
},
]

60
remote/error.rs Normal file
View File

@ -0,0 +1,60 @@
// 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 std::num;
use failure::Fail;
use http;
use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE};
#[derive(Debug, Fail)]
pub enum RemoteAgentError {
#[fail(display = "expected address syntax [<host>]:<port>: {}", _0)]
AddressSpec(http::uri::InvalidUri),
#[fail(display = "conflicting flags --remote-debugger and --remote-debugging-port")]
FlagConflict,
#[fail(display = "invalid port: {}", _0)]
InvalidPort(num::ParseIntError),
#[fail(display = "missing port number")]
MissingPort,
#[fail(display = "unavailable")]
Unavailable,
#[fail(display = "error result {}", _0)]
XpCom(nsresult),
}
impl From<RemoteAgentError> for nsresult {
fn from(err: RemoteAgentError) -> nsresult {
use RemoteAgentError::*;
match err {
AddressSpec(_) | InvalidPort(_) => NS_ERROR_INVALID_ARG,
MissingPort | FlagConflict => NS_ERROR_INVALID_ARG,
Unavailable => NS_ERROR_NOT_AVAILABLE,
XpCom(result) => result,
}
}
}
impl From<num::ParseIntError> for RemoteAgentError {
fn from(err: num::ParseIntError) -> Self {
RemoteAgentError::InvalidPort(err)
}
}
impl From<http::uri::InvalidUri> for RemoteAgentError {
fn from(err: http::uri::InvalidUri) -> Self {
RemoteAgentError::AddressSpec(err)
}
}
impl From<nsresult> for RemoteAgentError {
fn from(result: nsresult) -> Self {
RemoteAgentError::XpCom(result)
}
}

View File

@ -10,7 +10,6 @@ remote.jar:
content/Error.jsm (Error.jsm)
content/JSONHandler.jsm (JSONHandler.jsm)
content/Log.jsm (Log.jsm)
content/Observer.jsm (Observer.jsm)
content/Protocol.jsm (Protocol.jsm)
content/RecommendedPreferences.jsm (RecommendedPreferences.jsm)
content/Sync.jsm (Sync.jsm)

18
remote/lib.rs Normal file
View File

@ -0,0 +1,18 @@
// 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/.
extern crate failure;
extern crate http;
extern crate libc;
extern crate log;
extern crate nserror;
extern crate nsstring;
extern crate xpcom;
mod error;
mod remote_agent;
mod startup;
pub use crate::error::RemoteAgentError;
pub use crate::remote_agent::{RemoteAgent, RemoteAgentResult, DEFAULT_HOST, DEFAULT_PORT};

View File

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
"startup",
"test",
]

66
remote/remote_agent.rs Normal file
View File

@ -0,0 +1,66 @@
// 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/.
//! Rust interface for the Gecko remote agent.
use std::str::FromStr;
use log::*;
use nsstring::{nsAString, nsString};
use xpcom::interfaces::nsIRemoteAgent;
use xpcom::RefPtr;
use crate::error::RemoteAgentError::{self, *};
pub const DEFAULT_HOST: &'static str = "localhost";
pub const DEFAULT_PORT: u16 = 9222;
pub type RemoteAgentResult<T> = Result<T, RemoteAgentError>;
pub struct RemoteAgent {
inner: RefPtr<nsIRemoteAgent>,
}
impl RemoteAgent {
pub fn get() -> RemoteAgentResult<RemoteAgent> {
let inner = xpcom::services::get_RemoteAgent().ok_or(Unavailable)?;
Ok(RemoteAgent { inner })
}
pub fn listen(&self, spec: &str) -> RemoteAgentResult<()> {
let addr = http::uri::Authority::from_str(spec)?;
let host = if addr.host().is_empty() {
DEFAULT_HOST
} else {
addr.host()
}
.to_string();
let port = addr.port_u16().unwrap_or(DEFAULT_PORT);
let url = nsString::from(&format!("http://{}:{}/", host, port));
unsafe { self.inner.Listen(&*url as &nsAString) }.to_result()?;
Ok(())
}
pub fn listening(&self) -> RemoteAgentResult<bool> {
let mut listening = false;
unsafe { self.inner.GetListening(&mut listening) }.to_result()?;
Ok(listening)
}
pub fn close(&self) -> RemoteAgentResult<()> {
unsafe { self.inner.Close() }.to_result()?;
Ok(())
}
}
impl Drop for RemoteAgent {
fn drop(&mut self) {
// it should always be safe to call nsIRemoteAgent.close()
if let Err(e) = self.close() {
error!("unable to close remote agent listener: {}", e);
}
}
}

View File

@ -0,0 +1,36 @@
/* 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/. */
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "nsCOMPtr.h"
#include "nsICommandLineHandler.h"
#include "nsISupportsUtils.h"
#include "RemoteAgentHandler.h"
// anonymous namespace prevents outside C++ code
// from improperly accessing these implementation details
namespace {
extern "C" {
// implemented in Rust, see handler.rs
void new_remote_agent_handler(nsICommandLineHandler** result);
}
static mozilla::StaticRefPtr<nsICommandLineHandler> sHandler;
} // namespace
already_AddRefed<nsICommandLineHandler> GetRemoteAgentHandler() {
nsCOMPtr<nsICommandLineHandler> handler;
if (sHandler) {
handler = sHandler;
} else {
new_remote_agent_handler(getter_AddRefs(handler));
sHandler = handler;
mozilla::ClearOnShutdown(&sHandler);
}
return handler.forget();
}

View File

@ -0,0 +1,12 @@
/* 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/. */
#ifndef mozilla_remote_startup_RemoteAgentHandler_h
#define mozilla_remote_startup_RemoteAgentHandler_h
#include "nsICommandLineHandler.h"
already_AddRefed<nsICommandLineHandler> GetRemoteAgentHandler();
#endif // mozilla_remote_startup_RemoteAgentHandler_h

253
remote/startup/handler.rs Normal file
View File

@ -0,0 +1,253 @@
// 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 std::cell::RefCell;
use std::ffi::{CStr, CString, NulError};
use std::slice;
use libc::c_char;
use log::*;
use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_ILLEGAL_VALUE, NS_ERROR_INVALID_ARG, NS_OK};
use nsstring::{nsACString, nsCString, nsString};
use xpcom::interfaces::{nsICommandLine, nsICommandLineHandler, nsIObserverService, nsISupports};
use xpcom::{xpcom, xpcom_method, RefPtr};
use crate::{
RemoteAgent,
RemoteAgentError::{self, *},
RemoteAgentResult, DEFAULT_HOST, DEFAULT_PORT,
};
macro_rules! fatalln {
($($arg:tt)*) => ({
let p = prog().unwrap_or("gecko".to_string());
eprintln!("{}: {}", p, format_args!($($arg)*));
panic!();
})
}
#[no_mangle]
pub unsafe extern "C" fn new_remote_agent_handler(result: *mut *const nsICommandLineHandler) {
let handler: RefPtr<RemoteAgentHandler> = RemoteAgentHandler::new().unwrap();
RefPtr::new(handler.coerce::<nsICommandLineHandler>()).forget(&mut *result);
}
#[derive(xpcom)]
#[xpimplements(nsICommandLineHandler)]
#[xpimplements(nsIObserver)]
#[refcnt = "atomic"]
struct InitRemoteAgentHandler {
agent: RemoteAgent,
observer: RefPtr<nsIObserverService>,
address: RefCell<String>,
}
impl RemoteAgentHandler {
pub fn new() -> Result<RefPtr<Self>, RemoteAgentError> {
let agent = RemoteAgent::get()?;
let observer = xpcom::services::get_ObserverService().ok_or(Unavailable)?;
Ok(Self::allocate(InitRemoteAgentHandler {
agent,
observer,
address: RefCell::new(String::new()),
}))
}
xpcom_method!(handle => Handle(command_line: *const nsICommandLine));
fn handle(&self, command_line: &nsICommandLine) -> Result<(), nsresult> {
match self.handle_inner(&command_line) {
Ok(_) => Ok(()),
Err(err) => fatalln!("{}", err),
}
}
fn handle_inner(&self, command_line: &nsICommandLine) -> RemoteAgentResult<()> {
let flags = CommandLine::new(command_line);
let remote_debugger = if flags.present("remote-debugger") {
Some(flags.opt_str("remote-debugger")?)
} else {
None
};
let remote_debugging_port = if flags.present("remote-debugging-port") {
Some(flags.opt_u16("remote-debugging-port")?)
} else {
None
};
let addr = match (remote_debugger, remote_debugging_port) {
(Some(_), Some(_)) => return Err(FlagConflict),
(None, None) => return Ok(()),
// --remote-debugger [<host>][:<port>]
(Some(Some(spec)), _) => spec,
(Some(None), _) => format!("{}:{}", DEFAULT_HOST, DEFAULT_PORT),
// --remote-debugging-port <port>
(None, Some(Some(port))) => format!("{}:{}", DEFAULT_HOST, port),
(None, Some(None)) => return Err(MissingPort),
};
*self.address.borrow_mut() = addr.to_string();
// Before we can start the remote agent we ensure the browser session
// state has been restored. This guarantees we wait for all windows
// and tabs to be resurrected.
//
// Once sessionstore-windows-restored fires, it takes care of asking
// the remote agent to listen for incoming connections. Because the
// remote agent starts asynchronously, we wait until we receive
// remote-listening before we declare to the world that we are ready
// to accept connections.
self.add_observer("remote-listening")?;
self.add_observer("sessionstore-windows-restored")?;
Ok(())
}
fn add_observer(&self, topic: &str) -> RemoteAgentResult<()> {
let topic = CString::new(topic).unwrap();
unsafe {
self.observer
.AddObserver(self.coerce(), topic.as_ptr(), false)
}
.to_result()?;
Ok(())
}
xpcom_method!(help_info => GetHelpInfo() -> nsACString);
fn help_info(&self) -> Result<nsCString, nsresult> {
let help = r#" --remote-debugger [<host>][:<port>]
--remote-debugging-port <port> Start the Firefox remote agent, which is
a low-level debugging interface based on the CDP protocol.
Defaults to listen on localhost:9222.
"#;
Ok(nsCString::from(help))
}
xpcom_method!(observe => Observe(_subject: *const nsISupports, topic: string, data: wstring));
fn observe(
&self,
_subject: *const nsISupports,
topic: string,
data: wstring,
) -> Result<(), nsresult> {
let topic = unsafe { CStr::from_ptr(topic) }.to_str().unwrap();
match topic {
"sessionstore-windows-restored" => {
if let Err(err) = self.agent.listen(&self.address.borrow()) {
fatalln!("unable to start remote agent: {}", err);
}
}
"remote-listening" => {
let url = unsafe { wstring_to_cstring(data) }.map_err(|_| NS_ERROR_FAILURE)?;
eprintln!("DevTools listening on {}", url.to_string_lossy());
}
s => warn!("unknown system notification: {}", s),
}
Ok(())
}
}
// Rust wrapper for nsICommandLine.
struct CommandLine<'a> {
inner: &'a nsICommandLine,
}
impl<'a> CommandLine<'a> {
const CASE_SENSITIVE: bool = true;
fn new(inner: &'a nsICommandLine) -> Self {
Self { inner }
}
fn position(&self, name: &str) -> i32 {
let flag = nsString::from(name);
let mut result: i32 = 0;
unsafe {
self.inner
.FindFlag(&*flag, Self::CASE_SENSITIVE, &mut result)
}
.to_result()
.map_err(|err| error!("FindFlag: {}", err))
.unwrap();
result
}
fn present(&self, name: &str) -> bool {
self.position(name) >= 0
}
// nsICommandLine.handleFlagWithParam has the following possible return values:
//
// - an AString value representing the argument value if it exists
// - NS_ERROR_INVALID_ARG if the flag was defined, but without a value
// - a null pointer if the flag was not defined
// - possibly any other NS exception
//
// This means we need to treat NS_ERROR_INVALID_ARG with special care
// because --remote-debugger can be used both with and without a value.
fn opt_str(&self, name: &str) -> RemoteAgentResult<Option<String>> {
if self.present(name) {
let flag = nsString::from(name);
let mut val = nsString::new();
let result = unsafe {
self.inner
.HandleFlagWithParam(&*flag, Self::CASE_SENSITIVE, &mut *val)
}
.to_result();
match result {
Ok(_) => Ok(Some(val.to_string())),
Err(NS_ERROR_INVALID_ARG) => Ok(None),
Err(err) => Err(RemoteAgentError::XpCom(err)),
}
} else {
Err(RemoteAgentError::XpCom(NS_ERROR_ILLEGAL_VALUE))
}
}
fn opt_u16(&self, name: &str) -> RemoteAgentResult<Option<u16>> {
Ok(if let Some(s) = self.opt_str(name)? {
Some(s.parse()?)
} else {
None
})
}
}
fn prog() -> Option<String> {
std::env::current_exe()
.ok()?
.file_name()?
.to_str()?
.to_owned()
.into()
}
// Arcane XPIDL types for raw character pointers
// to ASCII (7-bit) and UTF-16 strings, respectively.
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Guide/Internal_strings#IDL
#[allow(non_camel_case_types)]
type string = *const c_char;
#[allow(non_camel_case_types)]
type wstring = *const i16;
// Convert wstring to a CString (via nsCString's UTF-16 to UTF-8 conversion).
// But first, say three Hail Marys.
unsafe fn wstring_to_cstring(ws: wstring) -> Result<CString, NulError> {
let mut len: usize = 0;
while (*(ws.offset(len as isize))) != 0 {
len += 1;
}
let ss = slice::from_raw_parts(ws as *const u16, len);
let mut s = nsCString::new();
s.assign_utf16_to_utf8(ss);
CString::new(s.as_str_unchecked())
}

5
remote/startup/mod.rs Normal file
View File

@ -0,0 +1,5 @@
// 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/.
mod handler;

7
remote/startup/moz.build Normal file
View File

@ -0,0 +1,7 @@
# 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/.
EXPORTS += ["RemoteAgentHandler.h"]
UNIFIED_SOURCES += ["RemoteAgentHandler.cpp"]
FINAL_LIBRARY = "xul"

View File

@ -29,6 +29,7 @@ fuzzing_interfaces = ["gkrust-shared/fuzzing_interfaces", "gecko-fuzz-targets"]
webrtc = ["gkrust-shared/webrtc"]
wasm_library_sandboxing = ["gkrust-shared/wasm_library_sandboxing"]
webgpu = ["gkrust-shared/webgpu"]
remote_agent = ["gkrust-shared/remote"]
[dependencies]
bench-collections-gtest = { path = "../../../../xpcom/rust/gtest/bench-collections" }

View File

@ -30,6 +30,7 @@ fuzzing_interfaces = ["gkrust-shared/fuzzing_interfaces"]
webrtc = ["gkrust-shared/webrtc"]
wasm_library_sandboxing = ["gkrust-shared/wasm_library_sandboxing"]
webgpu = ["gkrust-shared/webgpu"]
remote_agent = ["gkrust-shared/remote"]
[dependencies]
gkrust-shared = { path = "shared" }

View File

@ -67,3 +67,6 @@ if CONFIG['FUZZING_INTERFACES']:
if CONFIG['MOZ_WEBRTC']:
gkrust_features += ['webrtc']
if CONFIG['ENABLE_REMOTE_AGENT']:
gkrust_features += ['remote_agent']

View File

@ -45,6 +45,7 @@ neqo_glue = { path = "../../../../netwerk/socket/neqo_glue" }
rlbox_lucet_sandbox = { version = "0.1.0", optional = true }
wgpu-remote = { path = "../../../../gfx/wgpu/wgpu-remote", optional = true }
mapped_hyph = { git = "https://github.com/jfkthame/mapped_hyph.git", tag = "v0.3.0" }
remote = { path = "../../../../remote", optional = true }
unic-langid = { version = "0.7.1", features = ["likelysubtags"] }
unic-langid-ffi = { path = "../../../../intl/locale/rust/unic-langid-ffi" }
@ -79,6 +80,7 @@ fuzzing_interfaces = []
webrtc = ["mdns_service"]
wasm_library_sandboxing = ["rlbox_lucet_sandbox"]
webgpu = ["wgpu-remote"]
remote_agent = ["remote"]
[lib]
path = "lib.rs"

View File

@ -64,6 +64,9 @@ extern crate unic_langid_ffi;
extern crate fluent_langneg;
extern crate fluent_langneg_ffi;
#[cfg(feature = "remote")]
extern crate remote;
use std::boxed::Box;
use std::env;
use std::ffi::{CStr, CString};