Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mozilla/geckodriver.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/browser.rs')
-rw-r--r--src/browser.rs186
1 files changed, 152 insertions, 34 deletions
diff --git a/src/browser.rs b/src/browser.rs
index b777a0a..306bfe1 100644
--- a/src/browser.rs
+++ b/src/browser.rs
@@ -3,16 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::android::AndroidHandler;
-use crate::capabilities::FirefoxOptions;
+use crate::capabilities::{FirefoxOptions, ProfileType};
use crate::logging;
use crate::prefs;
use mozprofile::preferences::Pref;
use mozprofile::profile::{PrefFile, Profile};
use mozrunner::runner::{FirefoxProcess, FirefoxRunner, Runner, RunnerProcess};
use std::fs;
-use std::path::PathBuf;
+use std::io::Read;
+use std::path::{Path, PathBuf};
use std::time;
-
use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
/// A running Gecko instance.
@@ -22,7 +22,7 @@ pub(crate) enum Browser {
Remote(RemoteBrowser),
/// An existing browser instance not controlled by GeckoDriver
- Existing,
+ Existing(u16),
}
impl Browser {
@@ -30,7 +30,29 @@ impl Browser {
match self {
Browser::Local(x) => x.close(wait_for_shutdown),
Browser::Remote(x) => x.close(),
- Browser::Existing => Ok(()),
+ Browser::Existing(_) => Ok(()),
+ }
+ }
+
+ pub(crate) fn marionette_port(&mut self) -> WebDriverResult<Option<u16>> {
+ match self {
+ Browser::Local(x) => x.marionette_port(),
+ Browser::Remote(x) => x.marionette_port(),
+ Browser::Existing(x) => Ok(Some(*x)),
+ }
+ }
+
+ pub(crate) fn update_marionette_port(&mut self, port: u16) {
+ match self {
+ 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"
+ );
+ }
+ }
}
}
}
@@ -38,8 +60,10 @@ impl Browser {
#[derive(Debug)]
/// A local Firefox process, running on this (host) device.
pub(crate) struct LocalBrowser {
- process: FirefoxProcess,
+ marionette_port: u16,
prefs_backup: Option<PrefsBackup>,
+ process: FirefoxProcess,
+ profile_path: Option<PathBuf>,
}
impl LocalBrowser {
@@ -58,26 +82,34 @@ impl LocalBrowser {
)
})?;
- let is_custom_profile = options.profile.is_some();
+ let is_custom_profile = matches!(options.profile, ProfileType::Path(_));
let mut profile = match options.profile {
- Some(x) => x,
- None => Profile::new()?,
+ ProfileType::Named => None,
+ ProfileType::Path(x) => Some(x),
+ ProfileType::Temporary => Some(Profile::new()?),
};
- let prefs_backup = set_prefs(
- marionette_port,
- &mut profile,
- is_custom_profile,
- options.prefs,
- jsdebugger,
- )
- .map_err(|e| {
- WebDriverError::new(
- ErrorStatus::SessionNotCreated,
- format!("Failed to set preferences: {}", e),
+ let (profile_path, prefs_backup) = if let Some(ref mut 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)
+ };
let mut runner = FirefoxRunner::new(&binary, profile);
@@ -109,8 +141,10 @@ impl LocalBrowser {
};
Ok(LocalBrowser {
- process,
+ marionette_port,
prefs_backup,
+ process,
+ profile_path,
})
}
@@ -132,6 +166,26 @@ impl LocalBrowser {
Ok(())
}
+ fn marionette_port(&mut self) -> WebDriverResult<Option<u16>> {
+ if self.marionette_port != 0 {
+ return Ok(Some(self.marionette_port));
+ }
+
+ if let Some(profile_path) = self.profile_path.as_ref() {
+ return Ok(read_marionette_port(profile_path));
+ }
+
+ // This should be impossible, but it isn't enforced
+ Err(WebDriverError::new(
+ ErrorStatus::SessionNotCreated,
+ "Port not known when using named profile",
+ ))
+ }
+
+ fn update_marionette_port(&mut self, port: u16) {
+ self.marionette_port = port;
+ }
+
pub(crate) fn check_status(&mut self) -> Option<String> {
match self.process.try_wait() {
Ok(Some(status)) => Some(
@@ -146,10 +200,33 @@ impl LocalBrowser {
}
}
+fn read_marionette_port(profile_path: &Path) -> Option<u16> {
+ let port_file = profile_path.join("MarionetteActivePort");
+ let mut port_str = String::with_capacity(6);
+ let mut file = match fs::File::open(&port_file) {
+ Ok(file) => file,
+ Err(_) => {
+ trace!("Failed to open {}", &port_file.to_string_lossy());
+ return None;
+ }
+ };
+ if let Err(e) = file.read_to_string(&mut port_str) {
+ trace!("Failed to read {}: {}", &port_file.to_string_lossy(), e);
+ return None;
+ };
+ println!("Read port: {}", port_str);
+ let port = port_str.parse::<u16>().ok();
+ if port.is_none() {
+ warn!("Failed fo convert {} to u16", &port_str);
+ }
+ port
+}
+
#[derive(Debug)]
/// A remote instance, running on a (target) Android device.
pub(crate) struct RemoteBrowser {
handler: AndroidHandler,
+ marionette_port: u16,
}
impl RemoteBrowser {
@@ -163,9 +240,16 @@ impl RemoteBrowser {
let handler = AndroidHandler::new(&android_options, marionette_port, websocket_port)?;
// Profile management.
- let is_custom_profile = options.profile.is_some();
-
- let mut profile = options.profile.unwrap_or(Profile::new()?);
+ let (mut profile, is_custom_profile) = match options.profile {
+ ProfileType::Named => {
+ return Err(WebDriverError::new(
+ ErrorStatus::SessionNotCreated,
+ "Cannot use a named profile on Android",
+ ));
+ }
+ ProfileType::Path(x) => (x, true),
+ ProfileType::Temporary => (Profile::new()?, false),
+ };
set_prefs(
handler.marionette_target_port,
@@ -185,13 +269,24 @@ impl RemoteBrowser {
handler.launch()?;
- Ok(RemoteBrowser { handler })
+ Ok(RemoteBrowser {
+ handler,
+ marionette_port,
+ })
}
fn close(self) -> WebDriverResult<()> {
self.handler.force_stop()?;
Ok(())
}
+
+ fn marionette_port(&mut self) -> WebDriverResult<Option<u16>> {
+ Ok(Some(self.marionette_port))
+ }
+
+ fn update_marionette_port(&mut self, port: u16) {
+ self.marionette_port = port;
+ }
}
fn set_prefs(
@@ -209,14 +304,14 @@ fn set_prefs(
})?;
let backup_prefs = if custom_profile && prefs.path.exists() {
- Some(PrefsBackup::new(&prefs)?)
+ Some(PrefsBackup::new(prefs)?)
} else {
None
};
- for &(ref name, ref value) in prefs::DEFAULT.iter() {
+ for &(name, ref value) in prefs::DEFAULT.iter() {
if !custom_profile || !prefs.contains_key(name) {
- prefs.insert((*name).to_string(), (*value).clone());
+ prefs.insert(name.to_string(), (*value).clone());
}
}
@@ -232,9 +327,6 @@ fn set_prefs(
prefs.insert("marionette.port", Pref::new(port));
prefs.insert("remote.log.level", logging::max_level().into());
- // Deprecated since Firefox 91.
- prefs.insert("marionette.log.level", logging::max_level().into());
-
prefs.write().map_err(|e| {
WebDriverError::new(
ErrorStatus::UnknownError,
@@ -284,12 +376,15 @@ impl PrefsBackup {
#[cfg(test)]
mod tests {
use super::set_prefs;
- use crate::capabilities::FirefoxOptions;
+ use crate::browser::read_marionette_port;
+ use crate::capabilities::{FirefoxOptions, ProfileType};
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;
fn example_profile() -> Value {
let mut profile_data = Vec::with_capacity(1024);
@@ -342,7 +437,10 @@ mod tests {
let opts = FirefoxOptions::from_capabilities(None, &marionette_settings, &mut caps)
.expect("Valid profile and prefs");
- let mut profile = opts.profile.expect("valid firefox profile");
+ let mut profile = match opts.profile {
+ ProfileType::Path(profile) => profile,
+ _ => panic!("Expected ProfileType::Path"),
+ };
set_prefs(2828, &mut profile, true, opts.prefs, false).expect("set preferences");
@@ -420,4 +518,24 @@ mod tests {
.unwrap();
assert_eq!(final_prefs_data, initial_prefs_data);
}
+
+ #[test]
+ fn test_local_read_marionette_port() {
+ fn create_port_file(profile_path: &Path, data: &[u8]) {
+ let port_path = profile_path.join("MarionetteActivePort");
+ let mut file = File::create(&port_path).unwrap();
+ file.write_all(data).unwrap();
+ }
+
+ let profile_dir = tempdir().unwrap();
+ let profile_path = profile_dir.path();
+ assert_eq!(read_marionette_port(profile_path), None);
+ assert_eq!(read_marionette_port(profile_path), None);
+ create_port_file(profile_path, b"");
+ assert_eq!(read_marionette_port(profile_path), None);
+ create_port_file(profile_path, b"1234");
+ assert_eq!(read_marionette_port(profile_path), Some(1234));
+ create_port_file(profile_path, b"1234abc");
+ assert_eq!(read_marionette_port(profile_path), None);
+ }
}