Commit 933b81ec authored by Andrey Lushnikov's avatar Andrey Lushnikov Committed by Commit Bot

DevTools: implement Target.createBrowserContext for non-headless mode

This patch uses OffTheRecord profiles to implement
|Target.createBrowserContext| and |Target.diposeBrowserContext| methods
for non-headless mode.

R=dgozman
BUG=836272

Change-Id: Ibd8b33bd9c804b69f17ef9cf1283b8c4bfc405ac
Reviewed-on: https://chromium-review.googlesource.com/1023591
Commit-Queue: Andrey Lushnikov <lushnikov@chromium.org>
Reviewed-by: default avatarStefan Kuhne <skuhne@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553323}
parent 4ff78330
......@@ -25,9 +25,8 @@ ChromeDevToolsSession::ChromeDevToolsSession(
agent_host->GetType() == content::DevToolsAgentHost::kTypePage) {
page_handler_ = std::make_unique<PageHandler>(agent_host->GetWebContents(),
dispatcher_.get());
target_handler_ = std::make_unique<TargetHandler>(
agent_host->GetWebContents(), dispatcher_.get());
}
target_handler_ = std::make_unique<TargetHandler>(dispatcher_.get());
browser_handler_ = std::make_unique<BrowserHandler>(dispatcher_.get());
#if defined(OS_CHROMEOS)
window_manager_protocl_handler_ =
......
......@@ -2206,6 +2206,18 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, LoadNetworkResourceForFrontend) {
DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
}
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, CreateBrowserContext) {
embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url(embedded_test_server()->GetURL("/devtools/empty.html"));
ui_test_utils::NavigateToURL(browser(), url);
window_ =
DevToolsWindowTesting::OpenDevToolsWindowSync(GetInspectedTab(), false);
RunTestMethod("testCreateBrowserContext", url.spec().c_str());
DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
}
IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsSanityTest, InspectElement) {
GURL url(embedded_test_server()->GetURL("a.com", "/devtools/oopif.html"));
GURL iframe_url(
......
......@@ -18,7 +18,7 @@
},
{
"domain": "Target",
"include": [ "setRemoteLocations" ],
"include": [ "setRemoteLocations", "createBrowserContext", "createTarget", "disposeBrowserContext" ],
"include_events": []
},
{
......
......@@ -5,10 +5,14 @@
#include "chrome/browser/devtools/protocol/target_handler.h"
#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "content/public/browser/devtools_agent_host.h"
TargetHandler::TargetHandler(content::WebContents* web_contents,
protocol::UberDispatcher* dispatcher) {
DCHECK(web_contents);
TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher)
: weak_factory_(this) {
protocol::Target::Dispatcher::wire(dispatcher, this);
}
......@@ -17,6 +21,7 @@ TargetHandler::~TargetHandler() {
ChromeDevToolsManagerDelegate::GetInstance();
if (delegate)
delegate->UpdateDeviceDiscovery();
registrations_.clear();
}
protocol::Response TargetHandler::SetRemoteLocations(
......@@ -38,3 +43,91 @@ protocol::Response TargetHandler::SetRemoteLocations(
delegate->UpdateDeviceDiscovery();
return protocol::Response::OK();
}
protocol::Response TargetHandler::CreateTarget(
const std::string& url,
protocol::Maybe<int> width,
protocol::Maybe<int> height,
protocol::Maybe<std::string> browser_context_id,
protocol::Maybe<bool> enable_begin_frame_control,
std::string* out_target_id) {
Profile* profile = ProfileManager::GetActiveUserProfile();
if (browser_context_id.isJust()) {
std::string profile_id = browser_context_id.fromJust();
auto it = registrations_.find(profile_id);
if (it == registrations_.end()) {
return protocol::Response::Error(
"Failed to find browser context with id " + profile_id);
}
profile = it->second->profile();
}
NavigateParams params(profile, GURL(url), ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
Browser* target_browser = nullptr;
// Find a browser to open a new tab.
// We shouldn't use browser that is scheduled to close.
for (auto* browser : *BrowserList::GetInstance()) {
if (browser->profile() == profile &&
!browser->IsAttemptingToCloseBrowser()) {
target_browser = browser;
break;
}
}
if (target_browser) {
params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
params.browser = target_browser;
} else {
params.disposition = WindowOpenDisposition::NEW_WINDOW;
}
Navigate(&params);
if (!params.target_contents)
return protocol::Response::Error("Failed to open a new tab");
*out_target_id =
content::DevToolsAgentHost::GetOrCreateFor(params.target_contents)
->GetId();
return protocol::Response::OK();
}
protocol::Response TargetHandler::CreateBrowserContext(
std::string* out_context_id) {
Profile* original_profile =
ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
auto registration =
IndependentOTRProfileManager::GetInstance()->CreateFromOriginalProfile(
original_profile,
base::BindOnce(&TargetHandler::OnOriginalProfileDestroyed,
weak_factory_.GetWeakPtr()));
*out_context_id = registration->profile()->UniqueId();
registrations_[*out_context_id] = std::move(registration);
return protocol::Response::OK();
}
void TargetHandler::OnOriginalProfileDestroyed(Profile* profile) {
base::EraseIf(registrations_, [&profile](const auto& it) {
return it.second->profile()->GetOriginalProfile() == profile;
});
}
protocol::Response TargetHandler::DisposeBrowserContext(
const std::string& context_id,
bool* out_success) {
auto it = registrations_.find(context_id);
if (it == registrations_.end()) {
return protocol::Response::Error("Failed to find browser context with id " +
context_id);
}
Profile* profile = it->second->profile();
for (auto* browser : *BrowserList::GetInstance()) {
if (browser->profile() == profile &&
!browser->IsAttemptingToCloseBrowser()) {
*out_success = false;
return protocol::Response::OK();
}
}
registrations_.erase(it);
*out_success = true;
return protocol::Response::OK();
}
......@@ -7,20 +7,17 @@
#include <set>
#include "base/memory/weak_ptr.h"
#include "chrome/browser/devtools/protocol/forward.h"
#include "chrome/browser/devtools/protocol/target.h"
#include "chrome/browser/media/router/presentation/independent_otr_profile_manager.h"
#include "net/base/host_port_pair.h"
namespace content {
class WebContents;
}
using RemoteLocations = std::set<net::HostPortPair>;
class TargetHandler : public protocol::Target::Backend {
public:
TargetHandler(content::WebContents* web_contents,
protocol::UberDispatcher* dispatcher);
explicit TargetHandler(protocol::UberDispatcher* dispatcher);
~TargetHandler() override;
RemoteLocations& remote_locations() { return remote_locations_; }
......@@ -29,10 +26,28 @@ class TargetHandler : public protocol::Target::Backend {
protocol::Response SetRemoteLocations(
std::unique_ptr<protocol::Array<protocol::Target::RemoteLocation>>
in_locations) override;
protocol::Response CreateBrowserContext(std::string* out_context_id) override;
protocol::Response CreateTarget(
const std::string& url,
protocol::Maybe<int> width,
protocol::Maybe<int> height,
protocol::Maybe<std::string> browser_context_id,
protocol::Maybe<bool> enable_begin_frame_control,
std::string* out_target_id) override;
protocol::Response DisposeBrowserContext(const std::string& context_id,
bool* out_success) override;
private:
void OnOriginalProfileDestroyed(Profile* profile);
base::flat_map<
std::string,
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>>
registrations_;
RemoteLocations remote_locations_;
base::WeakPtrFactory<TargetHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TargetHandler);
};
......
......@@ -1110,6 +1110,66 @@
this.releaseControl();
};
TestSuite.prototype.testCreateBrowserContext = async function(url) {
this.takeControl();
const browserContextIds = [];
const target1 = await createIsolatedTarget(url);
const target2 = await createIsolatedTarget(url);
await evalCode(target1, 'localStorage.setItem("page1", "page1")');
await evalCode(target2, 'localStorage.setItem("page2", "page2")');
this.assertEquals(await evalCode(target1, 'localStorage.getItem("page1")'), 'page1');
this.assertEquals(await evalCode(target1, 'localStorage.getItem("page2")'), null);
this.assertEquals(await evalCode(target2, 'localStorage.getItem("page1")'), null);
this.assertEquals(await evalCode(target2, 'localStorage.getItem("page2")'), 'page2');
this.assertEquals(await disposeBrowserContext(browserContextIds[0]), false);
this.assertEquals(await disposeBrowserContext(browserContextIds[1]), false);
await closeTarget(target1);
await closeTarget(target2);
this.assertEquals(await disposeBrowserContext(browserContextIds[0]), true);
this.assertEquals(await disposeBrowserContext(browserContextIds[1]), true);
this.releaseControl();
/**
* @param {string} url
* @return {!Promise<!SDK.Target>}
*/
async function createIsolatedTarget(url) {
const targetAgent = SDK.targetManager.mainTarget().targetAgent();
const {browserContextId} = await targetAgent.invoke_createBrowserContext();
browserContextIds.push(browserContextId);
const {targetId} = await targetAgent.invoke_createTarget({url: 'about:blank', browserContextId});
await targetAgent.invoke_attachToTarget({targetId});
const target = SDK.targetManager.targets().find(target => target.id() === targetId);
const pageAgent = target.pageAgent();
await pageAgent.invoke_enable();
await pageAgent.invoke_navigate({url});
return target;
}
async function closeTarget(target) {
const targetAgent = SDK.targetManager.mainTarget().targetAgent();
await targetAgent.invoke_closeTarget({targetId: target.id()});
}
async function disposeBrowserContext(browserContextId) {
const targetAgent = SDK.targetManager.mainTarget().targetAgent();
const {success} = await targetAgent.invoke_disposeBrowserContext({browserContextId});
return success;
}
async function evalCode(target, code) {
return (await target.runtimeAgent().invoke_evaluate({expression: code})).result.value;
}
};
TestSuite.prototype.testInputDispatchEventsToOOPIF = async function() {
this.takeControl();
......
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