diff options
author | Andreas Tolfsen <ato@mozilla.com> | 2017-06-03 15:21:18 +0300 |
---|---|---|
committer | Andreas Tolfsen <ato@mozilla.com> | 2017-06-03 15:21:18 +0300 |
commit | 4030c529d6b10b0d9e00cd08b5fb43579fe8a290 (patch) | |
tree | 66b5a3bd37a8d3aafba0c7cc7e6a5313e697e828 | |
parent | 60e7a430dc38a9e1921928c0cd996bb5fc00198b (diff) |
move canonical repo to mozilla-central
The canonical repository for geckodriver is henceforth in
mozilla-central's testing/geckodriver directory. Please submit any
future patches to the Testing :: geckodriver component in Bugzilla.
-rw-r--r-- | CHANGES.md | 327 | ||||
-rw-r--r-- | CONTRIBUTING.md | 97 | ||||
-rw-r--r-- | Cargo.lock | 775 | ||||
-rw-r--r-- | Cargo.toml | 31 | ||||
-rw-r--r-- | LICENSE | 373 | ||||
-rw-r--r-- | README.md | 16 | ||||
-rw-r--r-- | build.sh | 169 | ||||
-rw-r--r-- | ci.sh | 21 | ||||
-rw-r--r-- | i686-trusty/Dockerfile | 4 | ||||
-rw-r--r-- | src/capabilities.rs | 516 | ||||
-rw-r--r-- | src/logging.rs | 158 | ||||
-rw-r--r-- | src/main.rs | 177 | ||||
-rw-r--r-- | src/marionette.rs | 1579 | ||||
-rw-r--r-- | src/prefs.rs | 226 | ||||
-rw-r--r-- | src/tests/profile.zip | bin | 444 -> 0 bytes |
15 files changed, 15 insertions, 4454 deletions
diff --git a/CHANGES.md b/CHANGES.md deleted file mode 100644 index cd39073..0000000 --- a/CHANGES.md +++ /dev/null @@ -1,327 +0,0 @@ -# Change log - -All notable changes to this program is documented in this file. - -## 0.16.1 (2016-04-26) - -### Fixed -- Read Firefox version number from stdout when failing to look for the application .ini file (fixes [Selenium #3884](https://github.com/SeleniumHQ/selenium/issues/3884)) -- Session is now ended when closing the last Firefox window (fixes [#613](https://github.com/mozilla/geckodriver/issues/613)) - -## 0.16.0 (2016-04-21) - -Note that geckodriver v0.16.0 is only compatible with Selenium 3.4 and greater. - -### Added -- Support for WebDriver-conforming [New Session](https://w3c.github.io/webdriver/webdriver-spec.html#dfn-new-session) negotiation, with `desiredCapabilities`/`requiredCapabilities` negotiation as fallback -- Added two new endpoints: - - GET `/session/{session id}/window/rect` for [Get Window Rect](https://w3c.github.io/webdriver/webdriver-spec.html#get-window-rect) - - POST `/session/{session id}/window/rect` for [Set Window Rect](https://w3c.github.io/webdriver/webdriver-spec.html#set-window-rect) -- Align errors with the [WebDriver errors](https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors): - - Introduces new errors [`ElementClickIntercepted`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.ElementClickIntercepted), [`ElementNotInteractable`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.ElementNotInteractable), [`InvalidCoordinates`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.InvalidCoordinates), [`NoSuchCookie`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.NoSuchCookie), [`UnableToCaptureScreen`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.UnableToCaptureScreen), and [`UnknownCommand`](https://docs.rs/webdriver/0.25.0/webdriver/error/enum.ErrorStatus.html#variant.UnknownCommand) - - Removes `ElementNotVisible` and `InvalidElementCoordinates` errors - -### Removed -- Removed following list of unused endpoints: - - GET `/session/{session id}/alert_text` - - POST `/session/{session id}/alert_text` - - POST `/session/{session id}/accept_alert` - - POST `/session/{session id}/dismiss_alert` - - GET `/session/{session id}/window_handle` - - DELETE `/session/{session id}/window_handle` - - POST `/session/{session id}/execute_async` - - POST `/session/{session id}/execute` - -### Changed -- [`SendKeysParameters`](https://docs.rs/webdriver/0.25.0/webdriver/command/struct.SendKeysParameters.html), which is used for the [Element Send Keys](https://w3c.github.io/webdriver/webdriver-spec.html#element-send-keys) and [Send Alert Text](https://w3c.github.io/webdriver/webdriver-spec.html#send-alert-text) commands, has been updated to take a string `text` field -- [`CookieResponse`](https://docs.rs/webdriver/0.25.0/webdriver/response/struct.CookieResponse.html) and [`CloseWindowResponse`](https://docs.rs/webdriver/0.25.0/webdriver/response/struct.CloseWindowResponse.html) fixed to be properly wrapped in a `value` field, like other responses -- Allow negative numbers for `x` and `y` fields in `pointerMove` action -- Disable Flash and the plugin container in Firefox by default, which should help mitigate the “Plugin Container for Firefox has stopped wroking” problems [many users were reporting](https://github.com/mozilla/geckodriver/issues/225) when deleting a session -- Preferences passed in a profile now take precedence over set of default preferences defined by geckodriver (fixed by [@DrMarcII](https://github.com/DrMarcII)) - - The exceptions are the `marionette.port` and `marionette.log.level` preferences and their fallbacks, which are set unconditionally and cannot be overriden -- Remove default preference that disables unsafe CPOW checks -- WebDriver library updated to 0.25.2 - -### Fixed -- Fix for the “corrupt deflate stream” exception that sometimes occured when trying to write an empty profile by [@kirhgoph](https://github.com/kirhgoph) -- Recognise `sslProxy` and `sslProxyPort` entries in the proxy configuration object (fixed by [@juangj](https://github.com/juangj)) -- Fix “`httpProxyPort` was not an integer” error (fixed by [@juangj](https://github.com/juangj)) -- Fix broken unmarshaling of _Get Timeouts_ response format from Firefox 52 and earlier (fixed by [@juangj](https://github.com/juangj)) -- Allow preferences in `moz:firefoxOptions` to be both positive- and negative integers (fixed by [@juangj](https://github.com/juangj)) -- Allow IPv6 hostnames in the proxy configuration object -- i686-unknown-linux-musl (Linux 32-bit) build fixed -- Log messages from other Rust modules are now ignored -- Improved log messages to the HTTPD - -## 0.15.0 (2017-03-08) - -### Added -- Added routing and parsing for the [Get Timeouts](https://w3c.github.io/webdriver/webdriver-spec.html#dfn-get-timeouts) command - -### Changed -- All HTTP responses are now wrapped in `{value: …}` objects per the WebDriver specification; this may likely require you to update your client library -- Pointer move action’s `element` key changed to `origin`, which lets pointer actions originate within the context of the viewport, the pointer’s current position, or from an element -- Now uses about:blank as the new tab document; this was previously disabled due to [bug 1333736](https://bugzilla.mozilla.org/show_bug.cgi?id=1333736) in Marionette -- WebDriver libary updated to 0.23.0 - -### Fixed -- Aligned the data structure accepted by the [Set Timeouts](https://w3c.github.io/webdriver/webdriver-spec.html#set-timeouts) command with the WebDriver specification - -## 0.14.0 (2017-01-31) - -### Changed -- Firefox process is now terminated and session ended when the last window is closed -- WebDriver library updated to version 0.20.0 - -### Fixed -- Stacktraces are now included when the error originates from within the Rust stack -- HTTPD now returns correct response headers for `Content-Type` and `Cache-Control` thanks to @jugglinmike - -## 0.13.0 (2017-01-06) - -### Changed -- When navigating to a document with an insecure- or otherwise invalid TLS certificate, an [insecure certificate](https://w3c.github.io/webdriver/webdriver-spec.html#dfn-insecure-certificate) error will be returned -- On macOS, deducing Firefox’ location on the system will look for _firefox-bin_ on the system path (`PATH` environmental variable) before looking in the applications folder -- Window position coordinates are allowed to be negative numbers, to cater for maximised window positioning on Windows -- WebDriver library updated to version 0.18.0 - -### Fixed -- Check for single-character key codes in action sequences now counts characters instead of bytes - -## 0.12.0 (2017-01-03) - -### Added -- Added [_Take Element Screenshot_](https://w3c.github.io/webdriver/webdriver-spec.html#take-element-screenshot) command -- Added new [_Status_](https://w3c.github.io/webdriver/webdriver-spec.html#status) command -- Added routing for the [_Get Timeouts_](https://w3c.github.io/webdriver/webdriver-spec.html#get-timeouts) command, but it is not yet implemented in Marionette, and will return an _unsupported operation_ error until it is -- Implemented routing for [new actions API](https://w3c.github.io/webdriver/webdriver-spec.html#actions), but it too is not yet fully implemented in Marionette - -### Changed -- [Synced Firefox preferences](https://github.com/mozilla/geckodriver/commit/2bfdc3ec8151c427a6a75a6ba3ad203459540495) with those used in Mozilla automation -- Default log level for debug builds of Firefox, which used to be `DEBUG`, changed to `INFO`-level -- WebDriver library dependency upgraded to 0.17.1 -- Using _session not created_ error when failing to start session -- geckodriver will exit with exit code 69 to indicate that the port is unavailable - -### Fixed -- Improved logging when starting Firefox -- Reverted to synchronous logging, which should address cases of inconsistent output when failing to bind to port -- Clarified in README that geckodriver is not supported on Windows XP -- Added documentation of supported capabilities to [README](https://github.com/mozilla/geckodriver/blob/master/README.md) -- Included capabilities example in [README](https://github.com/mozilla/geckodriver/blob/master/README.md) - -## 0.11.1 (2016-10-10) - -### Fixed -- Version number in binary now reflects the release version. - -## 0.11.0 (2016-10-10) - -### Added -- Introduced continous integration builds for Linux- and Windows 32-bit binaries -- Added commands for setting- and getting the window position -- Added new extension commands for finding an element’s anonymous children and querying its attributes; accessible through the `/session/{sessionId}/moz/xbl/{elementId}/anonymous_children` to return all anonymous children and `/session/{sessionId}/moz/xbl/{elementId}/anonymous_by_attribute` to return an anonymous element by a name and attribute query -- Introduced a `moz:firefoxOptions` capability to customise a Firefox session: - - The `binary`, `args`, and `profile` entries on this dictionary is equivalent to the old `firefox_binary`, `firefox_args`, and `firefox_profile` capabilities, which have now all been removed - - The `log` capability takes a dictionary such as `{log: "trace"}` to enable trace level verbosity in Gecko - - The `prefs` capability lets you define Firefox preferences through capabilities -- Re-introduced the `--webdriver-port` argument as a hidden alias to `--port` - -### Changed -- `firefox_binary`, `firefox_args`, and `firefox_profile` capabilities removed in favour of the `moz:firefoxOptions` dictionary detailed above and in the README -- Removed `--no-e10s` flag, and geckodriver will from now rely on the Firefox default multiprocessing settings (override using preferences) -- Disable pop-up blocker in the default profile by @juangj -- Changed Rust compiler version to 1.12 (beta) temporarily because of [trouble linking Musl binaries](https://github.com/rust-lang/rust/issues/34978) -- Replaced _env_logger_ logging facility with the _slog_ package, causing the `RUST_LOG` environment variable to no longer have any affect -- Updated the WebDriver Rust library to version 0.15. - -### Fixed -- Corrected link to repository in Cargo metadata -- Verbosity shorthand flag `-v[v]` now works again, following the replacement of the argument parsing library in the previous release -- When the HTTPD fails to start, errors are propagated to the user -- Disabled the additional welcome URL (`startup.homepage_welcome_url.additional`) so that officially branded Firefox builds do not start with two open tabs in fresh profiles -- Disabled homepage override URL redirection on milestone upgrades, which means a tab with an upgrade notice is not displayed when launching a new Firefox version - -## 0.10.0 (2016-08-02) - -### Changed -- Use multi-process Firefox (e10s) by default, added flag `--no-e10s` to disable it and removed `--e10s` flag -- Disable autofilling of forms by default by @mythsunwind -- Replace _argparse_ with _clap_ for arguments parsing - -### Fixed -- Attempt to deploy a single file from Travis when making a release -- Grammar fix in README - - -## 0.9.0 (2016-06-30) - -### Added -- Add ability to use `firefox_binary` capability to define location of Firefox to use -- Automatically detect the default Firefox path if one is not given -- Cross-compile to Windows and ARMv7 (HF) in CI -- Add Musl C library-backed static binaries in CI -- Add `-v`, `-vv`, and `--log LEVEL` flags to increase Gecko verbosity -- Add Get Element Property endpoint -- Add new `--version` flag showing copying information and a link to the repository - -### Changed -- Now connects to a Marionette on a random port by default -- Update webdriver-rust library dependency -- Migrated to use Travis to deploy new releases -- Reduced amount of logging -- Introduced a changelog (this) - - -## 0.8.0 (2016-06-07) - -### Added -- Allow specifying array of arguments to the Firefox binary through the `firefox_args` capability -- Pass parameters with New Session command - -### Changed -- Change product name to _geckodriver_ -- Make README more exhaustive -- Quit Firefox when deleting a session -- Update webdriver-rust library -- Update dependencies - -### Fixed -- Fix tests -- FIx typo in error message for parsing errors - - -## 0.7.1 (2016-04-27) - -### Added -- Add command line flag for using e10s enabeld Firefox by @martionsideofthemoon -- Allow providing custom profiels - -### Changed -- Allow binding to an IPv6 address by @juangj -- By default, connect to host-agnostic localhost by @juangj -- Make `GeckoContextParameters` public -- Update dependencies - -### Fixed -- Squash rustc 1.6 warnings by using `std::thread::sleep(dur: Duration)` - - -## 0.6.2 (2016-01-20) - -### Added -- Add LICENSE file from @joshbruning -- Schedule builds in CI on pushes and pull requests - -### Changed -- Enable CPOWs in Marionette - - -## 0.6.0 (2016-01-12) - -### Added -- Add Get Page Source endpoint - -### Changed -- Handle arrays being sent from Marionette -- Correct build steps in README -- Update what properties are read from errors sent by Marionette -- Update dependencies - - -## 0.5.0 (2015-12-10) - -### Changed -- Update argparse dependency to use Cargo -- Update to the latest version of the Marionette wire protocol -- Update to latest webdriver-rust library -- Update dependencies - - -## 0.4.2 (2015-10-02) - -### Changed -- Skip compiling optional items in hyper - - -## 0.4.1 (2015-10-02) - -### Changed -- Update webdriver-rust library -- Update dependencies - - -## 0.4.0 (2015-09-28) - -### Added -- Add command extensions for switching between content- and chrome contexts -- Add more documentation from @vladikoff - -### Changed -- Update Cargo.lock with new dependencies for building -- Update for protocol updates that flatten commands -- Update to new protocol error handling -- Update for Marionette protocol version 3 changes -- Strip any leading and trailing `{}` from the `sessionId` Marionette returns -- Update dependencies - -### Fixed -- Fix `GetCSSValue` message to send correct key `propertyName` -- Fix example in documentation from @vladikoff - - -## 0.3.0 (2015-08-17) - -### Added -- Add support for finding elements in subtrees - - -## 0.2.0 (2015-05-20) - -### Added -- Extra debug messages -- Add ability to set WebDriver port -- Add support for getting the active element -- Add support for `GetCookies` and `DeleteCookie`/`DeleteCookies` -- Add preferences that switch off certain features not required for WebDriver tests - -### Changed -- Make failing to communicate with Firefox a fatal error that closes the session -- Shut down session only when loosing connection -- Better handling of missing command line flags -- Poll for connection every 100ms rather than every 100s -- Switch to string-based error codes -- Switch webdriver-rust library dependency to be pulled from git -- Update dependencies - -### Fixed -- Handle null id for switching to frame more correctly - - -## 0.1.0 (2015-04-09) - -### Added -- Add proxy for converting WebDriver HTTP protocol to Marionette protocol -- Add endpoints for modal dialogue support -- Allow connecting to a running Firefox instance -- Add explicit Cargo.lock file -- Start Firefox when we get a New Session command -- Add flag parsing and address parsing -- Add basic error handling - -### Changed -- Update for Rust beta -- Switch to new IO libraries -- Pin webdriver-rust commit so we can upgrade rustc versions independently -- Set preferences when starting Firefox -- Improve some error messages -- Re-enable environment variable based logging - -### Fixed -- Fix Get Element Rect command to return floats instead of integers -- Fix passing of web elements to Switch To Frame command -- Fix serialisation of script commands -- Fix assorted bugs found by the Selenium test suite -- Fix conversion of Find Element/Find Elements responses from Marionette to WebDriver -- Fixed build by updating Cargo.lock with new dependencies for building -- Squash compile warnings diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index ca22acb..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,97 +0,0 @@ -# Contributing to geckodriver - -The geckodriver project welcomes contributions from everyone. There are a -number of ways you can help: - -## Issue Reports - -When opening new issues or commenting on existing issues please make -sure discussions are related to concrete technical issues with the -geckodriver or Marionette software. - -For issue reports to be actionable, it must be clear exactly what the -observed and expected behaviours are, and how to set up the state required -to observe the erroneous behaviour. The most useful thing to provide is a -minimal HTML file which allows the problem to be reproduced, plus a -trace-level log from geckodriver showing the wire-protocol calls used to set -up the problem. Please provide [concise reproducible test -cases](http://sscce.org/) and describe what results you are seeing and what -results you expect. Because of the wide variety of client bindings for -WebDriver, clients scripts and logs are typically not very useful if the -verbose geckodriver logs are available. Issues relating to a specific client -should be filed in the issue tracker of that project. - -## Code Contributions - -If you're looking for easy bugs, have a look at -[issues labelled E-easy](https://github.com/mozilla/geckodriver/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3Aeasy+) -on Github. - -This document will guide you through the contribution process. - -### Step 1: Fork - -Fork the project [on Github](https://github.com/mozilla/geckodriver) -and check out your copy locally. - -```text -% git clone git@github.com:username/geckodriver.git -% cd geckodriver -% git remote add upstream git://github.com/mozilla/geckodriver.git -``` - -### Step 2: Branch - -Create a feature branch and start hacking: - -```text -% git checkout -b my-feature-branch -``` - -We practice HEAD-based development, which means all changes are applied -directly on top of master. - -### Step 3: Commit - -First make sure git knows your name and email address: - -```text -% git config --global user.name 'Santa Claus' -% git config --global user.email 'santa@example.com' -``` - -The first line must be meaningful as it's what people see when they -run `git shortlog` or `git log --oneline`. - -### Step 4: Rebase - -Use `git rebase` (not `git merge`) to sync your work from time to time. - -```text -% git fetch upstream -% git rebase upstream/master -``` - -### Step 5: Push - -```text -% git push my-feature-branch -``` - -Go to https://github.com/yourusername/geckodriver and press the _Pull -Request_ and fill out the form. - -Pull requests are usually reviewed within a few days. Reviews will be done -through [Reviewable](https://reviewable.io/reviews/mozilla/geckodriver) - -### Step 6: Integration - -When code review is complete, a committer will take your PR and -integrate it on geckodriver's master branch. Because we like to keep a -linear history on the master branch, we will normally squash and rebase -your branch history. - -## Communication - -geckodriver contributors frequent the `#ateam` channel on -[`irc.mozilla.org`](http://chat.mibbit.com/?server=irc.mozilla.org:#ateam). diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 258e639..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,775 +0,0 @@ -[root] -name = "geckodriver" -version = "0.16.1" -dependencies = [ - "chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mozprofile 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mozrunner 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mozversion 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-atomic 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-stdlog 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-stream 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "webdriver 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "advapi32-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bzip2" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bzip2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cfg-if" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clap" -version = "2.23.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cookie" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dbghelp-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.45" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "httparse" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hyper" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "isatty" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ktmw32-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "matches" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mozprofile" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mozrunner" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mozprofile 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winreg 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mozversion" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-ini 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "msdos_time" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "podio" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "regex" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rust-ini" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slog" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slog-atomic" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-extra" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-stdlog" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-stream" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-extra 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-term" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", - "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-stream 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strsim" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "term_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread-id" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-segmentation" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "url" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uuid" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "vec_map" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "webdriver" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winreg" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ktmw32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zip" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "307c92332867e586720c0222ee9d890bbe8431711efed8a1b06bc5b40fc66bd7" -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80" -"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" -"checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24" -"checksum bzip2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "98ce3fff84d4e90011f464bbdf48e3428f04270439f703868fd489d2aaedfc30" -"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" -"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" -"checksum clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f57e9b63057a545ad2ecd773ea61e49422ed1b1d63d74d5da5ecaee55b3396cd" -"checksum cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce776927cd64cbe74ebd1d9b375edb9d1b6bfa808618ddf9548645e019ebdfbb" -"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" -"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" -"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" -"checksum httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77f756bed9ee3a83ce98774f4155b42a31b787029013f3a7d83eca714e500e21" -"checksum hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)" = "94da93321c171e26481afeebe8288757b0501901b7c5492648163d8ec4942ec5" -"checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375" -"checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f" -"checksum kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e014dab1082fd9d80ea1fa6fcb261b47ed3eb511612a14198bb507701add083e" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum ktmw32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f9313a869ff779ae08dd990b75a92dc06aa16d771f41305f7286649cd39a0ee" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" -"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" -"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5514f038123342d01ee5f95129e4ef1e0470c93bc29edf058a46f9ee3ba6737e" -"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" -"checksum mozprofile 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4981de229fba7d949465a2f564e2b46906c6e876516040416956a54021a84165" -"checksum mozrunner 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "91c54a746e7430326d2bc48a5b10ba7e9cd2294306773cb9f232835abe791f02" -"checksum mozversion 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76acea204db8c94a612821e0ddc5e4513e46af21fdbd8c15b8efe13b343062f0" -"checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958" -"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40" -"checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37" -"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" -"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" -"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" -"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" -"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" -"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rust-ini 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06d4e8b0b50e7e7f827d609fa9746e1cf6371a1fa15404a1a0a86152a801079f" -"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" -"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" -"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bab9d589681f7d6b9ca4ed5cc861779a392bca7beaae2f69f2341617415a78dc" -"checksum slog-atomic 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6f5a4e4908d6818fe553b6126ba5377801556ab885c65ebf960b722a6778864" -"checksum slog-extra 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "511581f4dd1dc90e4eca99b60be8a692d9c975e8757558aa774f16007d27492a" -"checksum slog-stdlog 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56cc08f40c45e0ab41dcfde0a19a22c5b7176d3827fc7d078450ebfdc080a37c" -"checksum slog-stream 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f0fee00b80a7a44f82c5cf44ba03b6dc2712f9c14469a62ad90ea0911635c5" -"checksum slog-term 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb53c0bae0745898fd5a7b75b1c389507333470ac4c645ae431890c0f828b6ca" -"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" -"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" -"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" -"checksum time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd7ccbf969a892bf83f1e441126968a07a3941c24ff522a26af9f9f4585d1a3" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" -"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" -"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" -"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" -"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f" -"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum webdriver 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d161bc62ed766ddc0838af89f1b339ed3c8b5c3dbe8776b59731dfae7b1a6c7" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winreg 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e63857fb213f619b4c4fff86b158285c76766aac7e7474967e92fb6dbbfeefe9" -"checksum zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c0deac03fc7d43abcf19f2c2db6bd9289f9ea3d31f350e26eb0ed8b4117983c1" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index e3bc8d4..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "geckodriver" -version = "0.16.1" -authors = [ - "James Graham <james@hoppipolla.co.uk>", - "Andreas Tolfsen <ato@mozilla.com>", -] -description = "Proxy for using WebDriver clients to interact with Gecko-based browsers." -keywords = ["webdriver", "w3c", "httpd", "mozilla", "firefox"] -repository = "https://github.com/mozilla/geckodriver" -readme = "README.md" -license = "MPL-2.0" - -[dependencies] -chrono = "^0.2" -clap = {version = "^2.19", default-features = false, features = ["suggestions", "wrap_help"]} -hyper = "0.10" -lazy_static = "0.1" -log = "0.3" -mozprofile = "0.2" -mozrunner = "0.3" -mozversion = "0.1" -regex = "0.2" -rustc-serialize = "0.3" -slog = "1" -slog-atomic = "0.4" -slog-stdlog = "1" -slog-stream = "1" -uuid = "0.1.18" -webdriver = "0.25" -zip = "0.1" diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 14e2f77..0000000 --- a/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - 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/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. @@ -1,4 +1,4 @@ -# geckodriver [![Build Status](https://travis-ci.org/mozilla/geckodriver.svg?branch=master)](https://travis-ci.org/mozilla/geckodriver) +# geckodriver Proxy for using W3C WebDriver-compatible clients to interact with Gecko-based browsers. @@ -533,3 +533,17 @@ Or if you want a non-optimised binary for debugging: [WebDriver]: https://w3c.github.io/webdriver/webdriver-spec.html [Marionette]: http://searchfox.org/mozilla-central/source/testing/marionette/README [Rust compiler toolchain]: https://rustup.rs/ + +## Contributing + +The canonical source code repository for geckodriver +now lives in [mozilla-central] under [testing/geckodriver]. +You can read more about [working with Mozilla source code] on MDN. +This means we do no longer accept pull requests on GitHub. +Patches should be uploaded to a bug +in the [Testing :: GeckoDriver] component. + +[mozilla-central]: https://hg.mozilla.org/mozilla-central/ +[testing/geckodriver]: https://hg.mozilla.org/mozilla-central/file/tip/testing/geckodriver +[working with Mozilla source code]: https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Source_Code +[Testing :: geckodriver]: https://bugzilla.mozilla.org/buglist.cgi?product=Testing&component=geckodriver&resolution=---&list_id=13613952 diff --git a/build.sh b/build.sh deleted file mode 100644 index 8bf54e9..0000000 --- a/build.sh +++ /dev/null @@ -1,169 +0,0 @@ -set -ex - -print_versions() { - rustc -V - cargo -V - cc --version -} - -rustup_install() { - export PATH="$PATH:$HOME/.cargo/bin" - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$1 -} - -# Add provided target to current Rust toolchain if it is not already -# the default or installed. -rustup_target_add() { - if ! rustup target list | grep -E "$1 \((default|installed)\)" - then - rustup target add $1 - fi -} - -setup_docker() { - apt-get -qq -y install zip - cd /mnt/host -} - -mingw_i686_install() { - curl https://static.rust-lang.org/dist/rust-mingw-nightly-i686-pc-windows-gnu.tar.gz \ - | tar xzvf - -C /tmp - /tmp/rust-mingw-nightly-i686-pc-windows-gnu/install.sh --prefix=`rustc --print sysroot` -} - -# Configure rustc target for cross compilation. Provided with a build -# target, this will determine which linker to use for cross compilation. -cargo_config() { - local prefix - - case "$TARGET" in - aarch64-unknown-linux-gnu) - prefix=aarch64-linux-gnu - ;; - arm*-unknown-linux-gnueabihf) - prefix=arm-linux-gnueabihf - ;; - arm-unknown-linux-gnueabi) - prefix=arm-linux-gnueabi - ;; - mipsel-unknown-linux-musl) - prefix=mipsel-openwrt-linux - ;; - x86_64-pc-windows-gnu) - prefix=x86_64-w64-mingw32 - ;; - i686-pc-windows-gnu) - prefix=i686-w64-mingw32 - ;; - *) - return - ;; - esac - - mkdir -p ~/.cargo - cat >~/.cargo/config <<EOF -[target.$TARGET] -linker = "$prefix-gcc" -EOF - - cat ~/.cargo/config -} - -# Build current crate for given target and print file type information. -# If the second argument is set, a release build will be made. -cargo_build() { - local mode - if [ -z "$2" ] - then - mode=debug - else - mode=release - fi - - local modeflag - if [ "$mode" == "release" ] - then - modeflag=--release - fi - - cargo build --target $1 $modeflag - - file $(get_binary $1 $mode) -} - -# Run current crate's tests if the current system supports it. -cargo_test() { - if echo "$1" | grep -E "(i686|x86_64)-unknown-linux-(gnu|musl)|darwin" - then - cargo test --target $1 - fi -} - -# Returns relative path to binary -# based on build target and type ("release"/"debug"). -get_binary() { - local ext - if [[ "$1" =~ "windows" ]] - then - ext=".exe" - fi - echo "target/$1/$2/geckodriver$ext" -} - -# Create a compressed archive of the binary -# for the given given git tag, build target, and build type. -package_binary() { - local bin - bin=$(get_binary $2 $4) - cp $bin . - - if [[ "$2" =~ "windows" ]] - then - filename="geckodriver-$1-$3.zip" - zip "$filename" geckodriver.exe - file "$filename" - else - filename="geckodriver-$1-$3.tar.gz" - tar zcvf "$filename" geckodriver - file "$filename" - fi - if [ ! -z "$DOCKER_IMAGE" ] - then - chown "$USER_ID:$GROUP_ID" "$filename" - fi -} - -main() { - TOOLCHAIN=${TOOLCHAIN:=stable} - - if [ ! -z "$DOCKER_IMAGE" ] - then - setup_docker - fi - - rustup_install $TOOLCHAIN - print_versions - rustup_target_add $TARGET - - # custom mingw component required - # when compiling on 32-bit windows - # see https://github.com/mozilla/geckodriver/pull/138#issuecomment-232139097 - if [[ $TARGET == "i686-pc-windows-gnu" ]] - then - mingw_i686_install - fi - - cargo_config $TARGET - cargo_build $TARGET - cargo_test $TARGET - - # when something is tagged, - # also create a release build and package it - if [ ! -z "$TRAVIS_TAG" ] - then - cargo_build $TARGET 1 - package_binary $TRAVIS_TAG $TARGET $NAME "release" - fi -} - -main @@ -1,21 +0,0 @@ -set -ex - -if [ ! -z "$DOCKER_IMAGE" ] -then - tag="$DOCKER_IMAGE/latest" - docker build $DOCKER_IMAGE -t $tag - docker run \ - -e USER="$USER" \ - -e TARGET="$TARGET" \ - -e TOOLCHAIN="$TOOLCHAIN" \ - -e DOCKER_IMAGE="$DOCKER_IMAGE" \ - -e NAME="$NAME" \ - -e TRAVIS_TAG="$TRAVIS_TAG" \ - -e USER_ID=$(id -u) \ - -e GROUP_ID=$(id -g) \ - -v $PWD:/mnt/host \ - -i $tag \ - bash -s -- < build.sh -else - bash build.sh -fi diff --git a/i686-trusty/Dockerfile b/i686-trusty/Dockerfile deleted file mode 100644 index 4d2480f..0000000 --- a/i686-trusty/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM ubuntu:15.10 - -RUN apt-get -y update -RUN apt-get -y install curl file gcc gcc-mingw-w64-i686 zip diff --git a/src/capabilities.rs b/src/capabilities.rs deleted file mode 100644 index ce7a1bc..0000000 --- a/src/capabilities.rs +++ /dev/null @@ -1,516 +0,0 @@ -use logging::LogLevel; -use marionette::LogOptions; -use mozprofile::preferences::Pref; -use mozprofile::profile::Profile; -use mozrunner::runner::platform::firefox_default_path; -use mozversion::{self, firefox_version, Version}; -use regex::bytes::Regex; -use rustc_serialize::base64::FromBase64; -use rustc_serialize::json::Json; -use std::collections::BTreeMap; -use std::default::Default; -use std::error::Error; -use std::fs; -use std::io::BufWriter; -use std::io::Cursor; -use std::io; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::str::{self, FromStr}; -use webdriver::capabilities::{BrowserCapabilities, Capabilities}; -use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; -use zip; - -/// Provides matching of `moz:firefoxOptions` and resolution of which Firefox -/// binary to use. -/// -/// `FirefoxCapabilities` is constructed with the fallback binary, should -/// `moz:firefoxOptions` not contain a binary entry. This may either be the -/// system Firefox installation or an override, for example given to the -/// `--binary` flag of geckodriver. -pub struct FirefoxCapabilities<'a> { - pub chosen_binary: Option<PathBuf>, - fallback_binary: Option<&'a PathBuf>, - version_cache: BTreeMap<PathBuf, String>, -} - - -impl<'a> FirefoxCapabilities<'a> { - pub fn new(fallback_binary: Option<&'a PathBuf>) -> FirefoxCapabilities<'a> { - FirefoxCapabilities { - chosen_binary: None, - fallback_binary: fallback_binary, - version_cache: BTreeMap::new(), - } - } - - fn set_binary(&mut self, capabilities: &BTreeMap<String, Json>) { - self.chosen_binary = capabilities - .get("moz:firefoxOptions") - .and_then(|x| x.find("binary")) - .and_then(|x| x.as_string()) - .map(|x| PathBuf::from(x)) - .or_else(|| self.fallback_binary.map(|x| x.clone())) - .or_else(|| firefox_default_path()) - .and_then(|x| x.canonicalize().ok()) - } - - fn version(&mut self) -> Option<String> { - if let Some(ref binary) = self.chosen_binary { - if let Some(value) = self.version_cache.get(binary) { - return Some((*value).clone()); - } - debug!("Trying to read firefox version from ini files"); - let rv = firefox_version(&*binary) - .ok() - .and_then(|x| x.version_string) - .or_else(|| { - debug!("Trying to read firefox version from binary"); - self.version_from_binary(binary) - }); - if let Some(ref version) = rv { - debug!("Found version {}", version); - self.version_cache - .insert(binary.clone(), version.clone()); - } else { - debug!("Failed to get binary version"); - } - rv - } else { - None - } - } - - fn version_from_binary(&self, binary: &PathBuf) -> Option<String> { - let version_regexp = Regex::new(r#"\d+\.\d+(?:[a-z]\d+)?"#).expect("Error parsing version regexp"); - let output = Command::new(binary) - .args(&["-version"]) - .stdout(Stdio::piped()) - .spawn() - .and_then(|child| child.wait_with_output()) - .ok(); - - if let Some(x) = output { - version_regexp.captures(&*x.stdout) - .and_then(|captures| captures.get(0)) - .and_then(|m| str::from_utf8(m.as_bytes()).ok()) - .map(|x| x.into()) - } else { - None - } - } -} - -// TODO: put this in webdriver-rust -fn convert_version_error(err: mozversion::Error) -> WebDriverError { - WebDriverError::new( - ErrorStatus::SessionNotCreated, - err.description().to_string()) -} - -impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> { - fn init(&mut self, capabilities: &Capabilities) { - self.set_binary(capabilities); - } - - fn browser_name(&mut self, _: &Capabilities) -> WebDriverResult<Option<String>> { - Ok(Some("firefox".into())) - } - - fn browser_version(&mut self, _: &Capabilities) -> WebDriverResult<Option<String>> { - Ok(self.version()) - } - - fn platform_name(&mut self, _: &Capabilities) -> WebDriverResult<Option<String>> { - Ok(if cfg!(target_os = "windows") { - Some("windows".into()) - } else if cfg!(target_os = "macos") { - Some("mac".into()) - } else if cfg!(target_os = "linux") { - Some("linux".into()) - } else { - None - }) - } - - fn accept_insecure_certs(&mut self, _: &Capabilities) -> WebDriverResult<bool> { - let version_str = self.version(); - if let Some(x) = version_str { - Ok(try!(Version::from_str(&*x).or_else(|x| Err(convert_version_error(x)))).major >= 52) - } else { - Ok(false) - } - } - - fn compare_browser_version(&mut self, - version: &str, - comparison: &str) - -> WebDriverResult<bool> { - try!(Version::from_str(version).or_else(|x| Err(convert_version_error(x)))) - .matches(comparison) - .or_else(|x| Err(convert_version_error(x))) - } - - fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> { - Ok(true) - } - - fn validate_custom(&self, name: &str, value: &Json) -> WebDriverResult<()> { - if !name.starts_with("moz:") { - return Ok(()) - } - match name { - "moz:firefoxOptions" => { - let data = try_opt!(value.as_object(), - ErrorStatus::InvalidArgument, - "moz:firefoxOptions is not an object"); - for (key, value) in data.iter() { - match &**key { - "binary" => { - if !value.is_string() { - return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - "binary path is not a string")); - } - }, - "args" => { - if !try_opt!(value.as_array(), - ErrorStatus::InvalidArgument, - "args is not an array") - .iter() - .all(|value| value.is_string()) { - return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - "args entry is not a string")); - } - }, - "profile" => { - if !value.is_string() { - return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - "profile is not a string")); - } - }, - "log" => { - let log_data = try_opt!(value.as_object(), - ErrorStatus::InvalidArgument, - "log value is not an object"); - for (log_key, log_value) in log_data.iter() { - match &**log_key { - "level" => { - let level = try_opt!(log_value.as_string(), - ErrorStatus::InvalidArgument, - "log level is not a string"); - if LogLevel::from_str(level).is_err() { - return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - format!("{} is not a valid log level", - level))) - } - } - x => return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - format!("Invalid log field {}", x))) - } - } - }, - "prefs" => { - let prefs_data = try_opt!(value.as_object(), - ErrorStatus::InvalidArgument, - "prefs value is not an object"); - if !prefs_data.values() - .all(|x| x.is_string() || x.is_i64() || x.is_u64() || x.is_boolean()) { - return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - "Preference values not all string or integer or boolean")); - } - } - x => return Err(WebDriverError::new( - ErrorStatus::InvalidArgument, - format!("Invalid moz:firefoxOptions field {}", x))) - } - } - } - _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument, - format!("Unrecognised option {}", name))) - } - Ok(()) - } - - fn accept_custom(&mut self, _: &str, _: &Json, _: &Capabilities) -> WebDriverResult<bool> { - Ok(true) - } -} - -/// Rust representation of `moz:firefoxOptions`. -/// -/// Calling `FirefoxOptions::from_capabilities(binary, capabilities)` causes -/// the encoded profile, the binary arguments, log settings, and additional -/// preferences to be checked and unmarshaled from the `moz:firefoxOptions` -/// JSON Object into a Rust representation. -#[derive(Default)] -pub struct FirefoxOptions { - pub binary: Option<PathBuf>, - pub profile: Option<Profile>, - pub args: Option<Vec<String>>, - pub log: LogOptions, - pub prefs: Vec<(String, Pref)>, -} - -impl FirefoxOptions { - pub fn new() -> FirefoxOptions { - Default::default() - } - - pub fn from_capabilities(binary_path: Option<PathBuf>, - matched: &mut Capabilities) - -> WebDriverResult<FirefoxOptions> { - let mut rv = FirefoxOptions::new(); - rv.binary = binary_path; - - if let Some(json) = matched.remove("moz:firefoxOptions") { - let options = try!(json.as_object() - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "'moz:firefoxOptions' \ - capability is not an object"))); - - rv.profile = try!(FirefoxOptions::load_profile(&options)); - rv.args = try!(FirefoxOptions::load_args(&options)); - rv.log = try!(FirefoxOptions::load_log(&options)); - rv.prefs = try!(FirefoxOptions::load_prefs(&options)); - } - - Ok(rv) - } - - fn load_profile(options: &Capabilities) -> WebDriverResult<Option<Profile>> { - if let Some(profile_json) = options.get("profile") { - let profile_base64 = - try!(profile_json - .as_string() - .ok_or(WebDriverError::new(ErrorStatus::UnknownError, - "Profile is not a string"))); - let profile_zip = &*try!(profile_base64.from_base64()); - - // Create an emtpy profile directory - let profile = try!(Profile::new(None)); - try!(unzip_buffer(profile_zip, - profile - .temp_dir - .as_ref() - .expect("Profile doesn't have a path") - .path())); - - Ok(Some(profile)) - } else { - Ok(None) - } - } - - fn load_args(options: &Capabilities) -> WebDriverResult<Option<Vec<String>>> { - if let Some(args_json) = options.get("args") { - let args_array = try!(args_json - .as_array() - .ok_or(WebDriverError::new(ErrorStatus::UnknownError, - "Arguments were not an \ - array"))); - let args = try!(args_array - .iter() - .map(|x| x.as_string().map(|x| x.to_owned())) - .collect::<Option<Vec<String>>>() - .ok_or(WebDriverError::new(ErrorStatus::UnknownError, - "Arguments entries were not all \ - strings"))); - Ok(Some(args)) - } else { - Ok(None) - } - } - - fn load_log(options: &Capabilities) -> WebDriverResult<LogOptions> { - if let Some(json) = options.get("log") { - let log = try!(json.as_object() - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "Log section is not an object"))); - - let level = match log.get("level") { - Some(json) => { - let s = try!(json.as_string() - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "Log level is not a string"))); - Some(try!(LogLevel::from_str(s) - .ok() - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "Log level is unknown")))) - } - None => None, - }; - - Ok(LogOptions { level: level }) - - } else { - Ok(Default::default()) - } - } - - pub fn load_prefs(options: &Capabilities) -> WebDriverResult<Vec<(String, Pref)>> { - if let Some(prefs_data) = options.get("prefs") { - let prefs = try!(prefs_data - .as_object() - .ok_or(WebDriverError::new(ErrorStatus::UnknownError, - "Prefs were not an object"))); - let mut rv = Vec::with_capacity(prefs.len()); - for (key, value) in prefs.iter() { - rv.push((key.clone(), try!(pref_from_json(value)))); - } - Ok(rv) - } else { - Ok(vec![]) - } - } -} - -fn pref_from_json(value: &Json) -> WebDriverResult<Pref> { - match value { - &Json::String(ref x) => Ok(Pref::new(x.clone())), - &Json::I64(x) => Ok(Pref::new(x)), - &Json::U64(x) => Ok(Pref::new(x as i64)), - &Json::Boolean(x) => Ok(Pref::new(x)), - _ => Err(WebDriverError::new(ErrorStatus::UnknownError, - "Could not convert pref value to string, boolean, or integer")) - } -} - -fn unzip_buffer(buf: &[u8], dest_dir: &Path) -> WebDriverResult<()> { - let reader = Cursor::new(buf); - let mut zip = try!(zip::ZipArchive::new(reader).map_err(|_| { - WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile") - })); - - for i in 0..zip.len() { - let mut file = try!(zip.by_index(i).map_err(|_| { - WebDriverError::new(ErrorStatus::UnknownError, "Processing profile zip file failed") - })); - let unzip_path = { - let name = file.name(); - let is_dir = name.ends_with("/"); - let rel_path = Path::new(name); - let dest_path = dest_dir.join(rel_path); - - { - let create_dir = if is_dir { - Some(dest_path.as_path()) - } else { - dest_path.parent() - }; - if let Some(dir) = create_dir { - if !dir.exists() { - debug!("Creating profile directory tree {}", dir.to_string_lossy()); - try!(fs::create_dir_all(dir)); - } - } - } - - if is_dir { - None - } else { - Some(dest_path) - } - }; - - if let Some(unzip_path) = unzip_path { - debug!("Extracting profile to {}", unzip_path.to_string_lossy()); - let dest = try!(fs::File::create(unzip_path)); - if file.size() > 0 { - let mut writer = BufWriter::new(dest); - try!(io::copy(&mut file, &mut writer)); - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - extern crate mozprofile; - extern crate rustc_serialize; - - use self::mozprofile::preferences::Pref; - use self::rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64}; - use self::rustc_serialize::json::Json; - use super::FirefoxOptions; - use marionette::MarionetteHandler; - use std::collections::BTreeMap; - use std::default::Default; - use std::fs::File; - use std::io::Read; - - use webdriver::capabilities::Capabilities; - - fn example_profile() -> Json { - let mut profile_data = Vec::with_capacity(1024); - let mut profile = File::open("src/tests/profile.zip").unwrap(); - profile.read_to_end(&mut profile_data).unwrap(); - let base64_config = Config { - char_set: CharacterSet::Standard, - newline: Newline::LF, - pad: true, - line_length: None, - }; - Json::String(profile_data.to_base64(base64_config)) - } - - fn make_options(firefox_opts: Capabilities) -> FirefoxOptions { - let mut caps = Capabilities::new(); - caps.insert("moz:firefoxOptions".into(), Json::Object(firefox_opts)); - let binary = None; - FirefoxOptions::from_capabilities(binary, &mut caps).unwrap() - } - - #[test] - fn test_profile() { - let encoded_profile = example_profile(); - let mut firefox_opts = Capabilities::new(); - firefox_opts.insert("profile".into(), encoded_profile); - - let opts = make_options(firefox_opts); - let mut profile = opts.profile.unwrap(); - let prefs = profile.user_prefs().unwrap(); - - println!("{:#?}", prefs.prefs); - - assert_eq!(prefs.get("startup.homepage_welcome_url"), - Some(&Pref::new("data:text/html,PASS"))); - } - - #[test] - fn test_prefs() { - let encoded_profile = example_profile(); - let mut prefs: BTreeMap<String, Json> = BTreeMap::new(); - prefs.insert("browser.display.background_color".into(), - Json::String("#00ff00".into())); - - let mut firefox_opts = Capabilities::new(); - firefox_opts.insert("profile".into(), encoded_profile); - firefox_opts.insert("prefs".into(), Json::Object(prefs)); - - let opts = make_options(firefox_opts); - let mut profile = opts.profile.unwrap(); - - let handler = MarionetteHandler::new(Default::default()); - handler - .set_prefs(2828, &mut profile, true, opts.prefs) - .unwrap(); - - let prefs_set = profile.user_prefs().unwrap(); - println!("{:#?}", prefs_set.prefs); - - assert_eq!(prefs_set.get("startup.homepage_welcome_url"), - Some(&Pref::new("data:text/html,PASS"))); - assert_eq!(prefs_set.get("browser.display.background_color"), - Some(&Pref::new("#00ff00"))); - assert_eq!(prefs_set.get("marionette.defaultPrefs.port"), - Some(&Pref::new(2828))); - } -} diff --git a/src/logging.rs b/src/logging.rs deleted file mode 100644 index 2cbff7e..0000000 --- a/src/logging.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::fmt; -use std::io; -use std::str::FromStr; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::SeqCst; - -use chrono::{DateTime, Local}; -use slog; -use slog::DrainExt; -use slog_atomic::{AtomicSwitch, AtomicSwitchCtrl}; -use slog_stream::{stream, Format, Streamer}; -use slog::Level as SlogLevel; -use slog::{LevelFilter, Logger}; -use slog::{OwnedKeyValueList, Record}; -use slog_stdlog; - -lazy_static! { - static ref ATOMIC_DRAIN: AtomicSwitchCtrl<io::Error> = AtomicSwitch::new( - slog::Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should not happen")) - ).ctrl(); - static ref FIRST_RUN: AtomicBool = AtomicBool::new(true); -} - -static DEFAULT_LEVEL: &'static LogLevel = &LogLevel::Info; - -/// Logger levels from [Log.jsm] -/// (https://developer.mozilla.org/en/docs/Mozilla/JavaScript_code_modules/Log.jsm). -#[derive(Debug, Clone)] -pub enum LogLevel { - Fatal, - Error, - Warn, - Info, - Config, - Debug, - Trace, -} - -impl fmt::Display for LogLevel { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match *self { - LogLevel::Fatal => "FATAL", - LogLevel::Error => "ERROR", - LogLevel::Warn => "WARN", - LogLevel::Info => "INFO", - LogLevel::Config => "CONFIG", - LogLevel::Debug => "DEBUG", - LogLevel::Trace => "TRACE", - }; - write!(f, "{}", s) - } -} - -impl FromStr for LogLevel { - type Err = (); - - fn from_str(s: &str) -> Result<LogLevel, ()> { - match s { - "fatal" => Ok(LogLevel::Fatal), - "error" => Ok(LogLevel::Error), - "warn" => Ok(LogLevel::Warn), - "info" => Ok(LogLevel::Info), - "config" => Ok(LogLevel::Config), - "debug" => Ok(LogLevel::Debug), - "trace" => Ok(LogLevel::Trace), - _ => Err(()), - } - } -} - -trait ToSlogLevel { - fn to_slog(&self) -> SlogLevel; -} - -impl ToSlogLevel for LogLevel { - fn to_slog(&self) -> SlogLevel { - match *self { - LogLevel::Fatal => SlogLevel::Critical, - LogLevel::Error => SlogLevel::Error, - LogLevel::Warn => SlogLevel::Warning, - LogLevel::Info => SlogLevel::Info, - LogLevel::Config | LogLevel::Debug => SlogLevel::Debug, - LogLevel::Trace => SlogLevel::Trace, - } - } -} - -trait ToGeckoLevel { - fn to_gecko(&self) -> LogLevel; -} - -impl ToGeckoLevel for SlogLevel { - fn to_gecko(&self) -> LogLevel { - match *self { - SlogLevel::Critical => LogLevel::Fatal, - SlogLevel::Error => LogLevel::Error, - SlogLevel::Warning => LogLevel::Warn, - SlogLevel::Info => LogLevel::Info, - SlogLevel::Debug => LogLevel::Debug, - SlogLevel::Trace => LogLevel::Trace, - } - } -} - -/// Initialise logger if it has not been already. The provided `level` -/// filters out log records below this granularity. -pub fn init(level: &Option<LogLevel>) { - let effective_level = level.as_ref().unwrap_or(DEFAULT_LEVEL); - - let drain = filtered_gecko_log(&effective_level); - ATOMIC_DRAIN.set(drain); - - let first_run = FIRST_RUN.load(SeqCst); - FIRST_RUN.store(false, SeqCst); - if first_run { - let log = Logger::root(ATOMIC_DRAIN.drain().fuse(), o!()); - slog_stdlog::set_logger(log.clone()).unwrap(); - } -} - -fn filtered_gecko_log(level: &LogLevel) -> LevelFilter<Streamer<io::Stderr, GeckoFormat>> { - let io = stream(io::stderr(), GeckoFormat {}); - slog::level_filter(level.to_slog(), io) -} - -struct GeckoFormat; - -impl Format for GeckoFormat { - fn format(&self, io: &mut io::Write, record: &Record, _: &OwnedKeyValueList) -> io::Result<()> { - // TODO(ato): Quite sure this is the wrong way to filter records with slog, - // but I do not comprehend how slog works. - let module = record.module(); - if module.starts_with("geckodriver") || module.starts_with("webdriver") { - let ts = format_ts(Local::now()); - let level = record.level().to_gecko(); - let _ = try!(write!(io, "{}\t{}\t{}\t{}\n", ts, module, level, record.msg())); - } - Ok(()) - } -} - -/// Produces a 13-digit Unix Epoch timestamp similar to Gecko. -fn format_ts(ts: DateTime<Local>) -> String { - format!("{}{:03}", ts.timestamp(), ts.timestamp_subsec_millis()) -} - -#[cfg(test)] -mod tests { - use chrono::Local; - use super::format_ts; - - #[test] - fn test_format_ts() { - let ts = Local::now(); - let s = format_ts(ts); - assert_eq!(s.len(), 13); - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 518b50e..0000000 --- a/src/main.rs +++ /dev/null @@ -1,177 +0,0 @@ -extern crate chrono; -#[macro_use] -extern crate clap; -#[macro_use] -extern crate lazy_static; -extern crate hyper; -extern crate mozprofile; -extern crate mozrunner; -extern crate mozversion; -extern crate regex; -extern crate rustc_serialize; -#[macro_use] -extern crate slog; -extern crate slog_atomic; -extern crate slog_stdlog; -extern crate slog_stream; -extern crate zip; -extern crate webdriver; - -#[macro_use] -extern crate log; - -use std::borrow::ToOwned; -use std::io::Write; -use std::net::{SocketAddr, IpAddr}; -use std::path::PathBuf; -use std::str::FromStr; - -use clap::{App, Arg}; - -macro_rules! try_opt { - ($expr:expr, $err_type:expr, $err_msg:expr) => ({ - match $expr { - Some(x) => x, - None => return Err(WebDriverError::new($err_type, $err_msg)) - } - }) -} - -mod logging; -mod prefs; -mod marionette; -mod capabilities; - -use logging::LogLevel; -use marionette::{MarionetteHandler, MarionetteSettings, extension_routes}; - -type ProgramResult = std::result::Result<(), (ExitCode, String)>; - -enum ExitCode { - Ok = 0, - Usage = 64, - Unavailable = 69, -} - -fn app<'a, 'b>() -> App<'a, 'b> { - App::new(format!("geckodriver {}", crate_version!())) - .about("WebDriver implementation for Firefox.") - .arg(Arg::with_name("webdriver_host") - .long("host") - .value_name("HOST") - .help("Host ip to use for WebDriver server (default: 127.0.0.1)") - .takes_value(true)) - .arg(Arg::with_name("webdriver_port") - .short("p") - .long("port") - .value_name("PORT") - .help("Port to use for WebDriver server (default: 4444)") - .takes_value(true) - .alias("webdriver-port")) - .arg(Arg::with_name("binary") - .short("b") - .long("binary") - .value_name("BINARY") - .help("Path to the Firefox binary") - .takes_value(true)) - .arg(Arg::with_name("marionette_port") - .long("marionette-port") - .value_name("PORT") - .help("Port to use to connect to Gecko (default: random free port)") - .takes_value(true)) - .arg(Arg::with_name("connect_existing") - .long("connect-existing") - .requires("marionette_port") - .help("Connect to an existing Firefox instance")) - .arg(Arg::with_name("verbosity") - .short("v") - .multiple(true) - .conflicts_with("log_level") - .help("Log level verbosity (-v for debug and -vv for trace level)")) - .arg(Arg::with_name("log_level") - .long("log") - .takes_value(true) - .value_name("LEVEL") - .possible_values(&["fatal", "error", "warn", "info", "config", "debug", "trace"]) - .help("Set Gecko log level")) - .arg(Arg::with_name("version") - .short("V") - .long("version") - .help("Prints version and copying information")) -} - -fn run() -> ProgramResult { - let matches = app().get_matches(); - - if matches.is_present("version") { - println!("geckodriver {}\n\n{}", crate_version!(), -"The source code of this program is available at -https://github.com/mozilla/geckodriver. - -This program is subject to the terms of the Mozilla Public License 2.0. -You can obtain a copy of the license at https://mozilla.org/MPL/2.0/."); - return Ok(()) - } - - let host = matches.value_of("webdriver_host").unwrap_or("127.0.0.1"); - let port = match u16::from_str(matches.value_of("webdriver_port") - .or(matches.value_of("webdriver_port_alias")) - .unwrap_or("4444")) { - Ok(x) => x, - Err(_) => return Err((ExitCode::Usage, "invalid WebDriver port".to_owned())), - }; - let addr = match IpAddr::from_str(host) { - Ok(addr) => SocketAddr::new(addr, port), - Err(_) => return Err((ExitCode::Usage, "invalid host address".to_owned())), - }; - - let binary = matches.value_of("binary").map(|x| PathBuf::from(x)); - - let marionette_port = match matches.value_of("marionette_port") { - Some(x) => match u16::from_str(x) { - Ok(x) => Some(x), - Err(_) => return Err((ExitCode::Usage, "invalid Marionette port".to_owned())), - }, - None => None - }; - - // overrides defaults in Gecko - // which are info for optimised builds - // and debug for debug builds - let log_level = if matches.is_present("log_level") { - LogLevel::from_str(matches.value_of("log_level").unwrap()).ok() - } else { - match matches.occurrences_of("verbosity") { - 0 => Some(LogLevel::Info), - 1 => Some(LogLevel::Debug), - _ => Some(LogLevel::Trace), - } - }; - logging::init(&log_level); - - let settings = MarionetteSettings { - port: marionette_port, - binary: binary, - connect_existing: matches.is_present("connect_existing"), - log_level: log_level, - }; - - let handler = MarionetteHandler::new(settings); - let listening = try!(webdriver::server::start(addr, handler, &extension_routes()[..]) - .map_err(|err| (ExitCode::Unavailable, err.to_string()))); - info!("Listening on {}", listening.socket); - Ok(()) -} - -fn main() { - let exit_code = match run() { - Ok(_) => ExitCode::Ok, - Err((exit_code, reason)) => { - error!("{}", reason); - exit_code - }, - }; - - std::io::stdout().flush().unwrap(); - std::process::exit(exit_code as i32); -} diff --git a/src/marionette.rs b/src/marionette.rs deleted file mode 100644 index 1039795..0000000 --- a/src/marionette.rs +++ /dev/null @@ -1,1579 +0,0 @@ -use hyper::method::Method; -use logging; -use logging::LogLevel; -use mozprofile::preferences::Pref; -use mozprofile::profile::Profile; -use mozrunner::runner::{Runner, FirefoxRunner}; -use regex::Captures; -use rustc_serialize::json; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; -use std::error::Error; -use std::io::Error as IoError; -use std::io::ErrorKind; -use std::io::prelude::*; -use std::path::PathBuf; -use std::io::Result as IoResult; -use std::net::{TcpListener, TcpStream}; -use std::sync::Mutex; -use std::thread::sleep; -use std::time::Duration; -use webdriver::capabilities::CapabilitiesMatching; -use webdriver::command::{WebDriverCommand, WebDriverMessage, Parameters, - WebDriverExtensionCommand}; -use webdriver::command::WebDriverCommand::{ - NewSession, DeleteSession, Status, Get, GetCurrentUrl, - GoBack, GoForward, Refresh, GetTitle, GetPageSource, GetWindowHandle, - GetWindowHandles, CloseWindow, SetWindowRect, - GetWindowRect, MaximizeWindow, SwitchToWindow, SwitchToFrame, - SwitchToParentFrame, FindElement, FindElements, - FindElementElement, FindElementElements, GetActiveElement, - IsDisplayed, IsSelected, GetElementAttribute, GetElementProperty, GetCSSValue, - GetElementText, GetElementTagName, GetElementRect, IsEnabled, - ElementClick, ElementTap, ElementClear, ElementSendKeys, - ExecuteScript, ExecuteAsyncScript, GetCookies, GetNamedCookie, AddCookie, - DeleteCookies, DeleteCookie, GetTimeouts, SetTimeouts, DismissAlert, - AcceptAlert, GetAlertText, SendAlertText, TakeScreenshot, TakeElementScreenshot, - Extension, PerformActions, ReleaseActions}; -use webdriver::command::{ - NewSessionParameters, GetParameters, WindowRectParameters, SwitchToWindowParameters, - SwitchToFrameParameters, LocatorParameters, JavascriptCommandParameters, - GetNamedCookieParameters, AddCookieParameters, TimeoutsParameters, - ActionsParameters, TakeScreenshotParameters}; -use webdriver::response::{CloseWindowResponse, Cookie, CookieResponse, ElementRectResponse, - NewSessionResponse, TimeoutsResponse, ValueResponse, WebDriverResponse, - WindowRectResponse}; -use webdriver::common::{ - Date, Nullable, WebElement, FrameId, ELEMENT_KEY}; -use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; -use webdriver::server::{WebDriverHandler, Session}; -use webdriver::httpapi::{WebDriverExtensionRoute}; - -use capabilities::{FirefoxCapabilities, FirefoxOptions}; -use prefs; - -const DEFAULT_HOST: &'static str = "localhost"; - -pub fn extension_routes() -> Vec<(Method, &'static str, GeckoExtensionRoute)> { - return vec![(Method::Get, "/session/{sessionId}/moz/context", GeckoExtensionRoute::GetContext), - (Method::Post, "/session/{sessionId}/moz/context", GeckoExtensionRoute::SetContext), - (Method::Post, - "/session/{sessionId}/moz/xbl/{elementId}/anonymous_children", - GeckoExtensionRoute::XblAnonymousChildren), - (Method::Post, - "/session/{sessionId}/moz/xbl/{elementId}/anonymous_by_attribute", - GeckoExtensionRoute::XblAnonymousByAttribute), - (Method::Post, "/session/{sessionId}/moz/addon/install", - GeckoExtensionRoute::InstallAddon), - (Method::Post, "/session/{sessionId}/moz/addon/uninstall", - GeckoExtensionRoute::UninstallAddon)]; -} - -#[derive(Clone, PartialEq)] -pub enum GeckoExtensionRoute { - GetContext, - SetContext, - XblAnonymousChildren, - XblAnonymousByAttribute, - InstallAddon, - UninstallAddon, -} - -impl WebDriverExtensionRoute for GeckoExtensionRoute { - type Command = GeckoExtensionCommand; - - fn command(&self, - captures: &Captures, - body_data: &Json) - -> WebDriverResult<WebDriverCommand<GeckoExtensionCommand>> { - let command = match self { - &GeckoExtensionRoute::GetContext => GeckoExtensionCommand::GetContext, - &GeckoExtensionRoute::SetContext => { - let parameters: GeckoContextParameters = try!(Parameters::from_json(&body_data)); - GeckoExtensionCommand::SetContext(parameters) - } - &GeckoExtensionRoute::XblAnonymousChildren => { - let element_id = try!(captures.name("elementId") - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "Missing elementId parameter"))); - GeckoExtensionCommand::XblAnonymousChildren(element_id.as_str().into()) - } - &GeckoExtensionRoute::XblAnonymousByAttribute => { - let element_id = try!(captures.name("elementId") - .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "Missing elementId parameter"))); - let parameters: AttributeParameters = try!(Parameters::from_json(&body_data)); - GeckoExtensionCommand::XblAnonymousByAttribute(element_id.as_str().into(), - parameters) - } - &GeckoExtensionRoute::InstallAddon => { - let parameters: AddonInstallParameters = try!(Parameters::from_json(&body_data)); - GeckoExtensionCommand::InstallAddon(parameters) - } - &GeckoExtensionRoute::UninstallAddon => { - let parameters: AddonUninstallParameters = try!(Parameters::from_json(&body_data)); - GeckoExtensionCommand::UninstallAddon(parameters) - } - }; - Ok(WebDriverCommand::Extension(command)) - } -} - -#[derive(Clone, PartialEq)] -pub enum GeckoExtensionCommand { - GetContext, - SetContext(GeckoContextParameters), - XblAnonymousChildren(WebElement), - XblAnonymousByAttribute(WebElement, AttributeParameters), - InstallAddon(AddonInstallParameters), - UninstallAddon(AddonUninstallParameters) -} - -impl WebDriverExtensionCommand for GeckoExtensionCommand { - fn parameters_json(&self) -> Option<Json> { - match self { - &GeckoExtensionCommand::GetContext => None, - &GeckoExtensionCommand::SetContext(ref x) => Some(x.to_json()), - &GeckoExtensionCommand::XblAnonymousChildren(_) => None, - &GeckoExtensionCommand::XblAnonymousByAttribute(_, ref x) => Some(x.to_json()), - &GeckoExtensionCommand::InstallAddon(ref x) => Some(x.to_json()), - &GeckoExtensionCommand::UninstallAddon(ref x) => Some(x.to_json()), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -enum GeckoContext { - Content, - Chrome, -} - -impl ToJson for GeckoContext { - fn to_json(&self) -> Json { - match self { - &GeckoContext::Content => Json::String("content".to_owned()), - &GeckoContext::Chrome => Json::String("chrome".to_owned()), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct GeckoContextParameters { - context: GeckoContext -} - -impl Parameters for GeckoContextParameters { - fn from_json(body: &Json) -> WebDriverResult<GeckoContextParameters> { - let data = try!(body.as_object().ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Message body was not an object"))); - let context_value = try!(data.get("context").ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Missing context key"))); - let value = try!(context_value.as_string().ok_or( - WebDriverError::new( - ErrorStatus::InvalidArgument, - "context was not a string"))); - let context = try!(match value { - "chrome" => Ok(GeckoContext::Chrome), - "content" => Ok(GeckoContext::Content), - _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument, - format!("{} is not a valid context", - value))) - }); - Ok(GeckoContextParameters { - context: context - }) - } -} - -impl ToMarionette for GeckoContextParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("value".to_owned(), self.context.to_json()); - Ok(data) - } -} - -impl ToJson for GeckoContextParameters { - fn to_json(&self) -> Json { - let mut data = BTreeMap::new(); - data.insert("context".to_owned(), self.context.to_json()); - Json::Object(data) - } -} - - -#[derive(Clone, Debug, PartialEq)] -pub struct AttributeParameters { - name: String, - value: String -} - -impl Parameters for AttributeParameters { - fn from_json(body: &Json) -> WebDriverResult<AttributeParameters> { - let data = try!(body.as_object().ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Message body was not an object"))); - let name = try!(try!(data.get("name").ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Missing 'name' parameter"))).as_string(). - ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "'name' parameter is not a string"))); - let value = try!(try!(data.get("value").ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Missing 'value' parameter"))).as_string(). - ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, - "'value' parameter is not a string"))); - Ok(AttributeParameters { - name: name.to_owned(), - value: value.to_owned(), - }) - } -} - -impl ToJson for AttributeParameters { - fn to_json(&self) -> Json { - let mut data = BTreeMap::new(); - data.insert("name".to_owned(), self.name.to_json()); - data.insert("value".to_owned(), self.value.to_json()); - Json::Object(data) - } -} - -impl ToMarionette for AttributeParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("using".to_owned(), "anon attribute".to_json()); - let mut value = BTreeMap::new(); - value.insert(self.name.to_owned(), self.value.to_json()); - data.insert("value".to_owned(), Json::Object(value)); - Ok(data) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct AddonInstallParameters { - pub path: String, - pub temporary: bool -} - -impl Parameters for AddonInstallParameters { - fn from_json(body: &Json) -> WebDriverResult<AddonInstallParameters> { - let data = try!(body.as_object().ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Message body was not an object"))); - - let path = try_opt!( - try_opt!(data.get("path"), - ErrorStatus::InvalidArgument, - "Missing 'path' parameter").as_string(), - ErrorStatus::InvalidArgument, - "'path' is not a string").to_string(); - - let temporary = match data.get("temporary") { - Some(x) => try_opt!(x.as_boolean(), - ErrorStatus::InvalidArgument, - "Failed to convert 'temporary' to boolean"), - None => false - }; - - return Ok(AddonInstallParameters { - path: path, - temporary: temporary, - }) - } -} - -impl ToJson for AddonInstallParameters { - fn to_json(&self) -> Json { - let mut data = BTreeMap::new(); - data.insert("path".to_string(), self.path.to_json()); - data.insert("temporary".to_string(), self.temporary.to_json()); - Json::Object(data) - } -} - -impl ToMarionette for AddonInstallParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("path".to_string(), self.path.to_json()); - data.insert("temporary".to_string(), self.temporary.to_json()); - Ok(data) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct AddonUninstallParameters { - pub id: String -} - -impl Parameters for AddonUninstallParameters { - fn from_json(body: &Json) -> WebDriverResult<AddonUninstallParameters> { - let data = try!(body.as_object().ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Message body was not an object"))); - - let id = try_opt!( - try_opt!(data.get("id"), - ErrorStatus::InvalidArgument, - "Missing 'id' parameter").as_string(), - ErrorStatus::InvalidArgument, - "'id' is not a string").to_string(); - - return Ok(AddonUninstallParameters {id: id}) - } -} - -impl ToJson for AddonUninstallParameters { - fn to_json(&self) -> Json { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), self.id.to_json()); - Json::Object(data) - } -} - -impl ToMarionette for AddonUninstallParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), self.id.to_json()); - Ok(data) - } -} - -#[derive(Default)] -pub struct LogOptions { - pub level: Option<LogLevel>, -} - -#[derive(Default)] -pub struct MarionetteSettings { - pub port: Option<u16>, - pub binary: Option<PathBuf>, - pub connect_existing: bool, - - /// Optionally increase Marionette's verbosity by providing a log - /// level. The Gecko default is LogLevel::Info for optimised - /// builds and LogLevel::Debug for debug builds. - pub log_level: Option<LogLevel>, -} - -pub struct MarionetteHandler { - connection: Mutex<Option<MarionetteConnection>>, - settings: MarionetteSettings, - browser: Option<FirefoxRunner>, - current_log_level: Option<LogLevel>, -} - -impl MarionetteHandler { - pub fn new(settings: MarionetteSettings) -> MarionetteHandler { - MarionetteHandler { - connection: Mutex::new(None), - settings: settings, - browser: None, - current_log_level: None, - } - } - - fn create_connection(&mut self, - session_id: &Option<String>, - new_session_parameters: &NewSessionParameters) - -> WebDriverResult<BTreeMap<String, Json>> { - let (options, capabilities) = { - let mut fx_capabilities = FirefoxCapabilities::new(self.settings.binary.as_ref()); - let mut capabilities = try!( - try!(new_session_parameters - .match_browser(&mut fx_capabilities)) - .ok_or(WebDriverError::new( - ErrorStatus::SessionNotCreated, - "Unable to find a matching set of capabilities"))); - - let options = try!(FirefoxOptions::from_capabilities(fx_capabilities.chosen_binary, - &mut capabilities)); - (options, capabilities) - }; - - self.current_log_level = options.log.level.clone().or(self.settings.log_level.clone()); - logging::init(&self.current_log_level); - - let port = self.settings.port.unwrap_or(try!(get_free_port())); - if !self.settings.connect_existing { - try!(self.start_browser(port, options)); - } - - let mut connection = MarionetteConnection::new(port, session_id.clone()); - try!(connection.connect()); - self.connection = Mutex::new(Some(connection)); - - Ok(capabilities) - } - - fn start_browser(&mut self, port: u16, mut options: FirefoxOptions) -> WebDriverResult<()> { - let binary = try!(options.binary - .ok_or(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 custom_profile = options.profile.is_some(); - - let mut runner = try!(FirefoxRunner::new(&binary, options.profile.take()) - .map_err(|e| WebDriverError::new(ErrorStatus::SessionNotCreated, - e.description().to_owned()))); - - // double-dashed flags are not accepted on Windows systems - runner.args().push("-marionette".to_owned()); - - if let Some(args) = options.args.take() { - runner.args().extend(args); - }; - - try!(self.set_prefs(port, &mut runner.profile, custom_profile, options.prefs) - .map_err(|e| { - WebDriverError::new(ErrorStatus::SessionNotCreated, - format!("Failed to set preferences: {}", e)) - })); - - info!("Starting browser {} with args {:?}", binary.display(), runner.args()); - try!(runner.start() - .map_err(|e| { - WebDriverError::new(ErrorStatus::SessionNotCreated, - format!("Failed to start browser {}: {}", - binary.display(), e)) - })); - self.browser = Some(runner); - - Ok(()) - } - - pub fn set_prefs(&self, port: u16, profile: &mut Profile, custom_profile: bool, - extra_prefs: Vec<(String, Pref)>) - -> WebDriverResult<()> { - let prefs = try!(profile.user_prefs() - .map_err(|_| WebDriverError::new(ErrorStatus::UnknownError, - "Unable to read profile preferences file"))); - - for &(ref name, ref value) in prefs::DEFAULT.iter() { - if !custom_profile || !prefs.contains_key(name) { - prefs.insert((*name).clone(), (*value).clone()); - } - } - - prefs.insert_slice(&extra_prefs[..]); - - // fallbacks can be removed when Firefox 54 becomes stable - if let Some(ref level) = self.current_log_level { - prefs.insert("marionette.log.level", Pref::new(level.to_string())); - prefs.insert("marionette.logging", Pref::new(level.to_string())); // fallback - }; - prefs.insert("marionette.port", Pref::new(port as i64)); - prefs.insert("marionette.defaultPrefs.port", Pref::new(port as i64)); // fallback - - prefs.write().map_err(|_| WebDriverError::new(ErrorStatus::UnknownError, - "Unable to write Firefox profile")) - } -} - -impl WebDriverHandler<GeckoExtensionRoute> for MarionetteHandler { - fn handle_command(&mut self, _: &Option<Session>, - msg: WebDriverMessage<GeckoExtensionRoute>) -> WebDriverResult<WebDriverResponse> { - let mut resolved_capabilities = None; - { - let mut capabilities_options = None; - // First handle the status message which doesn't actually require a marionette - // connection or message - if msg.command == Status { - let (ready, message) = self.connection.lock() - .map(|ref connection| connection - .as_ref() - .map(|_| (false, "Session already started")) - .unwrap_or((true, ""))) - .unwrap_or((false, "geckodriver internal error")); - let mut value = BTreeMap::new(); - value.insert("ready".to_string(), Json::Boolean(ready)); - value.insert("message".to_string(), Json::String(message.into())); - return Ok(WebDriverResponse::Generic(ValueResponse::new(Json::Object(value)))); - } - match self.connection.lock() { - Ok(ref connection) => { - if connection.is_none() { - match msg.command { - NewSession(ref capabilities) => { - capabilities_options = Some(capabilities); - }, - _ => { - return Err(WebDriverError::new( - ErrorStatus::SessionNotCreated, - "Tried to run command without establishing a connection")); - } - } - } - }, - Err(_) => { - return Err(WebDriverError::new( - ErrorStatus::UnknownError, - "Failed to aquire Marionette connection")) - } - } - if let Some(capabilities) = capabilities_options { - resolved_capabilities = Some(try!( - self.create_connection(&msg.session_id, &capabilities))); - } - } - - match self.connection.lock() { - Ok(ref mut connection) => { - match connection.as_mut() { - Some(conn) => conn.send_command(resolved_capabilities, &msg), - None => panic!("Connection missing") - } - }, - Err(_) => { - Err(WebDriverError::new( - ErrorStatus::UnknownError, - "Failed to aquire Marionette connection")) - } - } - } - - fn delete_session(&mut self, _: &Option<Session>) { - if let Ok(connection) = self.connection.lock() { - if let Some(ref conn) = *connection { - conn.close(); - } - } - if let Some(ref mut runner) = self.browser { - debug!("Stopping browser process"); - if runner.stop().is_err() { - error!("Failed to kill browser process"); - }; - } - self.connection = Mutex::new(None); - self.browser = None; - } -} - -pub struct MarionetteSession { - pub session_id: String, - protocol: Option<String>, - application_type: Option<String>, - command_id: u64 -} - -impl MarionetteSession { - pub fn new(session_id: Option<String>) -> MarionetteSession { - let initital_id = session_id.unwrap_or("".to_string()); - MarionetteSession { - session_id: initital_id, - protocol: None, - application_type: None, - command_id: 0 - } - } - - pub fn update(&mut self, msg: &WebDriverMessage<GeckoExtensionRoute>, - resp: &MarionetteResponse) -> WebDriverResult<()> { - match msg.command { - NewSession(_) => { - let session_id = try_opt!( - try_opt!(resp.result.find("sessionId"), - ErrorStatus::SessionNotCreated, - "Unable to get session id").as_string(), - ErrorStatus::SessionNotCreated, - "Unable to convert session id to string"); - self.session_id = session_id.to_string().clone(); - }, - _ => {} - } - Ok(()) - } - - fn to_web_element(&self, json_data: &Json) -> WebDriverResult<WebElement> { - let data = try_opt!(json_data.as_object(), - ErrorStatus::UnknownError, - "Failed to convert data to an object"); - let id = try_opt!( - try_opt!( - match data.get("ELEMENT") { - Some(id) => Some(id), - None => { - match data.get(ELEMENT_KEY) { - Some(id) => Some(id), - None => None - } - } - }, - ErrorStatus::UnknownError, - "Failed to extract Web Element from response").as_string(), - ErrorStatus::UnknownError, - "Failed to convert id value to string" - ).to_string(); - Ok(WebElement::new(id)) - } - - pub fn next_command_id(&mut self) -> u64 { - self.command_id = self.command_id + 1; - self.command_id - } - - pub fn response(&mut self, msg: &WebDriverMessage<GeckoExtensionRoute>, - resp: MarionetteResponse) -> WebDriverResult<WebDriverResponse> { - - if resp.id != self.command_id { - return Err(WebDriverError::new(ErrorStatus::UnknownError, - format!("Marionette responses arrived out of sequence, expected {}, got {}", - self.command_id, resp.id))); - } - - if let Some(error) = resp.error { - let status = self.error_from_string(&error.status); - - return Err(WebDriverError::new(status, error.message)); - } - - try!(self.update(msg, &resp)); - - Ok(match msg.command { - // Everything that doesn't have a response value - Get(_) | GoBack | GoForward | Refresh | SetTimeouts(_) | - SetWindowRect(_) | MaximizeWindow | SwitchToWindow(_) | SwitchToFrame(_) | - SwitchToParentFrame | AddCookie(_) | DeleteCookies | DeleteCookie(_) | - DismissAlert | AcceptAlert | SendAlertText(_) | ElementClick(_) | - ElementTap(_) | ElementClear(_) | ElementSendKeys(_, _) | - PerformActions(_) | ReleaseActions => { - WebDriverResponse::Void - }, - // Things that simply return the contents of the marionette "value" property - GetCurrentUrl | GetTitle | GetPageSource | GetWindowHandle | IsDisplayed(_) | - IsSelected(_) | GetElementAttribute(_, _) | GetElementProperty(_, _) | - GetCSSValue(_, _) | GetElementText(_) | - GetElementTagName(_) | IsEnabled(_) | ExecuteScript(_) | ExecuteAsyncScript(_) | - GetAlertText | TakeScreenshot | TakeElementScreenshot(_) => { - let value = try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field"); - //TODO: Convert webelement keys - WebDriverResponse::Generic(ValueResponse::new(value.clone())) - }, - GetTimeouts => { - let script = try_opt!(try_opt!(resp.result - .find("script"), - ErrorStatus::UnknownError, - "Missing field: script") - .as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret script timeout duration as u64"); - // Check for the spec-compliant "pageLoad", but also for "page load", - // which was sent by Firefox 52 and earlier. - let page_load = try_opt!(try_opt!(resp.result.find("pageLoad") - .or(resp.result.find("page load")), - ErrorStatus::UnknownError, - "Missing field: pageLoad") - .as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret page load duration as u64"); - let implicit = try_opt!(try_opt!(resp.result - .find("implicit"), - ErrorStatus::UnknownError, - "Missing field: implicit") - .as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret implicit search duration as u64"); - - WebDriverResponse::Timeouts(TimeoutsResponse { - script: script, - pageLoad: page_load, - implicit: implicit, - }) - }, - Status => panic!("Got status command that should already have been handled"), - GetWindowHandles => { - WebDriverResponse::Generic(ValueResponse::new(resp.result.clone())) - }, - CloseWindow => { - let data = try_opt!(resp.result.as_array(), - ErrorStatus::UnknownError, - "Failed to interpret value as array"); - let handles = try!(data.iter() - .map(|x| { - Ok(try_opt!(x.as_string(), - ErrorStatus::UnknownError, - "Failed to interpret window handle as string") - .to_owned()) - }) - .collect()); - WebDriverResponse::CloseWindow(CloseWindowResponse { window_handles: handles }) - } - GetWindowRect => { - let width = try_opt!( - try_opt!(resp.result.find("width"), - ErrorStatus::UnknownError, - "Failed to find width field").as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret width as integer"); - - let height = try_opt!( - try_opt!(resp.result.find("height"), - ErrorStatus::UnknownError, - "Failed to find height field").as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret width as integer"); - - let x = try_opt!( - try_opt!(resp.result.find("x"), - ErrorStatus::UnknownError, - "Failed to find x field").as_i64(), - ErrorStatus::UnknownError, - "Failed to interpret x as integer"); - - let y = try_opt!( - try_opt!(resp.result.find("y"), - ErrorStatus::UnknownError, - "Failed to find y field").as_i64(), - ErrorStatus::UnknownError, - "Failed to interpret y as integer"); - - WebDriverResponse::WindowRect(WindowRectResponse {x: x, - y: y, - width: width, - height: height}) - }, - GetElementRect(_) => { - let x = try_opt!( - try_opt!(resp.result.find("x"), - ErrorStatus::UnknownError, - "Failed to find x field").as_f64(), - ErrorStatus::UnknownError, - "Failed to interpret x as float"); - - let y = try_opt!( - try_opt!(resp.result.find("y"), - ErrorStatus::UnknownError, - "Failed to find y field").as_f64(), - ErrorStatus::UnknownError, - "Failed to interpret y as float"); - - let width = try_opt!( - try_opt!(resp.result.find("width"), - ErrorStatus::UnknownError, - "Failed to find width field").as_f64(), - ErrorStatus::UnknownError, - "Failed to interpret width as float"); - - let height = try_opt!( - try_opt!(resp.result.find("height"), - ErrorStatus::UnknownError, - "Failed to find height field").as_f64(), - ErrorStatus::UnknownError, - "Failed to interpret width as float"); - - WebDriverResponse::ElementRect(ElementRectResponse::new(x, y, width, height)) - }, - GetCookies => { - let cookies = try!(self.process_cookies(&resp.result)); - WebDriverResponse::Cookie(CookieResponse::new(cookies)) - }, - GetNamedCookie(ref name) => { - let mut cookies = try!(self.process_cookies(&resp.result)); - cookies.retain(|x| x.name == *name); - WebDriverResponse::Cookie(CookieResponse::new(cookies)) - } - FindElement(_) | FindElementElement(_, _) => { - let element = try!(self.to_web_element( - try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field"))); - WebDriverResponse::Generic(ValueResponse::new(element.to_json())) - }, - FindElements(_) | FindElementElements(_, _) => { - let element_vec = try_opt!(resp.result.as_array(), - ErrorStatus::UnknownError, - "Failed to interpret value as array"); - let elements = try!(element_vec.iter().map( - |x| { - self.to_web_element(x) - }).collect::<Result<Vec<_>, _>>()); - WebDriverResponse::Generic(ValueResponse::new( - Json::Array(elements.iter().map(|x| {x.to_json()}).collect()))) - }, - GetActiveElement => { - let element = try!(self.to_web_element( - try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field"))); - WebDriverResponse::Generic(ValueResponse::new(element.to_json())) - }, - NewSession(_) => { - let mut session_id = try_opt!( - try_opt!(resp.result.find("sessionId"), - ErrorStatus::InvalidSessionId, - "Failed to find sessionId field").as_string(), - ErrorStatus::InvalidSessionId, - "sessionId was not a string"); - - if session_id.starts_with("{") && session_id.ends_with("}") { - session_id = &session_id[1..session_id.len()-1]; - } - - let capabilities = try_opt!( - try_opt!(resp.result.find("capabilities"), - ErrorStatus::UnknownError, - "Failed to find capabilities field").as_object(), - ErrorStatus::UnknownError, - "capabiltites field was not an Object"); - - WebDriverResponse::NewSession(NewSessionResponse::new( - session_id.to_string(), Json::Object(capabilities.clone()))) - }, - DeleteSession => { - WebDriverResponse::DeleteSession - }, - Extension(ref extension) => { - match extension { - &GeckoExtensionCommand::GetContext => { - let value = try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field"); - WebDriverResponse::Generic(ValueResponse::new(value.clone())) - }, - &GeckoExtensionCommand::SetContext(_) => WebDriverResponse::Void, - &GeckoExtensionCommand::XblAnonymousChildren(_) => { - let els_vec = try_opt!(resp.result.as_array(), - ErrorStatus::UnknownError, "Failed to interpret body as array"); - let els = try!(els_vec.iter().map(|x| self.to_web_element(x)) - .collect::<Result<Vec<_>, _>>()); - WebDriverResponse::Generic(ValueResponse::new( - Json::Array(els.iter().map(|el| el.to_json()).collect()))) - }, - &GeckoExtensionCommand::XblAnonymousByAttribute(_, _) => { - let el = try!(self.to_web_element(try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, "Failed to find value field"))); - WebDriverResponse::Generic(ValueResponse::new(el.to_json())) - }, - &GeckoExtensionCommand::InstallAddon(_) => { - let value = try_opt!(resp.result.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field"); - WebDriverResponse::Generic(ValueResponse::new(value.clone())) - }, - &GeckoExtensionCommand::UninstallAddon(_) => WebDriverResponse::Void - } - } - }) - } - - fn process_cookies(&self, json_data: &Json) -> WebDriverResult<Vec<Cookie>> { - let value = try_opt!(json_data.as_array(), - ErrorStatus::UnknownError, - "Failed to interpret value as array"); - value.iter().map(|x| { - let name = try_opt!( - try_opt!(x.find("name"), - ErrorStatus::UnknownError, - "Failed to find name field").as_string(), - ErrorStatus::UnknownError, - "Failed to interpret name as string").to_string(); - let value = try_opt!( - try_opt!(x.find("value"), - ErrorStatus::UnknownError, - "Failed to find value field").as_string(), - ErrorStatus::UnknownError, - "Failed to interpret value as string").to_string(); - let path = try!( - Nullable::from_json(x.find("path").unwrap_or(&Json::Null), - |x| { - Ok((try_opt!(x.as_string(), - ErrorStatus::UnknownError, - "Failed to interpret path as String")).to_string()) - })); - let domain = try!( - Nullable::from_json(x.find("domain").unwrap_or(&Json::Null), - |x| { - Ok((try_opt!(x.as_string(), - ErrorStatus::UnknownError, - "Failed to interpret domain as String")).to_string()) - })); - let expiry = try!( - Nullable::from_json(x.find("expiry").unwrap_or(&Json::Null), - |x| { - Ok(Date::new((try_opt!( - x.as_u64(), - ErrorStatus::UnknownError, - "Failed to interpret expiry as u64")))) - })); - let secure = try_opt!( - x.find("secure").map_or(Some(false), |x| x.as_boolean()), - ErrorStatus::UnknownError, - "Failed to interpret secure as boolean"); - let http_only = try_opt!( - x.find("httpOnly").map_or(Some(false), |x| x.as_boolean()), - ErrorStatus::UnknownError, - "Failed to interpret httpOnly as boolean"); - Ok(Cookie::new(name, value, path, domain, expiry, secure, http_only)) - }).collect::<Result<Vec<_>, _>>() - } - - pub fn error_from_string(&self, error_code: &str) -> ErrorStatus { - match error_code { - "element click intercepted" => ErrorStatus::ElementClickIntercepted, - "element not interactable" | "element not visible" => ErrorStatus::ElementNotInteractable, - "element not selectable" => ErrorStatus::ElementNotSelectable, - "insecure certificate" => ErrorStatus::InsecureCertificate, - "invalid argument" => ErrorStatus::InvalidArgument, - "invalid cookie domain" => ErrorStatus::InvalidCookieDomain, - "invalid coordinates" | "invalid element coordinates" => ErrorStatus::InvalidCoordinates, - "invalid element state" => ErrorStatus::InvalidElementState, - "invalid selector" => ErrorStatus::InvalidSelector, - "invalid session id" => ErrorStatus::InvalidSessionId, - "javascript error" => ErrorStatus::JavascriptError, - "move target out of bounds" => ErrorStatus::MoveTargetOutOfBounds, - "no such alert" => ErrorStatus::NoSuchAlert, - "no such element" => ErrorStatus::NoSuchElement, - "no such frame" => ErrorStatus::NoSuchFrame, - "no such window" => ErrorStatus::NoSuchWindow, - "script timeout" => ErrorStatus::ScriptTimeout, - "session not created" => ErrorStatus::SessionNotCreated, - "stale element reference" => ErrorStatus::StaleElementReference, - "timeout" => ErrorStatus::Timeout, - "unable to capture screen" => ErrorStatus::UnableToCaptureScreen, - "unable to set cookie" => ErrorStatus::UnableToSetCookie, - "unexpected alert open" => ErrorStatus::UnexpectedAlertOpen, - "unknown command" => ErrorStatus::UnknownCommand, - "unknown error" => ErrorStatus::UnknownError, - "unsupported operation" => ErrorStatus::UnsupportedOperation, - _ => ErrorStatus::UnknownError, - } - } -} - -pub struct MarionetteCommand { - pub id: u64, - pub name: String, - pub params: BTreeMap<String, Json> -} - -impl MarionetteCommand { - fn new(id: u64, name: String, params: BTreeMap<String, Json>) -> MarionetteCommand { - MarionetteCommand { - id: id, - name: name, - params: params, - } - } - - fn from_webdriver_message(id: u64, - capabilities: Option<BTreeMap<String, Json>>, - msg: &WebDriverMessage<GeckoExtensionRoute>) - -> WebDriverResult<MarionetteCommand> { - let (opt_name, opt_parameters) = match msg.command { - NewSession(_) => { - let caps = capabilities.expect("Tried to create new session without processing capabilities"); - - let mut data = BTreeMap::new(); - for (k, v) in caps.iter() { - data.insert(k.to_string(), v.to_json()); - } - - // duplicate in capabilities.desiredCapabilities for legacy compat - let mut legacy_caps = BTreeMap::new(); - legacy_caps.insert("desiredCapabilities".to_string(), caps.to_json()); - data.insert("capabilities".to_string(), legacy_caps.to_json()); - - (Some("newSession"), Some(Ok(data))) - }, - DeleteSession => { - let mut body = BTreeMap::new(); - body.insert("flags".to_owned(), vec!["eForceQuit".to_json()].to_json()); - (Some("quitApplication"), Some(Ok(body))) - }, - Status => panic!("Got status command that should already have been handled"), - Get(ref x) => (Some("get"), Some(x.to_marionette())), - GetCurrentUrl => (Some("getCurrentUrl"), None), - GoBack => (Some("goBack"), None), - GoForward => (Some("goForward"), None), - Refresh => (Some("refresh"), None), - GetTitle => (Some("getTitle"), None), - GetPageSource => (Some("getPageSource"), None), - GetWindowHandle => (Some("getWindowHandle"), None), - GetWindowHandles => (Some("getWindowHandles"), None), - CloseWindow => (Some("close"), None), - GetTimeouts => (Some("getTimeouts"), None), - SetTimeouts(ref x) => (Some("timeouts"), Some(x.to_marionette())), - SetWindowRect(ref x) => (Some("setWindowRect"), Some(x.to_marionette())), - GetWindowRect => (Some("getWindowRect"), None), - MaximizeWindow => (Some("maximizeWindow"), None), - SwitchToWindow(ref x) => (Some("switchToWindow"), Some(x.to_marionette())), - SwitchToFrame(ref x) => (Some("switchToFrame"), Some(x.to_marionette())), - SwitchToParentFrame => (Some("switchToParentFrame"), None), - FindElement(ref x) => (Some("findElement"), Some(x.to_marionette())), - FindElements(ref x) => (Some("findElements"), Some(x.to_marionette())), - FindElementElement(ref e, ref x) => { - let mut data = try!(x.to_marionette()); - data.insert("element".to_string(), e.id.to_json()); - (Some("findElement"), Some(Ok(data))) - }, - FindElementElements(ref e, ref x) => { - let mut data = try!(x.to_marionette()); - data.insert("element".to_string(), e.id.to_json()); - (Some("findElements"), Some(Ok(data))) - }, - GetActiveElement => (Some("getActiveElement"), None), - IsDisplayed(ref x) => (Some("isElementDisplayed"), Some(x.to_marionette())), - IsSelected(ref x) => (Some("isElementSelected"), Some(x.to_marionette())), - GetElementAttribute(ref e, ref x) => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), e.id.to_json()); - data.insert("name".to_string(), x.to_json()); - (Some("getElementAttribute"), Some(Ok(data))) - }, - GetElementProperty(ref e, ref x) => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), e.id.to_json()); - data.insert("name".to_string(), x.to_json()); - (Some("getElementProperty"), Some(Ok(data))) - }, - GetCSSValue(ref e, ref x) => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), e.id.to_json()); - data.insert("propertyName".to_string(), x.to_json()); - (Some("getElementValueOfCssProperty"), Some(Ok(data))) - }, - GetElementText(ref x) => (Some("getElementText"), Some(x.to_marionette())), - GetElementTagName(ref x) => (Some("getElementTagName"), Some(x.to_marionette())), - GetElementRect(ref x) => (Some("getElementRect"), Some(x.to_marionette())), - IsEnabled(ref x) => (Some("isElementEnabled"), Some(x.to_marionette())), - PerformActions(ref x) => (Some("performActions"), Some(x.to_marionette())), - ReleaseActions => (Some("releaseActions"), None), - ElementClick(ref x) => (Some("clickElement"), Some(x.to_marionette())), - ElementTap(ref x) => (Some("singleTap"), Some(x.to_marionette())), - ElementClear(ref x) => (Some("clearElement"), Some(x.to_marionette())), - ElementSendKeys(ref e, ref x) => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), e.id.to_json()); - data.insert("text".to_string(), x.text.to_json()); - data.insert("value".to_string(), - x.text - .chars() - .map(|x| x.to_string()) - .collect::<Vec<String>>() - .to_json()); - (Some("sendKeysToElement"), Some(Ok(data))) - }, - ExecuteScript(ref x) => (Some("executeScript"), Some(x.to_marionette())), - ExecuteAsyncScript(ref x) => (Some("executeAsyncScript"), Some(x.to_marionette())), - GetCookies | GetNamedCookie(_) => (Some("getCookies"), None), - DeleteCookies => (Some("deleteAllCookies"), None), - DeleteCookie(ref x) => { - let mut data = BTreeMap::new(); - data.insert("name".to_string(), x.to_json()); - (Some("deleteCookie"), Some(Ok(data))) - }, - AddCookie(ref x) => (Some("addCookie"), Some(x.to_marionette())), - DismissAlert => (Some("dismissDialog"), None), - AcceptAlert => (Some("acceptDialog"), None), - GetAlertText => (Some("getTextFromDialog"), None), - SendAlertText(ref x) => { - let mut data = BTreeMap::new(); - data.insert("text".to_string(), x.text.to_json()); - data.insert("value".to_string(), - x.text - .chars() - .map(|x| x.to_string()) - .collect::<Vec<String>>() - .to_json()); - (Some("sendKeysToDialog"), Some(Ok(data))) - }, - TakeScreenshot => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), Json::Null); - data.insert("highlights".to_string(), Json::Array(vec![])); - data.insert("full".to_string(), Json::Boolean(false)); - (Some("takeScreenshot"), Some(Ok(data))) - }, - TakeElementScreenshot(ref e) => { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), e.id.to_json()); - data.insert("highlights".to_string(), Json::Array(vec![])); - data.insert("full".to_string(), Json::Boolean(false)); - (Some("takeScreenshot"), Some(Ok(data))) - }, - Extension(ref extension) => { - match extension { - &GeckoExtensionCommand::GetContext => (Some("getContext"), None), - &GeckoExtensionCommand::SetContext(ref x) => { - (Some("setContext"), Some(x.to_marionette())) - }, - &GeckoExtensionCommand::XblAnonymousChildren(ref e) => { - let mut data = BTreeMap::new(); - data.insert("using".to_owned(), "anon".to_json()); - data.insert("value".to_owned(), Json::Null); - data.insert("element".to_string(), e.id.to_json()); - (Some("findElements"), Some(Ok(data))) - }, - &GeckoExtensionCommand::XblAnonymousByAttribute(ref e, ref x) => { - let mut data = try!(x.to_marionette()); - data.insert("element".to_string(), e.id.to_json()); - (Some("findElement"), Some(Ok(data))) - }, - &GeckoExtensionCommand::InstallAddon(ref x) => { - (Some("addon:install"), Some(x.to_marionette())) - }, - &GeckoExtensionCommand::UninstallAddon(ref x) => { - (Some("addon:uninstall"), Some(x.to_marionette())) - } - } - } - }; - - let name = try_opt!(opt_name, - ErrorStatus::UnsupportedOperation, - "Operation not supported"); - let parameters = try!(opt_parameters.unwrap_or(Ok(BTreeMap::new()))); - - Ok(MarionetteCommand::new(id, name.into(), parameters)) - } -} - -impl ToJson for MarionetteCommand { - fn to_json(&self) -> Json { - Json::Array(vec![Json::U64(0), self.id.to_json(), self.name.to_json(), - self.params.to_json()]) - } -} - -pub struct MarionetteResponse { - pub id: u64, - pub error: Option<MarionetteError>, - pub result: Json, -} - -impl MarionetteResponse { - fn from_json(data: &Json) -> WebDriverResult<MarionetteResponse> { - let data_array = try_opt!(data.as_array(), - ErrorStatus::UnknownError, - "Expected a json array"); - - if data_array.len() != 4 { - return Err(WebDriverError::new( - ErrorStatus::UnknownError, - "Expected an array of length 4")); - } - - if data_array[0].as_u64() != Some(1) { - return Err(WebDriverError::new(ErrorStatus::UnknownError, - "Expected 1 in first element of response")); - }; - let id = try_opt!(data[1].as_u64(), - ErrorStatus::UnknownError, - "Expected an integer id"); - let error = if data[2].is_object() { - Some(try!(MarionetteError::from_json(&data[2]))) - } else if data[2].is_null() { - None - } else { - return Err(WebDriverError::new(ErrorStatus::UnknownError, - "Expected object or null error")); - }; - - let result = if data[3].is_null() || data[3].is_object() || data[3].is_array() { - data[3].clone() - } else { - return Err(WebDriverError::new(ErrorStatus::UnknownError, - "Expected object params")); - }; - - Ok(MarionetteResponse {id: id, - error: error, - result: result}) - } -} - -impl ToJson for MarionetteResponse { - fn to_json(&self) -> Json { - Json::Array(vec![Json::U64(1), self.id.to_json(), self.error.to_json(), - self.result.clone()]) - } -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct MarionetteError { - pub status: String, - pub message: String, - pub stacktrace: Option<String> -} - -impl MarionetteError { - fn new(status: String, message: String, stacktrace: Option<String>) -> MarionetteError { - MarionetteError { - status: status, - message: message, - stacktrace: stacktrace - } - } - - fn from_json(data: &Json) -> WebDriverResult<MarionetteError> { - if !data.is_object() { - return Err(WebDriverError::new(ErrorStatus::UnknownError, - "Expected an error object")); - } - let status = try_opt!( - try_opt!(data.find("error"), - ErrorStatus::UnknownError, - "Error value has no status").as_string(), - ErrorStatus::UnknownError, - "Error status was not a string").into(); - - let message = try_opt!( - try_opt!(data.find("message"), - ErrorStatus::UnknownError, - "Error value has no message").as_string(), - ErrorStatus::UnknownError, - "Error message was not a string").into(); - - let stacktrace = match data.find("stacktrace") { - None | Some(&Json::Null) => None, - Some(x) => Some(try_opt!(x.as_string(), - ErrorStatus::UnknownError, - "Error message was not a string").into()), - }; - Ok(MarionetteError::new(status, message, stacktrace)) - } -} - -impl ToJson for MarionetteError { - fn to_json(&self) -> Json { - let mut data = BTreeMap::new(); - data.insert("status".into(), self.status.to_json()); - data.insert("message".into(), self.message.to_json()); - data.insert("stacktrace".into(), self.stacktrace.to_json()); - Json::Object(data) - } -} - -fn get_free_port() -> IoResult<u16> { - TcpListener::bind(&("localhost", 0)) - .and_then(|stream| stream.local_addr()) - .map(|x| x.port()) -} - -pub struct MarionetteConnection { - port: u16, - stream: Option<TcpStream>, - pub session: MarionetteSession -} - -impl MarionetteConnection { - pub fn new(port: u16, session_id: Option<String>) -> MarionetteConnection { - MarionetteConnection { - port: port, - stream: None, - session: MarionetteSession::new(session_id) - } - } - - pub fn connect(&mut self) -> WebDriverResult<()> { - let timeout = 60 * 1000; // ms - let poll_interval = 100; // ms - let poll_attempts = timeout / poll_interval; - let mut poll_attempt = 0; - - loop { - match TcpStream::connect(&(DEFAULT_HOST, self.port)) { - Ok(stream) => { - self.stream = Some(stream); - break - }, - Err(e) => { - trace!(" connection attempt {}/{}", poll_attempt, poll_attempts); - if poll_attempt <= poll_attempts { - poll_attempt += 1; - sleep(Duration::from_millis(poll_interval)); - } else { - return Err(WebDriverError::new( - ErrorStatus::UnknownError, e.description().to_owned())); - } - } - } - }; - - debug!("Connected to Marionette on {}:{}", DEFAULT_HOST, self.port); - - try!(self.handshake()); - Ok(()) - } - - fn handshake(&mut self) -> WebDriverResult<()> { - let resp = try!(self.read_resp()); - let handshake_data = try!(Json::from_str(&*resp)); - - let data = try_opt!(handshake_data.as_object(), - ErrorStatus::UnknownError, - "Expected a json object in handshake"); - - self.session.protocol = Some(try_opt!(data.get("marionetteProtocol"), - ErrorStatus::UnknownError, - "Missing 'marionetteProtocol' field in handshake").to_string()); - - self.session.application_type = Some(try_opt!(data.get("applicationType"), - ErrorStatus::UnknownError, - "Missing 'applicationType' field in handshake").to_string()); - - if self.session.protocol != Some("3".into()) { - return Err(WebDriverError::new( - ErrorStatus::UnknownError, - format!("Unsupported Marionette protocol version {}, required 3", - self.session.protocol.as_ref().unwrap_or(&"<unknown>".into())))); - } - - Ok(()) - } - - pub fn close(&self) { - } - - fn encode_msg(&self, msg:Json) -> String { - let data = json::encode(&msg).unwrap(); - format!("{}:{}", data.len(), data) - } - - pub fn send_command(&mut self, - capabilities: Option<BTreeMap<String, Json>>, - msg: &WebDriverMessage<GeckoExtensionRoute>) - -> WebDriverResult<WebDriverResponse> { - let id = self.session.next_command_id(); - let command = try!(MarionetteCommand::from_webdriver_message(id, capabilities, msg)); - - let resp_data = try!(self.send(command.to_json())); - let json_data: Json = try!(Json::from_str(&*resp_data)); - - self.session.response(msg, try!(MarionetteResponse::from_json(&json_data))) - } - - fn send(&mut self, msg: Json) -> WebDriverResult<String> { - let data = self.encode_msg(msg); - trace!("-> {}", data); - - match self.stream { - Some(ref mut stream) => { - if stream.write(&*data.as_bytes()).is_err() { - let mut err = WebDriverError::new(ErrorStatus::UnknownError, - "Failed to write response to stream"); - err.delete_session = true; - return Err(err); - } - } - None => { - let mut err = WebDriverError::new(ErrorStatus::UnknownError, - "Tried to write before opening stream"); - err.delete_session = true; - return Err(err); - } - } - match self.read_resp() { - Ok(resp) => Ok(resp), - Err(_) => { - let mut err = WebDriverError::new(ErrorStatus::UnknownError, - "Failed to decode response from marionette"); - err.delete_session = true; - Err(err) - } - } - } - - fn read_resp(&mut self) -> IoResult<String> { - let mut bytes = 0usize; - - // TODO(jgraham): Check before we unwrap? - let mut stream = self.stream.as_mut().unwrap(); - loop { - let mut buf = &mut [0 as u8]; - let num_read = try!(stream.read(buf)); - let byte = match num_read { - 0 => { - return Err(IoError::new(ErrorKind::Other, - "EOF reading marionette message")) - }, - 1 => buf[0] as char, - _ => panic!("Expected one byte got more") - }; - match byte { - '0'...'9' => { - bytes = bytes * 10; - bytes += byte as usize - '0' as usize; - }, - ':' => { - break - } - _ => {} - } - } - - let mut buf = &mut [0 as u8; 8192]; - let mut payload = Vec::with_capacity(bytes); - let mut total_read = 0; - while total_read < bytes { - let num_read = try!(stream.read(buf)); - if num_read == 0 { - return Err(IoError::new(ErrorKind::Other, - "EOF reading marionette message")) - } - total_read += num_read; - for x in &buf[..num_read] { - payload.push(*x); - } - } - - // TODO(jgraham): Need to handle the error here - let data = String::from_utf8(payload).unwrap(); - trace!("<- {}", data); - - Ok(data) - } -} - -trait ToMarionette { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>>; -} - -impl ToMarionette for GetParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) - } -} - -impl ToMarionette for TimeoutsParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) - } -} - -impl ToMarionette for WindowRectParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) - } -} - -impl ToMarionette for SwitchToWindowParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("name".to_string(), self.handle.to_json()); - Ok(data) - } -} - -impl ToMarionette for LocatorParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), - ErrorStatus::UnknownError, - "Expected an object") - .clone()) - } -} - -impl ToMarionette for SwitchToFrameParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - let key = match self.id { - FrameId::Null => None, - FrameId::Short(_) => Some("id"), - FrameId::Element(_) => Some("element"), - }; - if let Some(x) = key { - data.insert(x.to_string(), self.id.to_json()); - } - Ok(data) - } -} - -impl ToMarionette for JavascriptCommandParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = self.to_json().as_object().unwrap().clone(); - data.insert("newSandbox".to_string(), false.to_json()); - data.insert("specialPowers".to_string(), false.to_json()); - data.insert("scriptTimeout".to_string(), Json::Null); - Ok(data) - } -} - -impl ToMarionette for ActionsParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), - ErrorStatus::UnknownError, - "Expected an object") - .clone()) - } -} - -impl ToMarionette for GetNamedCookieParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - Ok(try_opt!(self.to_json().as_object(), - ErrorStatus::UnknownError, - "Expected an object") - .clone()) - } -} - -impl ToMarionette for AddCookieParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut cookie = BTreeMap::new(); - cookie.insert("name".to_string(), self.name.to_json()); - cookie.insert("value".to_string(), self.value.to_json()); - if self.path.is_value() { - cookie.insert("path".to_string(), self.path.to_json()); - } - if self.domain.is_value() { - cookie.insert("domain".to_string(), self.domain.to_json()); - } - if self.expiry.is_value() { - cookie.insert("expiry".to_string(), self.expiry.to_json()); - } - cookie.insert("secure".to_string(), self.secure.to_json()); - cookie.insert("httpOnly".to_string(), self.httpOnly.to_json()); - let mut data = BTreeMap::new(); - data.insert("cookie".to_string(), Json::Object(cookie)); - Ok(data) - } -} - -impl ToMarionette for TakeScreenshotParameters { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - let element = match self.element { - Nullable::Null => Json::Null, - Nullable::Value(ref x) => Json::Object(try!(x.to_marionette())) - }; - data.insert("element".to_string(), element); - Ok(data) - } -} - -impl ToMarionette for WebElement { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - data.insert("id".to_string(), self.id.to_json()); - Ok(data) - } -} - -impl<T: ToJson> ToMarionette for Nullable<T> { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - //Note this is a terrible hack. We don't want Nullable<T: ToJson+ToMarionette> - //so in cases where ToJson != ToMarionette you have to deal with the Nullable - //explicitly. This kind of suggests that the whole design is wrong. - Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) - } -} - -impl ToMarionette for FrameId { - fn to_marionette(&self) -> WebDriverResult<BTreeMap<String, Json>> { - let mut data = BTreeMap::new(); - match *self { - FrameId::Short(x) => data.insert("id".to_string(), x.to_json()), - FrameId::Element(ref x) => data.insert("element".to_string(), - Json::Object(try!(x.to_marionette()))), - FrameId::Null => None - }; - Ok(data) - } -} diff --git a/src/prefs.rs b/src/prefs.rs deleted file mode 100644 index 3e82850..0000000 --- a/src/prefs.rs +++ /dev/null @@ -1,226 +0,0 @@ -use mozprofile::preferences::Pref; - -lazy_static! { - pub static ref DEFAULT: [(&'static str, Pref); 78] = [ - // Disable automatic downloading of new releases - ("app.update.auto", Pref::new(false)), - - // Disable automatically upgrading Firefox - ("app.update.enabled", Pref::new(false)), - - // Increase the APZ content response timeout in tests to 1 - // minute. This is to accommodate the fact that test environments - // tends to be slower than production environments (with the - // b2g emulator being the slowest of them all), resulting in the - // production timeout value sometimes being exceeded and causing - // false-positive test failures. - // - // (bug 1176798, bug 1177018, bug 1210465) - ("apz.content_response_timeout", Pref::new(60000)), - - // Enable the dump function, which sends messages to the system - // console - ("browser.dom.window.dump.enabled", Pref::new(true)), - - // Indicate that the download panel has been shown once so - // that whichever download test runs first does not show the popup - // inconsistently - ("browser.download.panel.shown", Pref::new(true)), - - // Implicitly accept license - ("browser.EULA.override", Pref::new(true)), - - // use about:blank as new tab page - ("browser.newtabpage.enabled", Pref::new(false)), - - // Assume the about:newtab pages intro panels have been shown - // to not depend on which test runs first and happens to open - // about:newtab - ("browser.newtabpage.introShown", Pref::new(true)), - - // Never start the browser in offline mode - ("browser.offline", Pref::new(false)), - - // Background thumbnails in particular cause grief, and disabling - // thumbnails in general cannot hurt - ("browser.pagethumbnails.capturing_disabled", Pref::new(true)), - - // Avoid performing Reader Mode intros during tests - ("browser.reader.detectedFirstArticle", Pref::new(true)), - - // Disable safebrowsing components - ("browser.safebrowsing.blockedURIs.enabled", Pref::new(false)), - ("browser.safebrowsing.downloads.enabled", Pref::new(false)), - ("browser.safebrowsing.enabled", Pref::new(false)), - ("browser.safebrowsing.forbiddenURIs.enabled", Pref::new(false)), - ("browser.safebrowsing.malware.enabled", Pref::new(false)), - ("browser.safebrowsing.phishing.enabled", Pref::new(false)), - - // Disable updates to search engines - ("browser.search.update", Pref::new(false)), - - // Do not restore the last open set of tabs if the browser crashed - ("browser.sessionstore.resume_from_crash", Pref::new(false)), - - // Skip check for default browser on startup - ("browser.shell.checkDefaultBrowser", Pref::new(false)), - - // Do not warn when quitting with multiple tabs - ("browser.showQuitWarning", Pref::new(false)), - - // Disable Android snippets - ("browser.snippets.enabled", Pref::new(false)), - ("browser.snippets.syncPromo.enabled", Pref::new(false)), - ("browser.snippets.firstrunHomepage.enabled", Pref::new(false)), - - // Do not redirect user when a milestone upgrade of Firefox - // is detected - ("browser.startup.homepage_override.mstone", Pref::new("ignore")), - - // Start with a blank page (about:blank) - ("browser.startup.page", Pref::new(0)), - - // Disable tab animation - ("browser.tabs.animate", Pref::new(false)), - - // Do not warn when quitting a window with multiple tabs - ("browser.tabs.closeWindowWithLastTab", Pref::new(false)), - - // Do not allow background tabs to be zombified, otherwise for - // tests that open additional tabs, the test harness tab itself - // might get unloaded - ("browser.tabs.disableBackgroundZombification", Pref::new(false)), - - // Do not warn on exit when multiple tabs are open - ("browser.tabs.warnOnClose", Pref::new(false)), - - // Do not warn when closing all other open tabs - ("browser.tabs.warnOnCloseOtherTabs", Pref::new(false)), - - // Do not warn when multiple tabs will be opened - ("browser.tabs.warnOnOpen", Pref::new(false)), - - // Disable first run splash page on Windows 10 - ("browser.usedOnWindows10.introURL", Pref::new("")), - - // Disable the UI tour - ("browser.uitour.enabled", Pref::new(false)), - - // Do not warn on quitting Firefox - ("browser.warnOnQuit", Pref::new(false)), - - // Do not show datareporting policy notifications which can - // interfere with tests - ("datareporting.healthreport.about.reportUrl", Pref::new("http://%(server)s/dummy/abouthealthreport/")), - ("datareporting.healthreport.documentServerURI", Pref::new("http://%(server)s/dummy/healthreport/")), - ("datareporting.healthreport.logging.consoleEnabled", Pref::new(false)), - ("datareporting.healthreport.service.enabled", Pref::new(false)), - ("datareporting.healthreport.service.firstRun", Pref::new(false)), - ("datareporting.healthreport.uploadEnabled", Pref::new(false)), - ("datareporting.policy.dataSubmissionEnabled", Pref::new(false)), - ("datareporting.policy.dataSubmissionPolicyAccepted", Pref::new(false)), - ("datareporting.policy.dataSubmissionPolicyBypassNotification", Pref::new(true)), - - // Disable popup-blocker - ("dom.disable_open_during_load", Pref::new(false)), - - // Disable the ProcessHangMonitor - ("dom.ipc.reportProcessHangs", Pref::new(false)), - - // Disable slow script dialogues - ("dom.max_chrome_script_run_time", Pref::new(0)), - ("dom.max_script_run_time", Pref::new(0)), - - // Only load extensions from the application and user profile - // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION - ("extensions.autoDisableScopes", Pref::new(0)), - ("extensions.enabledScopes", Pref::new(5)), - - // don't block add-ons for e10s - ("extensions.e10sBlocksEnabling", Pref::new(false)), - - // Disable metadata caching for installed add-ons by default - ("extensions.getAddons.cache.enabled", Pref::new(false)), - - // Disable intalling any distribution extensions or add-ons - ("extensions.installDistroAddons", Pref::new(false)), - ("extensions.showMismatchUI", Pref::new(false)), - - // Turn off extension updates so they do not bother tests - ("extensions.update.enabled", Pref::new(false)), - ("extensions.update.notifyUser", Pref::new(false)), - - // Make sure opening about:addons will not hit the network - ("extensions.webservice.discoverURL", Pref::new("http://%(server)s/dummy/discoveryURL")), - - // Allow the application to have focus even it runs in the - // background - ("focusmanager.testmode", Pref::new(true)), - - // Disable useragent updates - ("general.useragent.updates.enabled", Pref::new(false)), - - // Always use network provider for geolocation tests so we bypass - // the macOS dialog raised by the corelocation provider - ("geo.provider.testing", Pref::new(true)), - - // Do not scan wi-fi - ("geo.wifi.scan", Pref::new(false)), - - // No hang monitor - ("hangmonitor.timeout", Pref::new(0)), - - // Show chrome errors and warnings in the error console - ("javascript.options.showInConsole", Pref::new(true)), - - // Make sure the disk cache does not get auto disabled - ("network.http.bypass-cachelock-threshold", Pref::new(200000)), - - // Do not prompt for temporary redirects - ("network.http.prompt-temp-redirect", Pref::new(false)), - - // Disable speculative connections so they are not reported as - // leaking when they are hanging around - ("network.http.speculative-parallel-limit", Pref::new(0)), - - // Do not automatically switch between offline and online - ("network.manage-offline-status", Pref::new(false)), - - // Make sure SNTP requests do not hit the network - ("network.sntp.pools", Pref::new("%(server)s")), - - // Disable Flash. The plugin container it is run in is - // causing problems when quitting Firefox from geckodriver, - // c.f. https://github.com/mozilla/geckodriver/issues/225. - ("plugin.state.flash", Pref::new(0)), - - // Local documents have access to all other local docments, - // including directory listings. - ("security.fileuri.strict_origin_policy", Pref::new(false)), - - // Tests don't wait for the notification button security delay - ("security.notification_enable_delay", Pref::new(0)), - - // Ensure blocklist updates don't hit the network - ("services.settings.server", Pref::new("http://%(server)s/dummy/blocklist/")), - - // Do not automatically fill sign-in forms with known usernames - // and passwords - ("signon.autofillForms", Pref::new(false)), - - // Disable password capture, so that tests that include forms - // are not influenced by the presence of the persistent doorhanger - // notification - ("signon.rememberSignons", Pref::new(false)), - - // Disable first run pages - ("startup.homepage_welcome_url", Pref::new("about:blank")), - ("startup.homepage_welcome_url.additional", Pref::new("")), - - // Prevent starting into safe mode after application crashes - ("toolkit.startup.max_resumed_crashes", Pref::new(-1)), - - // We want to collect telemetry, but we don't want to send in the results - ("toolkit.telemetry.server", Pref::new("https://%(server)s/dummy/telemetry/")), - ]; -} diff --git a/src/tests/profile.zip b/src/tests/profile.zip Binary files differdeleted file mode 100644 index 286b118..0000000 --- a/src/tests/profile.zip +++ /dev/null |