Merge autoland to mozilla-central. a=merge

This commit is contained in:
arthur.iakab 2018-03-11 23:44:57 +02:00
commit e8f2bfe9a4
3 changed files with 104 additions and 85 deletions

View File

@ -5,7 +5,7 @@
//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser, ParserInput, CowRcStr};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation, Token};
use error_reporting::{NullReporter, ContextualParseError, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext};
use properties::{DeclarationSource, Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
@ -126,20 +126,21 @@ impl KeyframePercentage {
}
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
KeyframePercentage::new(0.)
} else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
KeyframePercentage::new(1.)
} else {
let percentage = input.expect_percentage()?;
if percentage >= 0. && percentage <= 1. {
KeyframePercentage::new(percentage)
} else {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
};
Ok(percentage)
let token = input.next()?.clone();
match token {
Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
Ok(KeyframePercentage::new(0.))
},
Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
Ok(KeyframePercentage::new(1.))
},
Token::Percentage { unit_value: percentage, .. } if percentage >= 0. && percentage <= 1. => {
Ok(KeyframePercentage::new(percentage))
},
_ => {
Err(input.new_unexpected_token_error(token))
},
}
}
}

View File

@ -17,8 +17,8 @@ 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 std::thread;
use std::time;
use uuid::Uuid;
use webdriver::capabilities::CapabilitiesMatching;
use webdriver::command::{WebDriverCommand, WebDriverMessage, Parameters,
@ -56,10 +56,6 @@ use prefs;
const DEFAULT_HOST: &'static str = "localhost";
// Firefox' integrated background monitor which observes long running threads during
// shutdown kills those after 65s. Wait some additional seconds for a safe shutdown
const TIMEOUT_BROWSER_SHUTDOWN: u64 = 70 * 1000;
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),
@ -571,7 +567,7 @@ impl WebDriverHandler<GeckoExtensionRoute> for MarionetteHandler {
// Shutdown the browser if no session can
// be established due to errors.
if let NewSession(_) = msg.command {
err.delete_session=true;
err.delete_session = true;
}
err})
},
@ -587,32 +583,12 @@ impl WebDriverHandler<GeckoExtensionRoute> for MarionetteHandler {
}
fn delete_session(&mut self, session: &Option<Session>) {
// If there is still an active session send a delete session command
// and wait for the browser to quit
if let Some(ref s) = *session {
let delete_session = WebDriverMessage {
session_id: Some(s.id.clone()),
command: WebDriverCommand::DeleteSession
command: WebDriverCommand::DeleteSession,
};
let _ = self.handle_command(session, delete_session);
if let Some(ref mut runner) = self.browser {
let timeout = TIMEOUT_BROWSER_SHUTDOWN;
let poll_interval = 100;
let poll_attempts = timeout / poll_interval;
let mut poll_attempt = 0;
while runner.is_running() {
if poll_attempt <= poll_attempts {
debug!("Waiting for the browser process to shutdown");
poll_attempt += 1;
sleep(Duration::from_millis(poll_interval));
} else {
warn!("Browser process did not shutdown");
break;
}
}
}
}
if let Ok(ref mut connection) = self.connection.lock() {
@ -621,13 +597,11 @@ impl WebDriverHandler<GeckoExtensionRoute> for MarionetteHandler {
}
}
// If the browser is still open then kill the process
if let Some(ref mut runner) = self.browser {
if runner.is_running() {
info!("Forcing a shutdown of the browser process");
if runner.stop().is_err() {
error!("Failed to kill browser process");
};
// TODO(https://bugzil.la/1443922):
// Use toolkit.asyncshutdown.crash_timout pref
if runner.wait(time::Duration::from_secs(70)).is_err() {
error!("Failed to stop browser process");
}
}
@ -985,10 +959,10 @@ impl MarionetteSession {
let expiry = try!(
Nullable::from_json(x.find("expiry").unwrap_or(&Json::Null),
|x| {
Ok(Date::new((try_opt!(
Ok(Date::new(try_opt!(
x.as_u64(),
ErrorStatus::UnknownError,
"Cookie expiry must be a positive integer"))))
"Cookie expiry must be a positive integer")))
}));
let secure = try_opt!(
x.find("secure").map_or(Some(false), |x| x.as_boolean()),
@ -1341,54 +1315,59 @@ impl MarionetteConnection {
MarionetteConnection {
port: port,
stream: None,
session: MarionetteSession::new(session_id)
session: MarionetteSession::new(session_id),
}
}
pub fn connect(&mut self, browser: &mut Option<FirefoxProcess>) -> WebDriverResult<()> {
let timeout = 60 * 1000; // ms
let poll_interval = 100; // ms
let timeout = 60 * 1000; // ms
let poll_interval = 100; // ms
let poll_attempts = timeout / poll_interval;
let mut poll_attempt = 0;
loop {
// If the process is gone, immediately abort the connection attempts
// immediately abort connection attempts if process disappears
if let &mut Some(ref mut runner) = browser {
let status = runner.status();
if status.is_err() || status.as_ref().map(|x| *x).unwrap_or(None) != None {
let exit_status = match runner.try_wait() {
Ok(Some(status)) => Some(
status
.code()
.map(|c| c.to_string())
.unwrap_or("signal".into()),
),
Ok(None) => None,
Err(_) => Some("{unknown}".into()),
};
if let Some(s) = exit_status {
return Err(WebDriverError::new(
ErrorStatus::UnknownError,
format!("Process unexpectedly closed with status: {}", status
.ok()
.and_then(|x| x)
.and_then(|x| x.code())
.map(|x| x.to_string())
.unwrap_or("{unknown}".into()))));
format!("Process unexpectedly closed with status {}", s),
));
}
}
match TcpStream::connect(&(DEFAULT_HOST, self.port)) {
Ok(stream) => {
self.stream = Some(stream);
break
},
break;
}
Err(e) => {
trace!(" connection attempt {}/{}", poll_attempt, poll_attempts);
if poll_attempt <= poll_attempts {
poll_attempt += 1;
sleep(Duration::from_millis(poll_interval));
thread::sleep(time::Duration::from_millis(poll_interval));
} else {
return Err(WebDriverError::new(
ErrorStatus::UnknownError, e.description().to_owned()));
ErrorStatus::UnknownError,
e.description().to_owned(),
));
}
}
}
};
}
debug!("Connected to Marionette on {}:{}", DEFAULT_HOST, self.port);
try!(self.handshake());
Ok(())
self.handshake()
}
fn handshake(&mut self) -> WebDriverResult<()> {

View File

@ -1,16 +1,18 @@
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::convert::From;
use std::env;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
use std::io;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};
use std::process;
use std::process::{Child, Command, Stdio};
use std::thread;
use std::time;
pub trait Runner {
type Process;
@ -47,14 +49,40 @@ pub trait Runner {
}
pub trait RunnerProcess {
fn status(&mut self) -> IoResult<Option<process::ExitStatus>>;
fn stop(&mut self) -> IoResult<process::ExitStatus>;
fn is_running(&mut self) -> bool;
/// Attempts to collect the exit status of the process if it has already exited.
///
/// This function will not block the calling thread and will only advisorily check to see if
/// the child process has exited or not. If the process has exited then on Unix the process ID
/// is reaped. This function is guaranteed to repeatedly return a successful exit status so
/// long as the child has already exited.
///
/// If the process has exited, then `Ok(Some(status))` is returned. If the exit status is not
/// available at this time then `Ok(None)` is returned. If an error occurs, then that error is
/// returned.
fn try_wait(&mut self) -> io::Result<Option<process::ExitStatus>>;
/// Waits for the process to exit completely, killing it if it does not stop within `timeout`,
/// and returns the status that it exited with.
///
/// Firefox' integrated background monitor observes long running threads during shutdown and
/// kills these after 63 seconds. If the process fails to exit within the duration of
/// `timeout`, it is forcefully killed.
///
/// This function will continue to have the same return value after it has been called at least
/// once.
fn wait(&mut self, timeout: time::Duration) -> io::Result<process::ExitStatus>;
/// Determine if the process is still running.
fn running(&mut self) -> bool;
/// Forces the process to exit and returns the exit status. This is
/// equivalent to sending a SIGKILL on Unix platforms.
fn kill(&mut self) -> io::Result<process::ExitStatus>;
}
#[derive(Debug)]
pub enum RunnerError {
Io(IoError),
Io(io::Error),
PrefReader(PrefReaderError),
}
@ -85,8 +113,8 @@ impl Error for RunnerError {
}
}
impl From<IoError> for RunnerError {
fn from(value: IoError) -> RunnerError {
impl From<io::Error> for RunnerError {
fn from(value: io::Error) -> RunnerError {
RunnerError::Io(value)
}
}
@ -100,19 +128,30 @@ impl From<PrefReaderError> for RunnerError {
#[derive(Debug)]
pub struct FirefoxProcess {
process: Child,
profile: Profile
profile: Profile,
}
impl RunnerProcess for FirefoxProcess {
fn status(&mut self) -> IoResult<Option<process::ExitStatus>> {
fn try_wait(&mut self) -> io::Result<Option<process::ExitStatus>> {
self.process.try_wait()
}
fn is_running(&mut self) -> bool {
self.status().unwrap().is_none()
fn wait(&mut self, timeout: time::Duration) -> io::Result<process::ExitStatus> {
let now = time::Instant::now();
while self.running() {
if now.elapsed() >= timeout {
break;
}
thread::sleep(time::Duration::from_millis(100));
}
self.kill()
}
fn stop(&mut self) -> IoResult<process::ExitStatus> {
fn running(&mut self) -> bool {
self.try_wait().unwrap().is_none()
}
fn kill(&mut self) -> io::Result<process::ExitStatus> {
self.process.kill()?;
self.process.wait()
}