/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
usecrate::android::{AndroidError, AndroidHandler}; usecrate::capabilities::{FirefoxOptions, ProfileType}; usecrate::logging; usecrate::prefs; use mozprofile::preferences::Pref; use mozprofile::profile::{PrefFile, Profile}; use mozrunner::runner::{FirefoxProcess, FirefoxRunner, Runner, RunnerProcess}; use std::env; use std::fs; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::time; use uuid::Uuid; use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
pub(crate) fn update_marionette_port(&mutself, port: u16) { matchself {
Browser::Local(x) => x.update_marionette_port(port),
Browser::Remote(x) => x.update_marionette_port(port),
Browser::Existing(x) => { if port != *x {
error!( "Cannot re-assign Marionette port when connected to an existing browser"
);
}
}
}
}
pub(crate) fn create_file(&self, content: &[u8]) -> WebDriverResult<String> { let addon_file = format!("addon-{}.xpi", Uuid::new_v4()); matchself {
Browser::Remote(x) => { let path = x.push_file(content, &addon_file).map_err(|e| {
WebDriverError::new(
ErrorStatus::UnknownError,
format!("Failed to create an addon file: {}", e),
)
})?;
Ok(path)
}
Browser::Local(_) | Browser::Existing(_) => { let path = env::temp_dir().as_path().join(addon_file); letmut xpi_file = fs::File::create(&path).map_err(|e| {
WebDriverError::new(
ErrorStatus::UnknownError,
format!("Failed to create an addon file: {}", e),
)
})?;
xpi_file.write_all(content).map_err(|e| {
WebDriverError::new(
ErrorStatus::UnknownError,
format!("Failed to write data to the addon file: {}", e),
)
})?;
Ok(path.display().to_string())
}
}
}
}
#[derive(Debug)] /// A local Firefox process, running on this (host) device. pub(crate) struct LocalBrowser {
marionette_port: u16,
prefs_backup: Option<PrefsBackup>,
process: FirefoxProcess, pub(crate) profile_path: Option<PathBuf>,
}
impl LocalBrowser { pub(crate) fn new(
options: FirefoxOptions,
marionette_port: u16,
jsdebugger: bool,
profile_root: Option<&Path>,
) -> WebDriverResult<LocalBrowser> { let binary = options.binary.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::SessionNotCreated, "Expected browser binary location, but unable to find \
binary in default location, no \ 'moz:firefoxOptions.binary' capability provided, and \
no binary flag set on the command line",
)
})?;
let is_custom_profile = matches!(options.profile, ProfileType::Path(_));
let (profile_path, prefs_backup) = iflet Some(refmut profile) = profile { let profile_path = profile.path.clone(); let prefs_backup = set_prefs(
marionette_port,
profile,
is_custom_profile,
options.prefs,
jsdebugger,
)
.map_err(|e| {
WebDriverError::new(
ErrorStatus::SessionNotCreated,
format!("Failed to set preferences: {}", e),
)
})?;
(Some(profile_path), prefs_backup)
} else {
warn!("Unable to set geckodriver prefs when using a named profile");
(None, None)
};
fn close(mutself, wait_for_shutdown: bool) -> WebDriverResult<()> { if wait_for_shutdown { // TODO(https://bugzil.la/1443922): // Use toolkit.asyncshutdown.crash_timout pref let duration = time::Duration::from_secs(70); matchself.process.wait(duration) {
Ok(x) => debug!("Browser process stopped: {}", x),
Err(e) => error!("Failed to stop browser process: {}", e),
}
} self.process.kill()?;
// Restoring the prefs if the browser fails to stop perhaps doesn't work anyway iflet Some(prefs_backup) = self.prefs_backup {
prefs_backup.restore();
};
// This should be impossible, but it isn't enforced
Err(WebDriverError::new(
ErrorStatus::SessionNotCreated, "Port not known when using named profile",
))
}
// Restoring the prefs if the browser fails to stop perhaps doesn't work anyway iflet Some(prefs_backup) = self.prefs_backup {
prefs_backup.restore();
};
#[cfg(test)] mod tests { usesuper::set_prefs; usecrate::browser::read_marionette_port; usecrate::capabilities::{FirefoxOptions, ProfileType}; use base64::prelude::BASE64_STANDARD; use base64::Engine; use mozprofile::preferences::{Pref, PrefValue}; use mozprofile::profile::Profile; use serde_json::{Map, Value}; use std::fs::File; use std::io::{Read, Write}; use std::path::Path; use tempfile::tempdir;
// This is not a pretty test, mostly due to the nature of // mozprofile's and MarionetteHandler's APIs, but we have had // several regressions related to remote.log.level. #[test] fn test_remote_log_level() { letmut profile = Profile::new(None).unwrap();
set_prefs(2828, &mut profile, false, vec![], false).ok(); let user_prefs = profile.user_prefs().unwrap();
let pref = user_prefs.get("remote.log.level").unwrap(); let value = match pref.value {
PrefValue::String(ref s) => s,
_ => panic!(),
}; for (i, ch) in value.chars().enumerate() { if i == 0 {
assert!(ch.is_uppercase());
} else {
assert!(ch.is_lowercase());
}
}
}
#[test] fn test_prefs() { let marionette_settings = Default::default();
// Create some prefs in the profile let initial_prefs = profile.user_prefs().unwrap();
initial_prefs.insert("geckodriver.example", Pref::new("example"));
initial_prefs.write().unwrap();
// Ensure the actual prefs contain both the existing ones and the ones we added let pref = user_prefs.get("marionette.port").unwrap();
assert_eq!(pref.value, PrefValue::Int(2828));
let pref = user_prefs.get("geckodriver.example").unwrap();
assert_eq!(pref.value, PrefValue::String("example".into()));
// Ensure the backup prefs don't contain the new settings letmut backup_data = String::new();
File::open(&backup_path)
.expect("Backup prefs exist")
.read_to_string(&mut backup_data)
.unwrap();
assert_eq!(backup_data, initial_prefs_data);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.