Commit 6afa6bc9 authored by Long Ly's avatar Long Ly Committed by Commit Bot

Fix to restrict W3C commands while in W3C mode

By default, all commands are accessible. However, once user specifies
session in W3C mode, all JWP commands will return as "Unknown Command".
Other commands such as "unknown origin", "ChromeDriver extentions"
won't be affected by the PR since they are used by Selenium binding
and internal python tests.


Bug: chromedriver:2060
Change-Id: I1e09fd6f06e290f374ffde5bc3507defe9fb52cd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504977Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Commit-Queue: Long Ly <loly@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#638186}
parent 70f834ba
...@@ -205,6 +205,7 @@ void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map, ...@@ -205,6 +205,7 @@ void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map,
void ExecuteSessionCommandOnSessionThread( void ExecuteSessionCommandOnSessionThread(
const char* command_name, const char* command_name,
const SessionCommand& command, const SessionCommand& command,
bool w3c_standard_command,
bool return_ok_without_session, bool return_ok_without_session,
std::unique_ptr<base::DictionaryValue> params, std::unique_ptr<base::DictionaryValue> params,
scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner, scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner,
...@@ -237,65 +238,73 @@ void ExecuteSessionCommandOnSessionThread( ...@@ -237,65 +238,73 @@ void ExecuteSessionCommandOnSessionThread(
// Will mark |session| for deletion if an error is encountered. // Will mark |session| for deletion if an error is encountered.
Status status = NotifyCommandListenersBeforeCommand(session, command_name); Status status = NotifyCommandListenersBeforeCommand(session, command_name);
// Only run the command if we were able to notify all listeners successfully.
// Otherwise, pass error to callback, delete |session|, and do not continue.
std::unique_ptr<base::Value> value; std::unique_ptr<base::Value> value;
if (status.IsError()) { if (session->w3c_compliant && !w3c_standard_command) {
LOG(ERROR) << status.message(); status = Status(kUnknownCommand,
"Cannot call non W3C standard command while in W3C mode");
} else { } else {
status = command.Run(session, *params, &value); // Only run the command if we were able to notify all listeners
// successfully.
if (status.IsError() && session->chrome) { // Otherwise, pass error to callback, delete |session|, and do not continue.
if (!session->quit && session->chrome->HasCrashedWebView()) { if (status.IsError()) {
session->quit = true; LOG(ERROR) << status.message();
std::string message("session deleted because of page crash"); } else {
if (!session->detach) { status = command.Run(session, *params, &value);
Status quit_status = session->chrome->Quit();
if (quit_status.IsError()) if (status.IsError() && session->chrome) {
message += ", but failed to kill browser:" + quit_status.message(); if (!session->quit && session->chrome->HasCrashedWebView()) {
session->quit = true;
std::string message("session deleted because of page crash");
if (!session->detach) {
Status quit_status = session->chrome->Quit();
if (quit_status.IsError())
message +=
", but failed to kill browser:" + quit_status.message();
}
status = Status(kUnknownError, message, status);
} else if (status.code() == kDisconnected) {
// Some commands, like clicking a button or link which closes the
// window, may result in a kDisconnected error code.
std::list<std::string> web_view_ids;
Status status_tmp = session->chrome->GetWebViewIds(
&web_view_ids, session->w3c_compliant);
if (status_tmp.IsError() &&
status_tmp.code() != kChromeNotReachable) {
status.AddDetails("failed to check if window was closed: " +
status_tmp.message());
} else if (!base::ContainsValue(web_view_ids, session->window)) {
status = Status(kOk);
}
} }
status = Status(kUnknownError, message, status); if (status.IsError()) {
} else if (status.code() == kDisconnected) { const BrowserInfo* browser_info = session->chrome->GetBrowserInfo();
// Some commands, like clicking a button or link which closes the status.AddDetails("Session info: " + browser_info->browser_name +
// window, may result in a kDisconnected error code. "=" + browser_info->browser_version);
std::list<std::string> web_view_ids;
Status status_tmp = session->chrome->GetWebViewIds(
&web_view_ids, session->w3c_compliant);
if (status_tmp.IsError() && status_tmp.code() != kChromeNotReachable) {
status.AddDetails(
"failed to check if window was closed: " + status_tmp.message());
} else if (!base::ContainsValue(web_view_ids, session->window)) {
status = Status(kOk);
} }
} }
if (status.IsError()) {
const BrowserInfo* browser_info = session->chrome->GetBrowserInfo();
status.AddDetails("Session info: " + browser_info->browser_name + "=" +
browser_info->browser_version);
}
}
if (IsVLogOn(0)) { if (IsVLogOn(0)) {
std::string result; std::string result;
if (status.IsError()) { if (status.IsError()) {
result = "ERROR " + status.message(); result = "ERROR " + status.message();
} else if (value) { } else if (value) {
result = FormatValueForDisplay(*value); result = FormatValueForDisplay(*value);
} }
if (!session->driver_log || if (!session->driver_log ||
session->driver_log->min_level() != Log::Level::kOff) { session->driver_log->min_level() != Log::Level::kOff) {
// Note: ChromeDriver log-replay depends on the format of this logging. // Note: ChromeDriver log-replay depends on the format of this
// see chromedriver/log_replay/client_replay.py // logging. see chromedriver/log_replay/client_replay.py
VLOG(0) << "[" << session->id << "] " VLOG(0) << "[" << session->id << "] "
<< "RESPONSE " << command_name << "RESPONSE " << command_name
<< (result.length() ? " " + result : ""); << (result.length() ? " " + result : "");
}
} }
}
if (status.IsOk() && session->auto_reporting_enabled) { if (status.IsOk() && session->auto_reporting_enabled) {
std::string message = session->GetFirstBrowserError(); std::string message = session->GetFirstBrowserError();
if (!message.empty()) if (!message.empty())
status = Status(kUnknownError, message); status = Status(kUnknownError, message);
}
} }
} }
...@@ -312,14 +321,14 @@ void ExecuteSessionCommandOnSessionThread( ...@@ -312,14 +321,14 @@ void ExecuteSessionCommandOnSessionThread(
} // namespace } // namespace
void ExecuteSessionCommand( void ExecuteSessionCommand(SessionThreadMap* session_thread_map,
SessionThreadMap* session_thread_map, const char* command_name,
const char* command_name, const SessionCommand& command,
const SessionCommand& command, bool w3c_standard_command,
bool return_ok_without_session, bool return_ok_without_session,
const base::DictionaryValue& params, const base::DictionaryValue& params,
const std::string& session_id, const std::string& session_id,
const CommandCallback& callback) { const CommandCallback& callback) {
auto iter = session_thread_map->find(session_id); auto iter = session_thread_map->find(session_id);
if (iter == session_thread_map->end()) { if (iter == session_thread_map->end()) {
Status status(return_ok_without_session ? kOk : kInvalidSessionId); Status status(return_ok_without_session ? kOk : kInvalidSessionId);
...@@ -329,7 +338,7 @@ void ExecuteSessionCommand( ...@@ -329,7 +338,7 @@ void ExecuteSessionCommand(
iter->second->task_runner()->PostTask( iter->second->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&ExecuteSessionCommandOnSessionThread, command_name, base::BindOnce(&ExecuteSessionCommandOnSessionThread, command_name,
command, return_ok_without_session, command, w3c_standard_command, return_ok_without_session,
base::WrapUnique(params.DeepCopy()), base::WrapUnique(params.DeepCopy()),
base::ThreadTaskRunnerHandle::Get(), callback, base::ThreadTaskRunnerHandle::Get(), callback,
base::Bind(&TerminateSessionThreadOnCommandThread, base::Bind(&TerminateSessionThreadOnCommandThread,
......
...@@ -58,14 +58,14 @@ typedef base::Callback<Status(Session* session, ...@@ -58,14 +58,14 @@ typedef base::Callback<Status(Session* session,
// Executes a given session command, after acquiring access to the appropriate // Executes a given session command, after acquiring access to the appropriate
// session. // session.
void ExecuteSessionCommand( void ExecuteSessionCommand(SessionThreadMap* session_thread_map,
SessionThreadMap* session_thread_map, const char* command_name,
const char* command_name, const SessionCommand& command,
const SessionCommand& command, bool w3c_standard_command,
bool return_ok_without_session, bool return_ok_without_session,
const base::DictionaryValue& params, const base::DictionaryValue& params,
const std::string& session_id, const std::string& session_id,
const CommandCallback& callback); const CommandCallback& callback);
namespace internal { namespace internal {
void CreateSessionOnSessionThreadForTesting(const std::string& id); void CreateSessionOnSessionThreadForTesting(const std::string& id);
......
...@@ -246,12 +246,7 @@ TEST(CommandsTest, ExecuteSessionCommand) { ...@@ -246,12 +246,7 @@ TEST(CommandsTest, ExecuteSessionCommand) {
base::test::ScopedTaskEnvironment scoped_task_environment; base::test::ScopedTaskEnvironment scoped_task_environment;
base::RunLoop run_loop; base::RunLoop run_loop;
ExecuteSessionCommand( ExecuteSessionCommand(
&map, &map, "cmd", cmd, true /*w3c_standard_command*/, false, params, id,
"cmd",
cmd,
false,
params,
id,
base::Bind(&OnSimpleCommand, &run_loop, id, &expected_value)); base::Bind(&OnSimpleCommand, &run_loop, id, &expected_value));
run_loop.Run(); run_loop.Run();
} }
...@@ -286,24 +281,16 @@ void OnNoSuchSessionIsOk(const Status& status, ...@@ -286,24 +281,16 @@ void OnNoSuchSessionIsOk(const Status& status,
TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSession) { TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSession) {
SessionThreadMap map; SessionThreadMap map;
base::DictionaryValue params; base::DictionaryValue params;
ExecuteSessionCommand(&map, ExecuteSessionCommand(&map, "cmd", base::Bind(&ShouldNotBeCalled),
"cmd", true /*w3c_standard_command*/, false, params, "session",
base::Bind(&ShouldNotBeCalled),
false,
params,
"session",
base::Bind(&OnNoSuchSession)); base::Bind(&OnNoSuchSession));
} }
TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk) { TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk) {
SessionThreadMap map; SessionThreadMap map;
base::DictionaryValue params; base::DictionaryValue params;
ExecuteSessionCommand(&map, ExecuteSessionCommand(&map, "cmd", base::Bind(&ShouldNotBeCalled),
"cmd", true /*w3c_standard_command*/, true, params, "session",
base::Bind(&ShouldNotBeCalled),
true,
params,
"session",
base::Bind(&OnNoSuchSessionIsOk)); base::Bind(&OnNoSuchSessionIsOk));
} }
...@@ -330,12 +317,9 @@ TEST(CommandsTest, ExecuteSessionCommandOnJustDeletedSession) { ...@@ -330,12 +317,9 @@ TEST(CommandsTest, ExecuteSessionCommandOnJustDeletedSession) {
base::test::ScopedTaskEnvironment scoped_task_environment; base::test::ScopedTaskEnvironment scoped_task_environment;
base::RunLoop run_loop; base::RunLoop run_loop;
ExecuteSessionCommand(&map, ExecuteSessionCommand(&map, "cmd", base::Bind(&ShouldNotBeCalled),
"cmd", true /*w3c_standard_command*/, false,
base::Bind(&ShouldNotBeCalled), base::DictionaryValue(), "session",
false,
base::DictionaryValue(),
"session",
base::Bind(&OnNoSuchSessionAndQuit, &run_loop)); base::Bind(&OnNoSuchSessionAndQuit, &run_loop));
run_loop.Run(); run_loop.Run();
} }
...@@ -740,14 +724,9 @@ TEST(CommandsTest, SuccessNotifyingCommandListeners) { ...@@ -740,14 +724,9 @@ TEST(CommandsTest, SuccessNotifyingCommandListeners) {
// |CommandListener|s are notified immediately before commands are run. // |CommandListener|s are notified immediately before commands are run.
// Here, the command adds |listener| to the session, so |listener| // Here, the command adds |listener| to the session, so |listener|
// should not be notified since it will not have been added yet. // should not be notified since it will not have been added yet.
ExecuteSessionCommand( ExecuteSessionCommand(&map, "cmd", cmd, true /*w3c_standard_command*/, false,
&map, params, id,
"cmd", base::Bind(&OnSessionCommand, &run_loop_addlistener));
cmd,
false,
params,
id,
base::Bind(&OnSessionCommand, &run_loop_addlistener));
run_loop_addlistener.Run(); run_loop_addlistener.Run();
listener->VerifyNotCalled(); listener->VerifyNotCalled();
...@@ -757,14 +736,9 @@ TEST(CommandsTest, SuccessNotifyingCommandListeners) { ...@@ -757,14 +736,9 @@ TEST(CommandsTest, SuccessNotifyingCommandListeners) {
// |listener| was added to |session| by ExecuteAddListenerToSessionCommand // |listener| was added to |session| by ExecuteAddListenerToSessionCommand
// and should be notified before the next command, ExecuteQuitSessionCommand. // and should be notified before the next command, ExecuteQuitSessionCommand.
ExecuteSessionCommand( ExecuteSessionCommand(&map, "cmd", cmd, true /*w3c_standard_command*/, false,
&map, params, id,
"cmd", base::Bind(&OnSessionCommand, &run_loop_testlistener));
cmd,
false,
params,
id,
base::Bind(&OnSessionCommand, &run_loop_testlistener));
run_loop_testlistener.Run(); run_loop_testlistener.Run();
listener->VerifyCalled(); listener->VerifyCalled();
...@@ -832,12 +806,7 @@ TEST(CommandsTest, ErrorNotifyingCommandListeners) { ...@@ -832,12 +806,7 @@ TEST(CommandsTest, ErrorNotifyingCommandListeners) {
base::RunLoop run_loop; base::RunLoop run_loop;
ExecuteSessionCommand( ExecuteSessionCommand(
&map, &map, "cmd", cmd, true /*w3c_standard_command*/, false, params, id,
"cmd",
cmd,
false,
params,
id,
base::Bind(&OnFailBecauseErrorNotifyingListeners, &run_loop)); base::Bind(&OnFailBecauseErrorNotifyingListeners, &run_loop));
run_loop.Run(); run_loop.Run();
......
...@@ -85,10 +85,14 @@ class HttpHandler { ...@@ -85,10 +85,14 @@ class HttpHandler {
typedef std::vector<CommandMapping> CommandMap; typedef std::vector<CommandMapping> CommandMap;
Command WrapToCommand(const char* name, Command WrapToCommand(const char* name,
const SessionCommand& session_command); const SessionCommand& session_command,
Command WrapToCommand(const char* name, const WindowCommand& window_command); bool w3c_standard_command = true);
Command WrapToCommand(const char* name, Command WrapToCommand(const char* name,
const ElementCommand& element_command); const WindowCommand& window_command,
bool w3c_standard_command = true);
Command WrapToCommand(const char* name,
const ElementCommand& element_command,
bool w3c_standard_command = true);
void HandleCommand(const net::HttpServerRequestInfo& request, void HandleCommand(const net::HttpServerRequestInfo& request,
const std::string& trimmed_path, const std::string& trimmed_path,
const HttpResponseSenderFunc& send_response_func); const HttpResponseSenderFunc& send_response_func);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment