Commit c3ead867 authored by eseckler's avatar eseckler Committed by Commit bot

[headless] Add default browser context to HeadlessBrowser.

This also modifies HeadlessDevToolsManagerDelegate to send error
responses if required parameters are missing.

BUG=679343,546953

Review-Url: https://codereview.chromium.org/2626823003
Cr-Commit-Position: refs/heads/master@{#443538}
parent 6d2c4d88
......@@ -75,6 +75,8 @@ class HeadlessShell : public HeadlessWebContents::Observer,
HeadlessBrowserContext::Builder context_builder =
browser_->CreateBrowserContextBuilder();
// TODO(eseckler): These switches should also affect BrowserContexts that
// are created via DevTools later.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDeterministicFetch)) {
deterministic_dispatcher_.reset(
......@@ -98,6 +100,7 @@ class HeadlessShell : public HeadlessWebContents::Observer,
}));
}
browser_context_ = context_builder.Build();
browser_->SetDefaultBrowserContext(browser_context_);
HeadlessWebContents::Builder builder(
browser_context_->CreateWebContentsBuilder());
......
......@@ -54,6 +54,7 @@ HeadlessBrowserImpl::HeadlessBrowserImpl(
: on_start_callback_(on_start_callback),
options_(std::move(options)),
browser_main_parts_(nullptr),
default_browser_context_(nullptr),
weak_ptr_factory_(this) {}
HeadlessBrowserImpl::~HeadlessBrowserImpl() {}
......@@ -158,6 +159,19 @@ void HeadlessBrowserImpl::DestroyBrowserContext(
auto it = browser_contexts_.find(browser_context->Id());
DCHECK(it != browser_contexts_.end());
browser_contexts_.erase(it);
if (default_browser_context_ == browser_context)
SetDefaultBrowserContext(nullptr);
}
void HeadlessBrowserImpl::SetDefaultBrowserContext(
HeadlessBrowserContext* browser_context) {
DCHECK(!browser_context ||
this == HeadlessBrowserContextImpl::From(browser_context)->browser());
default_browser_context_ = browser_context;
}
HeadlessBrowserContext* HeadlessBrowserImpl::GetDefaultBrowserContext() {
return default_browser_context_;
}
base::WeakPtr<HeadlessBrowserImpl> HeadlessBrowserImpl::GetWeakPtr() {
......
......@@ -51,6 +51,9 @@ class HeadlessBrowserImpl : public HeadlessBrowser {
const std::string& devtools_agent_host_id) override;
HeadlessBrowserContext* GetBrowserContextForId(
const std::string& id) override;
void SetDefaultBrowserContext(
HeadlessBrowserContext* browser_context) override;
HeadlessBrowserContext* GetDefaultBrowserContext() override;
void set_browser_main_parts(HeadlessBrowserMainParts* browser_main_parts);
HeadlessBrowserMainParts* browser_main_parts() const;
......@@ -82,6 +85,7 @@ class HeadlessBrowserImpl : public HeadlessBrowser {
std::unordered_map<std::string, std::unique_ptr<HeadlessBrowserContextImpl>>
browser_contexts_;
HeadlessBrowserContext* default_browser_context_; // Not owned.
base::WeakPtrFactory<HeadlessBrowserImpl> weak_ptr_factory_;
......
......@@ -20,9 +20,57 @@
namespace headless {
namespace {
const char kIdParam[] = "id";
const char kResultParam[] = "result";
const char kErrorParam[] = "error";
const char kErrorCodeParam[] = "code";
const char kErrorMessageParam[] = "message";
// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
enum Error {
kErrorInvalidParam = -32602,
kErrorServerError = -32000
};
std::unique_ptr<base::DictionaryValue> CreateSuccessResponse(
int command_id,
std::unique_ptr<base::Value> result) {
if (!result)
result.reset(new base::DictionaryValue());
std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
response->SetInteger(kIdParam, command_id);
response->Set(kResultParam, std::move(result));
return response;
}
std::unique_ptr<base::DictionaryValue> CreateErrorResponse(
int command_id,
int error_code,
const std::string& error_message) {
std::unique_ptr<base::DictionaryValue> error_object(
new base::DictionaryValue());
error_object->SetInteger(kErrorCodeParam, error_code);
error_object->SetString(kErrorMessageParam, error_message);
std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
response->Set(kErrorParam, std::move(error_object));
return response;
}
std::unique_ptr<base::DictionaryValue> CreateInvalidParamResponse(
int command_id,
const std::string& param) {
return CreateErrorResponse(
command_id, kErrorInvalidParam,
base::StringPrintf("Missing or invalid '%s' parameter", param.c_str()));
}
} // namespace
HeadlessDevToolsManagerDelegate::HeadlessDevToolsManagerDelegate(
base::WeakPtr<HeadlessBrowserImpl> browser)
: browser_(std::move(browser)), default_browser_context_(nullptr) {
: browser_(std::move(browser)) {
command_map_["Target.createTarget"] =
&HeadlessDevToolsManagerDelegate::CreateTarget;
command_map_["Target.closeTarget"] =
......@@ -55,19 +103,15 @@ base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand(
if (find_it == command_map_.end())
return nullptr;
CommandMemberFnPtr command_fn_ptr = find_it->second;
std::unique_ptr<base::Value> cmd_result(((this)->*command_fn_ptr)(params));
if (!cmd_result)
return nullptr;
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->SetInteger("id", id);
result->Set("result", std::move(cmd_result));
return result.release();
std::unique_ptr<base::DictionaryValue> cmd_result(
((this)->*command_fn_ptr)(id, params));
return cmd_result.release();
}
std::string HeadlessDevToolsManagerDelegate::GetDiscoveryPageHTML() {
return ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_HEADLESS_LIB_DEVTOOLS_DISCOVERY_PAGE).as_string();
return ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_HEADLESS_LIB_DEVTOOLS_DISCOVERY_PAGE)
.as_string();
}
std::string HeadlessDevToolsManagerDelegate::GetFrontendResource(
......@@ -75,7 +119,9 @@ std::string HeadlessDevToolsManagerDelegate::GetFrontendResource(
return content::DevToolsFrontendHost::GetFrontendResource(path).as_string();
}
std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CreateTarget(
std::unique_ptr<base::DictionaryValue>
HeadlessDevToolsManagerDelegate::CreateTarget(
int command_id,
const base::DictionaryValue* params) {
std::string url;
std::string browser_context_id;
......@@ -86,15 +132,20 @@ std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CreateTarget(
params->GetInteger("width", &width);
params->GetInteger("height", &height);
// TODO(alexclarke): Should we fail when user passes incorrect id?
HeadlessBrowserContext* context =
browser_->GetBrowserContextForId(browser_context_id);
if (!context) {
if (!default_browser_context_) {
default_browser_context_ =
browser_->CreateBrowserContextBuilder().Build();
if (!browser_context_id.empty()) {
context = browser_->GetBrowserContextForId(browser_context_id);
if (!context)
return CreateInvalidParamResponse(command_id, "browserContextId");
} else {
context = browser_->GetDefaultBrowserContext();
if (!context) {
return CreateErrorResponse(command_id, kErrorServerError,
"You specified no |browserContextId|, but "
"there is no default browser context set on "
"HeadlessBrowser");
}
context = default_browser_context_;
}
HeadlessWebContentsImpl* web_contents_impl =
......@@ -103,18 +154,21 @@ std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CreateTarget(
.SetWindowSize(gfx::Size(width, height))
.Build());
return target::CreateTargetResult::Builder()
.SetTargetId(web_contents_impl->GetDevToolsAgentHostId())
.Build()
->Serialize();
std::unique_ptr<base::Value> result(
target::CreateTargetResult::Builder()
.SetTargetId(web_contents_impl->GetDevToolsAgentHostId())
.Build()
->Serialize());
return CreateSuccessResponse(command_id, std::move(result));
}
std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CloseTarget(
std::unique_ptr<base::DictionaryValue>
HeadlessDevToolsManagerDelegate::CloseTarget(
int command_id,
const base::DictionaryValue* params) {
std::string target_id;
if (!params->GetString("targetId", &target_id)) {
return nullptr;
}
if (!params->GetString("targetId", &target_id))
return CreateInvalidParamResponse(command_id, "targetId");
HeadlessWebContents* web_contents =
browser_->GetWebContentsForDevToolsAgentHostId(target_id);
bool success = false;
......@@ -122,46 +176,51 @@ std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CloseTarget(
web_contents->Close();
success = true;
}
return target::CloseTargetResult::Builder()
.SetSuccess(success)
.Build()
->Serialize();
std::unique_ptr<base::Value> result(target::CloseTargetResult::Builder()
.SetSuccess(success)
.Build()
->Serialize());
return CreateSuccessResponse(command_id, std::move(result));
}
std::unique_ptr<base::Value>
std::unique_ptr<base::DictionaryValue>
HeadlessDevToolsManagerDelegate::CreateBrowserContext(
int command_id,
const base::DictionaryValue* params) {
HeadlessBrowserContext* browser_context =
browser_->CreateBrowserContextBuilder().Build();
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
return target::CreateBrowserContextResult::Builder()
.SetBrowserContextId(browser_context->Id())
.Build()
->Serialize();
std::unique_ptr<base::Value> result(
target::CreateBrowserContextResult::Builder()
.SetBrowserContextId(browser_context->Id())
.Build()
->Serialize());
return CreateSuccessResponse(command_id, std::move(result));
}
std::unique_ptr<base::Value>
std::unique_ptr<base::DictionaryValue>
HeadlessDevToolsManagerDelegate::DisposeBrowserContext(
int command_id,
const base::DictionaryValue* params) {
std::string browser_context_id;
if (!params->GetString("browserContextId", &browser_context_id)) {
return nullptr;
}
if (!params->GetString("browserContextId", &browser_context_id))
return CreateInvalidParamResponse(command_id, "browserContextId");
HeadlessBrowserContext* context =
browser_->GetBrowserContextForId(browser_context_id);
bool success = false;
if (context && context != default_browser_context_ &&
if (context && context != browser_->GetDefaultBrowserContext() &&
context->GetAllWebContents().empty()) {
success = true;
context->Close();
}
return target::DisposeBrowserContextResult::Builder()
.SetSuccess(success)
.Build()
->Serialize();
std::unique_ptr<base::Value> result(
target::DisposeBrowserContextResult::Builder()
.SetSuccess(success)
.Build()
->Serialize());
return CreateSuccessResponse(command_id, std::move(result));
}
} // namespace headless
......@@ -16,7 +16,6 @@
namespace headless {
class HeadlessBrowserImpl;
class HeadlessBrowserContext;
class HeadlessDevToolsManagerDelegate
: public content::DevToolsManagerDelegate {
......@@ -32,22 +31,26 @@ class HeadlessDevToolsManagerDelegate
std::string GetFrontendResource(const std::string& path) override;
private:
std::unique_ptr<base::Value> CreateTarget(
std::unique_ptr<base::DictionaryValue> CreateTarget(
int command_id,
const base::DictionaryValue* params);
std::unique_ptr<base::Value> CloseTarget(const base::DictionaryValue* params);
std::unique_ptr<base::Value> CreateBrowserContext(
std::unique_ptr<base::DictionaryValue> CloseTarget(
int command_id,
const base::DictionaryValue* params);
std::unique_ptr<base::Value> DisposeBrowserContext(
std::unique_ptr<base::DictionaryValue> CreateBrowserContext(
int command_id,
const base::DictionaryValue* params);
std::unique_ptr<base::DictionaryValue> DisposeBrowserContext(
int command_id,
const base::DictionaryValue* params);
base::WeakPtr<HeadlessBrowserImpl> browser_;
using CommandMemberFnPtr = std::unique_ptr<base::Value> (
HeadlessDevToolsManagerDelegate::*)(const base::DictionaryValue* params);
using CommandMemberFnPtr = std::unique_ptr<base::DictionaryValue> (
HeadlessDevToolsManagerDelegate::*)(int command_id,
const base::DictionaryValue* params);
std::map<std::string, CommandMemberFnPtr> command_map_;
HeadlessBrowserContext* default_browser_context_;
};
} // namespace headless
......
......@@ -56,6 +56,12 @@ class HEADLESS_EXPORT HeadlessBrowser {
virtual HeadlessBrowserContext* GetBrowserContextForId(
const std::string& id) = 0;
// Allows setting and getting the browser context that DevTools will create
// new targets in by default.
virtual void SetDefaultBrowserContext(
HeadlessBrowserContext* browser_context) = 0;
virtual HeadlessBrowserContext* GetDefaultBrowserContext() = 0;
// Returns a task runner for submitting work to the browser file thread.
virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserFileThread()
const = 0;
......
......@@ -184,7 +184,8 @@ void HeadlessBrowserTest::FinishAsynchronousTest() {
}
HeadlessAsyncDevTooledBrowserTest::HeadlessAsyncDevTooledBrowserTest()
: web_contents_(nullptr),
: browser_context_(nullptr),
web_contents_(nullptr),
devtools_client_(HeadlessDevToolsClient::Create()),
render_process_exited_(false) {}
......@@ -209,6 +210,7 @@ void HeadlessAsyncDevTooledBrowserTest::RenderProcessExited(
void HeadlessAsyncDevTooledBrowserTest::RunTest() {
browser_context_ = browser()->CreateBrowserContextBuilder().Build();
browser()->SetDefaultBrowserContext(browser_context_);
web_contents_ = browser_context_->CreateWebContentsBuilder().Build();
web_contents_->AddObserver(this);
......
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