diff options
Diffstat (limited to 'chromium/headless/lib/browser')
33 files changed, 462 insertions, 181 deletions
diff --git a/chromium/headless/lib/browser/devtools_api/domain_cc.template b/chromium/headless/lib/browser/devtools_api/domain_cc.template index de9425c33c8..ac16d62dd52 100644 --- a/chromium/headless/lib/browser/devtools_api/domain_cc.template +++ b/chromium/headless/lib/browser/devtools_api/domain_cc.template @@ -110,7 +110,7 @@ void Domain::Handle{{method_name}}Response(base::Callback<void(std::unique_ptr<{ } ErrorReporter errors; std::unique_ptr<{{method_name}}Result> result = {{method_name}}Result::Parse(response, &errors); - DCHECK(!errors.HasErrors()); + DCHECK(!errors.HasErrors()) << errors.ToString(); callback.Run(std::move(result)); } {% endfor %} @@ -121,7 +121,7 @@ void Domain::Handle{{method_name}}Response(base::Callback<void(std::unique_ptr<{ void Domain::Dispatch{{event.name | to_title_case}}Event(const base::Value& params) { ErrorReporter errors; std::unique_ptr<{{event.name | to_title_case}}Params> parsed_params({{event.name | to_title_case}}Params::Parse(params, &errors)); - DCHECK(!errors.HasErrors()); + DCHECK(!errors.HasErrors()) << errors.ToString(); for (ExperimentalObserver& observer : observers_) { observer.On{{event.name | to_title_case}}(*parsed_params); } diff --git a/chromium/headless/lib/browser/devtools_api/domain_type_conversions_h.template b/chromium/headless/lib/browser/devtools_api/domain_type_conversions_h.template index 15796eb756d..eb8297050ce 100644 --- a/chromium/headless/lib/browser/devtools_api/domain_type_conversions_h.template +++ b/chromium/headless/lib/browser/devtools_api/domain_type_conversions_h.template @@ -20,14 +20,13 @@ template <> struct FromValue<{{namespace}}::{{type.id}}> { static {{namespace}}::{{type.id}} Parse(const base::Value& value, ErrorReporter* errors) { {% set default = namespace + '::' + type.id + '::' + type.enum[0] | sanitize_literal | dash_to_camelcase | camelcase_to_hacker_style | upper %} - std::string string_value; - if (!value.GetAsString(&string_value)) { + if (!value.is_string()) { errors->AddError("string enum value expected"); {# Return an arbitrary enum member -- the caller will just ignore it. #} return {{default}}; } {% for literal in type.enum %} - if (string_value == "{{literal}}") + if (value.GetString() == "{{literal}}") return {{namespace}}::{{type.id}}::{{literal | sanitize_literal | dash_to_camelcase | camelcase_to_hacker_style | upper }}; {% endfor %} errors->AddError("invalid enum value"); diff --git a/chromium/headless/lib/browser/devtools_api/domain_types_cc.template b/chromium/headless/lib/browser/devtools_api/domain_types_cc.template index bd1c2773dd4..be125aeb835 100644 --- a/chromium/headless/lib/browser/devtools_api/domain_types_cc.template +++ b/chromium/headless/lib/browser/devtools_api/domain_types_cc.template @@ -31,8 +31,7 @@ namespace {{domain.domain | camelcase_to_hacker_style}} { std::unique_ptr<{{type.id}}> {{type.id}}::Parse(const base::Value& value, ErrorReporter* errors) { errors->Push(); errors->SetName("{{type.id}}"); - const base::DictionaryValue* object; - if (!value.GetAsDictionary(&object)) { + if (!value.is_dict()) { errors->AddError("object expected"); errors->Pop(); return nullptr; @@ -43,8 +42,8 @@ std::unique_ptr<{{type.id}}> {{type.id}}::Parse(const base::Value& value, ErrorR errors->SetName("{{type.id}}"); {% for property in type.properties %} {% set value_name = property.name | camelcase_to_hacker_style + "_value" %} - const base::Value* {{value_name}}; - if (object->Get("{{property.name}}", &{{value_name}})) { + const base::Value* {{value_name}} = value.FindKey("{{property.name}}"); + if ({{value_name}}) { errors->SetName("{{property.name}}"); {% if property.optional %} result->{{property.name | camelcase_to_hacker_style}}_ = internal::FromValue<{{resolve_type(property).raw_type}}>::Parse(*{{value_name}}, errors); diff --git a/chromium/headless/lib/browser/headless_browser_context_impl.cc b/chromium/headless/lib/browser/headless_browser_context_impl.cc index 781c0abe9e3..17849e27819 100644 --- a/chromium/headless/lib/browser/headless_browser_context_impl.cc +++ b/chromium/headless/lib/browser/headless_browser_context_impl.cc @@ -83,9 +83,9 @@ HeadlessBrowserContextImpl::HeadlessBrowserContextImpl( std::unique_ptr<HeadlessBrowserContextOptions> context_options) : browser_(browser), context_options_(std::move(context_options)), - resource_context_(new HeadlessResourceContext), + resource_context_(std::make_unique<HeadlessResourceContext>()), should_remove_headers_(true), - permission_manager_(new HeadlessPermissionManager()), + permission_manager_(std::make_unique<HeadlessPermissionManager>(this)), id_(base::GenerateGUID()) { InitWhileIOAllowed(); } @@ -201,7 +201,8 @@ void HeadlessBrowserContextImpl::Close() { void HeadlessBrowserContextImpl::InitWhileIOAllowed() { if (!context_options_->user_data_dir().empty()) { - path_ = context_options_->user_data_dir(); + path_ = + context_options_->user_data_dir().Append(FILE_PATH_LITERAL("Default")); } else { PathService::Get(base::DIR_EXE, &path_); } @@ -253,8 +254,6 @@ HeadlessBrowserContextImpl::GetSSLHostStateDelegate() { } content::PermissionManager* HeadlessBrowserContextImpl::GetPermissionManager() { - if (!permission_manager_.get()) - permission_manager_.reset(new HeadlessPermissionManager()); return permission_manager_.get(); } @@ -476,6 +475,12 @@ HeadlessBrowserContext::Builder::SetIncognitoMode(bool incognito_mode) { } HeadlessBrowserContext::Builder& +HeadlessBrowserContext::Builder::SetAllowCookies(bool allow_cookies) { + options_->allow_cookies_ = allow_cookies; + return *this; +} + +HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::AddTabSocketMojoBindings() { std::string js_bindings = ui::ResourceBundle::GetSharedInstance() @@ -514,13 +519,13 @@ HeadlessBrowserContext* HeadlessBrowserContext::Builder::Build() { return browser_->CreateBrowserContext(this); } -HeadlessBrowserContext::Builder::MojoBindings::MojoBindings() {} +HeadlessBrowserContext::Builder::MojoBindings::MojoBindings() = default; HeadlessBrowserContext::Builder::MojoBindings::MojoBindings( const std::string& mojom_name, const std::string& js_bindings) : mojom_name(mojom_name), js_bindings(js_bindings) {} -HeadlessBrowserContext::Builder::MojoBindings::~MojoBindings() {} +HeadlessBrowserContext::Builder::MojoBindings::~MojoBindings() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_browser_context_impl.h b/chromium/headless/lib/browser/headless_browser_context_impl.h index 580b8b0e15f..d84727c1a5d 100644 --- a/chromium/headless/lib/browser/headless_browser_context_impl.h +++ b/chromium/headless/lib/browser/headless_browser_context_impl.h @@ -13,7 +13,6 @@ #include "base/files/file_path.h" #include "base/unguessable_token.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" #include "headless/lib/browser/headless_browser_context_options.h" #include "headless/lib/browser/headless_network_conditions.h" @@ -120,7 +119,7 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext, bool canceled_by_devtools); void SetNetworkConditions(HeadlessNetworkConditions conditions); - HeadlessNetworkConditions GetNetworkConditions(); + HeadlessNetworkConditions GetNetworkConditions() override; private: HeadlessBrowserContextImpl( diff --git a/chromium/headless/lib/browser/headless_browser_context_options.cc b/chromium/headless/lib/browser/headless_browser_context_options.cc index 5898576830a..93e078083b7 100644 --- a/chromium/headless/lib/browser/headless_browser_context_options.cc +++ b/chromium/headless/lib/browser/headless_browser_context_options.cc @@ -74,6 +74,10 @@ bool HeadlessBrowserContextOptions::incognito_mode() const { browser_options_->incognito_mode); } +bool HeadlessBrowserContextOptions::allow_cookies() const { + return ReturnOverriddenValue(allow_cookies_, browser_options_->allow_cookies); +} + const base::Callback<void(WebPreferences*)>& HeadlessBrowserContextOptions::override_web_preferences_callback() const { return ReturnOverriddenValue( diff --git a/chromium/headless/lib/browser/headless_browser_context_options.h b/chromium/headless/lib/browser/headless_browser_context_options.h index 23a4f6251a7..00e1295f751 100644 --- a/chromium/headless/lib/browser/headless_browser_context_options.h +++ b/chromium/headless/lib/browser/headless_browser_context_options.h @@ -44,6 +44,8 @@ class HeadlessBrowserContextOptions { // Set HeadlessBrowser::Options::incognito_mode. bool incognito_mode() const; + bool allow_cookies() const; + // Custom network protocol handlers. These can be used to override URL // fetching for different network schemes. const ProtocolHandlerMap& protocol_handlers() const; @@ -70,6 +72,7 @@ class HeadlessBrowserContextOptions { base::Optional<gfx::Size> window_size_; base::Optional<base::FilePath> user_data_dir_; base::Optional<bool> incognito_mode_; + base::Optional<bool> allow_cookies_; base::Optional<base::Callback<void(WebPreferences*)>> override_web_preferences_callback_; diff --git a/chromium/headless/lib/browser/headless_browser_impl.cc b/chromium/headless/lib/browser/headless_browser_impl.cc index bbd231c1bb3..88bede99b53 100644 --- a/chromium/headless/lib/browser/headless_browser_impl.cc +++ b/chromium/headless/lib/browser/headless_browser_impl.cc @@ -77,7 +77,7 @@ HeadlessBrowserImpl::HeadlessBrowserImpl( agent_host_(nullptr), weak_ptr_factory_(this) {} -HeadlessBrowserImpl::~HeadlessBrowserImpl() {} +HeadlessBrowserImpl::~HeadlessBrowserImpl() = default; HeadlessBrowserContext::Builder HeadlessBrowserImpl::CreateBrowserContextBuilder() { @@ -103,7 +103,10 @@ void HeadlessBrowserImpl::Shutdown() { weak_ptr_factory_.InvalidateWeakPtrs(); // Destroy all browser contexts. - browser_contexts_.clear(); + { + base::AutoLock lock(browser_contexts_lock_); + browser_contexts_.clear(); + } BrowserMainThread()->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); @@ -112,6 +115,7 @@ void HeadlessBrowserImpl::Shutdown() { std::vector<HeadlessBrowserContext*> HeadlessBrowserImpl::GetAllBrowserContexts() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + base::AutoLock lock(browser_contexts_lock_); std::vector<HeadlessBrowserContext*> result; result.reserve(browser_contexts_.size()); @@ -162,6 +166,7 @@ HeadlessBrowserContext* HeadlessBrowserImpl::CreateBrowserContext( HeadlessBrowserContext* result = browser_context.get(); + base::AutoLock lock(browser_contexts_lock_); browser_contexts_[browser_context->Id()] = std::move(browser_context); return result; @@ -169,6 +174,7 @@ HeadlessBrowserContext* HeadlessBrowserImpl::CreateBrowserContext( void HeadlessBrowserImpl::DestroyBrowserContext( HeadlessBrowserContextImpl* browser_context) { + base::AutoLock lock(browser_contexts_lock_); auto it = browser_contexts_.find(browser_context->Id()); DCHECK(it != browser_contexts_.end()); browser_contexts_.erase(it); @@ -218,12 +224,26 @@ HeadlessWebContentsImpl* HeadlessBrowserImpl::GetWebContentsForWindowId( HeadlessBrowserContext* HeadlessBrowserImpl::GetBrowserContextForId( const std::string& id) { + base::AutoLock lock(browser_contexts_lock_); auto find_it = browser_contexts_.find(id); if (find_it == browser_contexts_.end()) return nullptr; return find_it->second.get(); } +LockedPtr<HeadlessBrowserContextImpl> +HeadlessBrowserImpl::GetBrowserContextForRenderFrame( + int render_process_id, + int render_frame_id) const { + MoveableAutoLock lock(browser_contexts_lock_); + for (const auto& pair : browser_contexts_) { + if (pair.second->GetDevToolsFrameToken(render_process_id, render_frame_id)) + return LockedPtr<HeadlessBrowserContextImpl>(std::move(lock), + pair.second.get()); + } + return LockedPtr<HeadlessBrowserContextImpl>(std::move(lock), nullptr); +} + HeadlessDevToolsTarget* HeadlessBrowserImpl::GetDevToolsTarget() { return agent_host_ ? this : nullptr; } diff --git a/chromium/headless/lib/browser/headless_browser_impl.h b/chromium/headless/lib/browser/headless_browser_impl.h index 591e50a0532..7f4ec64dc20 100644 --- a/chromium/headless/lib/browser/headless_browser_impl.h +++ b/chromium/headless/lib/browser/headless_browser_impl.h @@ -18,6 +18,7 @@ #include "headless/lib/browser/headless_devtools_manager_delegate.h" #include "headless/lib/browser/headless_web_contents_impl.h" #include "headless/public/headless_export.h" +#include "headless/public/util/moveable_auto_lock.h" namespace ui { class Compositor; @@ -78,6 +79,12 @@ class HEADLESS_EXPORT HeadlessBrowserImpl : public HeadlessBrowser, base::WeakPtr<HeadlessBrowserImpl> GetWeakPtr(); + // Returns the corresponding HeadlessBrowserContextImpl or null if one can't + // be found. Can be called on any thread. + LockedPtr<HeadlessBrowserContextImpl> GetBrowserContextForRenderFrame( + int render_process_id, + int render_frame_id) const; + // All the methods that begin with Platform need to be implemented by the // platform specific headless implementation. // Helper for one time initialization of application @@ -93,7 +100,8 @@ class HEADLESS_EXPORT HeadlessBrowserImpl : public HeadlessBrowser, HeadlessBrowser::Options options_; HeadlessBrowserMainParts* browser_main_parts_; // Not owned. - std::unordered_map<std::string, std::unique_ptr<HeadlessBrowserContextImpl>> + mutable base::Lock browser_contexts_lock_; // Protects |browser_contexts_| + base::flat_map<std::string, std::unique_ptr<HeadlessBrowserContextImpl>> browser_contexts_; HeadlessBrowserContext* default_browser_context_; // Not owned. diff --git a/chromium/headless/lib/browser/headless_browser_main_parts.cc b/chromium/headless/lib/browser/headless_browser_main_parts.cc index 64e9018f5e3..da66fb7f75d 100644 --- a/chromium/headless/lib/browser/headless_browser_main_parts.cc +++ b/chromium/headless/lib/browser/headless_browser_main_parts.cc @@ -18,7 +18,7 @@ HeadlessBrowserMainParts::HeadlessBrowserMainParts(HeadlessBrowserImpl* browser) : browser_(browser) , devtools_http_handler_started_(false) {} -HeadlessBrowserMainParts::~HeadlessBrowserMainParts() {} +HeadlessBrowserMainParts::~HeadlessBrowserMainParts() = default; void HeadlessBrowserMainParts::PreMainMessageLoopRun() { const base::CommandLine* command_line = diff --git a/chromium/headless/lib/browser/headless_clipboard.cc b/chromium/headless/lib/browser/headless_clipboard.cc index dcadd4c36c1..9b9fd069746 100644 --- a/chromium/headless/lib/browser/headless_clipboard.cc +++ b/chromium/headless/lib/browser/headless_clipboard.cc @@ -13,7 +13,7 @@ namespace headless { HeadlessClipboard::HeadlessClipboard() : default_store_type_(ui::CLIPBOARD_TYPE_COPY_PASTE) {} -HeadlessClipboard::~HeadlessClipboard() {} +HeadlessClipboard::~HeadlessClipboard() = default; void HeadlessClipboard::OnPreShutdown() {} @@ -182,7 +182,7 @@ HeadlessClipboard::DataStore::DataStore() : sequence_number(0) {} HeadlessClipboard::DataStore::DataStore(const DataStore& other) = default; -HeadlessClipboard::DataStore::~DataStore() {} +HeadlessClipboard::DataStore::~DataStore() = default; void HeadlessClipboard::DataStore::Clear() { data.clear(); diff --git a/chromium/headless/lib/browser/headless_content_browser_client.cc b/chromium/headless/lib/browser/headless_content_browser_client.cc index d96b9886839..98434626717 100644 --- a/chromium/headless/lib/browser/headless_content_browser_client.cc +++ b/chromium/headless/lib/browser/headless_content_browser_client.cc @@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/path_service.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" @@ -114,9 +115,11 @@ int GetCrashSignalFD(const base::CommandLine& command_line, HeadlessContentBrowserClient::HeadlessContentBrowserClient( HeadlessBrowserImpl* browser) - : browser_(browser) {} + : browser_(browser), + append_command_line_flags_callback_( + browser_->options()->append_command_line_flags_callback) {} -HeadlessContentBrowserClient::~HeadlessContentBrowserClient() {} +HeadlessContentBrowserClient::~HeadlessContentBrowserClient() = default; content::BrowserMainParts* HeadlessContentBrowserClient::CreateBrowserMainParts( const content::MainFunctionParams&) { @@ -230,6 +233,9 @@ void HeadlessContentBrowserClient::GetAdditionalMappedFilesForChildProcess( void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches( base::CommandLine* command_line, int child_process_id) { + // NOTE: We may be called on the UI or IO thread. If called on the IO thread, + // |browser_| may have already been destroyed. + command_line->AppendSwitch(::switches::kHeadless); const base::CommandLine& old_command_line( *base::CommandLine::ForCurrentProcess()); @@ -245,8 +251,10 @@ void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches( #endif // defined(HEADLESS_USE_BREAKPAD) // If we're spawning a renderer, then override the language switch. - if (command_line->GetSwitchValueASCII(::switches::kProcessType) == - ::switches::kRendererProcess) { + std::string process_type = + command_line->GetSwitchValueASCII(::switches::kProcessType); + if (process_type == ::switches::kRendererProcess) { + // Renderer processes are initialized on the UI thread, so this is safe. content::RenderProcessHost* render_process_host = content::RenderProcessHost::FromID(child_process_id); if (render_process_host) { @@ -262,6 +270,22 @@ void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches( } } } + + if (append_command_line_flags_callback_) { + HeadlessBrowserContextImpl* headless_browser_context_impl = nullptr; + if (process_type == ::switches::kRendererProcess) { + // Renderer processes are initialized on the UI thread, so this is safe. + content::RenderProcessHost* render_process_host = + content::RenderProcessHost::FromID(child_process_id); + if (render_process_host) { + headless_browser_context_impl = HeadlessBrowserContextImpl::From( + render_process_host->GetBrowserContext()); + } + } + append_command_line_flags_callback_.Run(command_line, + headless_browser_context_impl, + process_type, child_process_id); + } } void HeadlessContentBrowserClient::AllowCertificateError( @@ -290,8 +314,7 @@ void HeadlessContentBrowserClient::AllowCertificateError( void HeadlessContentBrowserClient::ResourceDispatcherHostCreated() { resource_dispatcher_host_delegate_.reset( - new HeadlessResourceDispatcherHostDelegate( - browser_->options()->enable_resource_scheduler)); + new HeadlessResourceDispatcherHostDelegate); content::ResourceDispatcherHost::Get()->SetDelegate( resource_dispatcher_host_delegate_.get()); } @@ -300,4 +323,37 @@ net::NetLog* HeadlessContentBrowserClient::GetNetLog() { return browser_->browser_main_parts()->net_log(); } +bool HeadlessContentBrowserClient::AllowGetCookie( + const GURL& url, + const GURL& first_party, + const net::CookieList& cookie_list, + content::ResourceContext* context, + int render_process_id, + int render_frame_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + LockedPtr<HeadlessBrowserContextImpl> browser_context = + browser_->GetBrowserContextForRenderFrame(render_process_id, + render_frame_id); + if (!browser_context) + return false; + return browser_context->options()->allow_cookies(); +} + +bool HeadlessContentBrowserClient::AllowSetCookie( + const GURL& url, + const GURL& first_party, + const net::CanonicalCookie& cookie, + content::ResourceContext* context, + int render_process_id, + int render_frame_id, + const net::CookieOptions& options) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + LockedPtr<HeadlessBrowserContextImpl> browser_context = + browser_->GetBrowserContextForRenderFrame(render_process_id, + render_frame_id); + if (!browser_context) + return false; + return browser_context->options()->allow_cookies(); +} + } // namespace headless diff --git a/chromium/headless/lib/browser/headless_content_browser_client.h b/chromium/headless/lib/browser/headless_content_browser_client.h index 929bc9f346b..6a7daae9ad8 100644 --- a/chromium/headless/lib/browser/headless_content_browser_client.h +++ b/chromium/headless/lib/browser/headless_content_browser_client.h @@ -7,6 +7,7 @@ #include "content/public/browser/content_browser_client.h" #include "headless/lib/browser/headless_resource_dispatcher_host_delegate.h" +#include "headless/public/headless_browser.h" namespace headless { @@ -55,6 +56,21 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient { net::NetLog* GetNetLog() override; + bool AllowGetCookie(const GURL& url, + const GURL& first_party, + const net::CookieList& cookie_list, + content::ResourceContext* context, + int render_process_id, + int render_frame_id) override; + + bool AllowSetCookie(const GURL& url, + const GURL& first_party, + const net::CanonicalCookie& cookie, + content::ResourceContext* context, + int render_process_id, + int render_frame_id, + const net::CookieOptions& options) override; + private: std::unique_ptr<base::Value> GetBrowserServiceManifestOverlay(); std::unique_ptr<base::Value> GetRendererServiceManifestOverlay(); @@ -62,6 +78,10 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient { HeadlessBrowserImpl* browser_; // Not owned. + // We store the callback here because we may call it from the I/O thread. + HeadlessBrowser::Options::AppendCommandLineFlagsCallback + append_command_line_flags_callback_; + std::unique_ptr<HeadlessResourceDispatcherHostDelegate> resource_dispatcher_host_delegate_; diff --git a/chromium/headless/lib/browser/headless_devtools_client_impl.cc b/chromium/headless/lib/browser/headless_devtools_client_impl.cc index 8cf1e5e5274..9763565c59b 100644 --- a/chromium/headless/lib/browser/headless_devtools_client_impl.cc +++ b/chromium/headless/lib/browser/headless_devtools_client_impl.cc @@ -61,6 +61,7 @@ HeadlessDevToolsClientImpl::HeadlessDevToolsClientImpl() memory_domain_(this), network_domain_(this), page_domain_(this), + performance_domain_(this), profiler_domain_(this), runtime_domain_(this), security_domain_(this), @@ -71,7 +72,7 @@ HeadlessDevToolsClientImpl::HeadlessDevToolsClientImpl() content::BrowserThread::UI)), weak_ptr_factory_(this) {} -HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() {} +HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() = default; bool HeadlessDevToolsClientImpl::AttachToHost( content::DevToolsAgentHost* agent_host) { @@ -115,14 +116,13 @@ void HeadlessDevToolsClientImpl::SendRawDevToolsMessage( #ifndef NDEBUG std::unique_ptr<base::Value> message = base::JSONReader::Read(json_message, base::JSON_PARSE_RFC); - const base::DictionaryValue* message_dict; - int id = 0; - if (!message || !message->GetAsDictionary(&message_dict) || - !message_dict->GetInteger("id", &id)) { - NOTREACHED() << "Badly formed message"; + const base::Value* id_value = message->FindKey("id"); + if (!id_value) { + NOTREACHED() << "Badly formed message " << json_message; return; } - DCHECK_EQ((id % 2), 1) << "Raw devtools messages must have an odd ID."; + DCHECK_EQ((id_value->GetInt() % 2), 1) + << "Raw devtools messages must have an odd ID."; #endif agent_host_->DispatchProtocolMessage(this, json_message); @@ -162,10 +162,10 @@ void HeadlessDevToolsClientImpl::DispatchProtocolMessage( bool HeadlessDevToolsClientImpl::DispatchMessageReply( const base::DictionaryValue& message_dict) { - int id = 0; - if (!message_dict.GetInteger("id", &id)) + const base::Value* id_value = message_dict.FindKey("id"); + if (!id_value) return false; - auto it = pending_messages_.find(id); + auto it = pending_messages_.find(id_value->GetInt()); if (it == pending_messages_.end()) { NOTREACHED() << "Unexpected reply"; return false; @@ -193,9 +193,10 @@ bool HeadlessDevToolsClientImpl::DispatchMessageReply( bool HeadlessDevToolsClientImpl::DispatchEvent( std::unique_ptr<base::Value> owning_message, const base::DictionaryValue& message_dict) { - std::string method; - if (!message_dict.GetString("method", &method)) + const base::Value* method_value = message_dict.FindKey("method"); + if (!method_value) return false; + const std::string& method = method_value->GetString(); if (method == "Inspector.targetCrashed") renderer_crashed_ = true; EventHandlerMap::const_iterator it = event_handlers_.find(method); @@ -228,8 +229,7 @@ void HeadlessDevToolsClientImpl::DispatchEventTask( } void HeadlessDevToolsClientImpl::AgentHostClosed( - content::DevToolsAgentHost* agent_host, - bool replaced_with_another_client) { + content::DevToolsAgentHost* agent_host) { DCHECK_EQ(agent_host_, agent_host); agent_host = nullptr; pending_messages_.clear(); @@ -340,6 +340,10 @@ page::Domain* HeadlessDevToolsClientImpl::GetPage() { return &page_domain_; } +performance::Domain* HeadlessDevToolsClientImpl::GetPerformance() { + return &performance_domain_; +} + profiler::Domain* HeadlessDevToolsClientImpl::GetProfiler() { return &profiler_domain_; } @@ -412,7 +416,7 @@ void HeadlessDevToolsClientImpl::RegisterEventHandler( event_handlers_[method] = callback; } -HeadlessDevToolsClientImpl::Callback::Callback() {} +HeadlessDevToolsClientImpl::Callback::Callback() = default; HeadlessDevToolsClientImpl::Callback::Callback(Callback&& other) = default; @@ -423,7 +427,7 @@ HeadlessDevToolsClientImpl::Callback::Callback( base::Callback<void(const base::Value&)> callback) : callback_with_result(callback) {} -HeadlessDevToolsClientImpl::Callback::~Callback() {} +HeadlessDevToolsClientImpl::Callback::~Callback() = default; HeadlessDevToolsClientImpl::Callback& HeadlessDevToolsClientImpl::Callback:: operator=(Callback&& other) = default; diff --git a/chromium/headless/lib/browser/headless_devtools_manager_delegate.cc b/chromium/headless/lib/browser/headless_devtools_manager_delegate.cc index 498aafcf51f..553d7159b51 100644 --- a/chromium/headless/lib/browser/headless_devtools_manager_delegate.cc +++ b/chromium/headless/lib/browser/headless_devtools_manager_delegate.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/base64.h" +#include "base/command_line.h" #include "base/json/json_writer.h" #include "build/build_config.h" #include "cc/base/switches.h" @@ -20,7 +21,6 @@ #include "headless/grit/headless_lib_resources.h" #include "headless/lib/browser/headless_browser_context_impl.h" #include "headless/lib/browser/headless_browser_impl.h" -#include "headless/lib/browser/headless_network_conditions.h" #include "headless/lib/browser/headless_web_contents_impl.h" #include "headless/public/devtools/domains/target.h" #include "printing/units.h" @@ -155,9 +155,11 @@ void OnBeginFrameFinished( ImageEncoding encoding, int quality, bool has_damage, + bool main_frame_content_updated, std::unique_ptr<SkBitmap> bitmap) { auto result = base::MakeUnique<base::DictionaryValue>(); result->SetBoolean("hasDamage", has_damage); + result->SetBoolean("mainFrameContentUpdated", main_frame_content_updated); if (bitmap && !bitmap->drawsNothing()) { result->SetString("screenshotData", @@ -182,21 +184,42 @@ std::unique_ptr<base::DictionaryValue> ParsePrintSettings( HeadlessPrintSettings* settings) { // We can safely ignore the return values of the following Get methods since // the defaults are already set in |settings|. - params->GetBoolean("landscape", &settings->landscape); - params->GetBoolean("displayHeaderFooter", &settings->display_header_footer); - params->GetBoolean("printBackground", &settings->should_print_backgrounds); - params->GetDouble("scale", &settings->scale); + if (const base::Value* landscape_value = params->FindKey("landscape")) + settings->landscape = landscape_value->GetBool(); + + if (const base::Value* display_header_footer_value = + params->FindKey("displayHeaderFooter")) { + settings->display_header_footer = display_header_footer_value->GetBool(); + } + + if (const base::Value* should_print_backgrounds_value = + params->FindKey("printBackground")) { + settings->should_print_backgrounds = + should_print_backgrounds_value->GetBool(); + } + if (const base::Value* scale_value = params->FindKey("scale")) + settings->scale = scale_value->GetDouble(); if (settings->scale > kScaleMaxVal / 100 || settings->scale < kScaleMinVal / 100) return CreateInvalidParamResponse(command_id, "scale"); - params->GetString("pageRanges", &settings->page_ranges); - params->GetBoolean("ignoreInvalidPageRanges", - &settings->ignore_invalid_page_ranges); + if (const base::Value* page_ranges_value = params->FindKey("pageRanges")) + settings->page_ranges = page_ranges_value->GetString(); + + if (const base::Value* ignore_invalid_page_ranges_value = + params->FindKey("ignoreInvalidPageRanges")) { + settings->ignore_invalid_page_ranges = + ignore_invalid_page_ranges_value->GetBool(); + } double paper_width_in_inch = printing::kLetterWidthInch; + + if (const base::Value* paper_width_value = params->FindKey("paperWidth")) + paper_width_in_inch = paper_width_value->GetDouble(); + double paper_height_in_inch = printing::kLetterHeightInch; - params->GetDouble("paperWidth", &paper_width_in_inch); - params->GetDouble("paperHeight", &paper_height_in_inch); + + if (const base::Value* paper_height_value = params->FindKey("paperHeight")) + paper_height_in_inch = paper_height_value->GetDouble(); if (paper_width_in_inch <= 0) return CreateInvalidParamResponse(command_id, "paperWidth"); if (paper_height_in_inch <= 0) @@ -211,10 +234,19 @@ std::unique_ptr<base::DictionaryValue> ParsePrintSettings( double margin_bottom_in_inch = default_margin_in_inch; double margin_left_in_inch = default_margin_in_inch; double margin_right_in_inch = default_margin_in_inch; - params->GetDouble("marginTop", &margin_top_in_inch); - params->GetDouble("marginBottom", &margin_bottom_in_inch); - params->GetDouble("marginLeft", &margin_left_in_inch); - params->GetDouble("marginRight", &margin_right_in_inch); + + if (const base::Value* margin_top_value = params->FindKey("marginTop")) + margin_top_in_inch = margin_top_value->GetDouble(); + + if (const base::Value* margin_bottom_value = params->FindKey("marginBottom")) + margin_bottom_in_inch = margin_bottom_value->GetDouble(); + + if (const base::Value* margin_left_value = params->FindKey("marginLeft")) + margin_left_in_inch = margin_left_value->GetDouble(); + + if (const base::Value* margin_right_value = params->FindKey("marginRight")) + margin_right_in_inch = margin_right_value->GetDouble(); + if (margin_top_in_inch < 0) return CreateInvalidParamResponse(command_id, "marginTop"); if (margin_bottom_in_inch < 0) @@ -281,7 +313,7 @@ HeadlessDevToolsManagerDelegate::HeadlessDevToolsManagerDelegate( &HeadlessDevToolsManagerDelegate::BeginFrame, base::Unretained(this)); } -HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {} +HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() = default; bool HeadlessDevToolsManagerDelegate::HandleCommand( content::DevToolsAgentHost* agent_host, @@ -292,21 +324,22 @@ bool HeadlessDevToolsManagerDelegate::HandleCommand( if (!browser_) return false; - int id; - std::string method; - if (!command->GetInteger("id", &id) || !command->GetString("method", &method)) + const base::Value* id_value = command->FindKey("id"); + const base::Value* method_value = command->FindKey("method"); + if (!id_value || !method_value) return false; const base::DictionaryValue* params = nullptr; command->GetDictionary("params", ¶ms); + const std::string& method = method_value->GetString(); auto find_it = command_map_.find(method); if (find_it == command_map_.end()) { // Check for any commands that are actioned then passed on to devtools to // handle. find_it = unhandled_command_map_.find(method); if (find_it != unhandled_command_map_.end()) - find_it->second.Run(agent_host, session_id, id, params); + find_it->second.Run(agent_host, session_id, id_value->GetInt(), params); return false; } @@ -315,7 +348,8 @@ bool HeadlessDevToolsManagerDelegate::HandleCommand( agent_host->GetType() != content::DevToolsAgentHost::kTypeBrowser) return false; - auto cmd_result = find_it->second.Run(agent_host, session_id, id, params); + auto cmd_result = + find_it->second.Run(agent_host, session_id, id_value->GetInt(), params); if (!cmd_result) return false; agent_host->SendProtocolMessageToClient(session_id, @@ -333,18 +367,19 @@ bool HeadlessDevToolsManagerDelegate::HandleAsyncCommand( if (!browser_) return false; - int id; - std::string method; - if (!command->GetInteger("id", &id) || !command->GetString("method", &method)) + const base::Value* id_value = command->FindKey("id"); + const base::Value* method_value = command->FindKey("method"); + if (!id_value || !method_value) return false; - auto find_it = async_command_map_.find(method); + auto find_it = async_command_map_.find(method_value->GetString()); if (find_it == async_command_map_.end()) return false; const base::DictionaryValue* params = nullptr; command->GetDictionary("params", ¶ms); - find_it->second.Run(agent_host, session_id, id, params, callback); + find_it->second.Run(agent_host, session_id, id_value->GetInt(), params, + callback); return true; } @@ -432,16 +467,32 @@ HeadlessDevToolsManagerDelegate::CreateTarget( int command_id, const base::DictionaryValue* params) { std::string url; + + if (const base::Value* url_value = params->FindKey("url")) { + url = url_value->GetString(); + } else { + return CreateInvalidParamResponse(command_id, "url"); + } + std::string browser_context_id; + if (const base::Value* browser_context_id_value = + params->FindKey("browserContextId")) { + browser_context_id = browser_context_id_value->GetString(); + } + int width = browser_->options()->window_size.width(); + if (const base::Value* width_value = params->FindKey("width")) + width = width_value->GetInt(); + int height = browser_->options()->window_size.height(); - if (!params || !params->GetString("url", &url)) - return CreateInvalidParamResponse(command_id, "url"); + if (const base::Value* height_value = params->FindKey("height")) + height = height_value->GetInt(); + bool enable_begin_frame_control = false; - params->GetString("browserContextId", &browser_context_id); - params->GetInteger("width", &width); - params->GetInteger("height", &height); - params->GetBoolean("enableBeginFrameControl", &enable_begin_frame_control); + if (const base::Value* enable_begin_frame_control_value = + params->FindKey("enableBeginFrameControl")) { + enable_begin_frame_control = enable_begin_frame_control_value->GetBool(); + } #if defined(OS_MACOSX) if (enable_begin_frame_control) { @@ -488,11 +539,12 @@ HeadlessDevToolsManagerDelegate::CloseTarget( int session_id, int command_id, const base::DictionaryValue* params) { - std::string target_id; - if (!params || !params->GetString("targetId", &target_id)) + const base::Value* target_id_value = params->FindKey("targetId"); + if (!target_id_value) return CreateInvalidParamResponse(command_id, "targetId"); HeadlessWebContents* web_contents = - browser_->GetWebContentsForDevToolsAgentHostId(target_id); + browser_->GetWebContentsForDevToolsAgentHostId( + target_id_value->GetString()); bool success = false; if (web_contents) { web_contents->Close(); @@ -528,11 +580,13 @@ HeadlessDevToolsManagerDelegate::DisposeBrowserContext( int session_id, int command_id, const base::DictionaryValue* params) { - std::string browser_context_id; - if (!params || !params->GetString("browserContextId", &browser_context_id)) + const base::Value* browser_context_id_value = + params->FindKey("browserContextId"); + if (!browser_context_id_value) return CreateInvalidParamResponse(command_id, "browserContextId"); + HeadlessBrowserContext* context = - browser_->GetBrowserContextForId(browser_context_id); + browser_->GetBrowserContextForId(browser_context_id_value->GetString()); bool success = false; if (context && context != browser_->GetDefaultBrowserContext() && @@ -555,12 +609,13 @@ HeadlessDevToolsManagerDelegate::GetWindowForTarget( int session_id, int command_id, const base::DictionaryValue* params) { - std::string target_id; - if (!params->GetString("targetId", &target_id)) + const base::Value* target_id_value = params->FindKey("targetId"); + if (!target_id_value) return CreateInvalidParamResponse(command_id, "targetId"); HeadlessWebContentsImpl* web_contents = HeadlessWebContentsImpl::From( - browser_->GetWebContentsForDevToolsAgentHostId(target_id)); + browser_->GetWebContentsForDevToolsAgentHostId( + target_id_value->GetString())); if (!web_contents) { return CreateErrorResponse(command_id, kErrorServerError, "No web contents for the given target id"); @@ -590,11 +645,11 @@ HeadlessDevToolsManagerDelegate::GetWindowBounds( int session_id, int command_id, const base::DictionaryValue* params) { - int window_id; - if (!params->GetInteger("windowId", &window_id)) + HeadlessWebContentsImpl* web_contents; + const base::Value* window_id_value = params->FindKey("windowId"); + if (!window_id_value || !window_id_value->is_int()) return CreateInvalidParamResponse(command_id, "windowId"); - HeadlessWebContentsImpl* web_contents = - browser_->GetWebContentsForWindowId(window_id); + web_contents = browser_->GetWebContentsForWindowId(window_id_value->GetInt()); if (!web_contents) { return CreateErrorResponse(command_id, kErrorServerError, "Browser window not found"); @@ -611,48 +666,56 @@ HeadlessDevToolsManagerDelegate::SetWindowBounds( int session_id, int command_id, const base::DictionaryValue* params) { - int window_id; - if (!params->GetInteger("windowId", &window_id)) + HeadlessWebContentsImpl* web_contents; + const base::Value* window_id_value = params->FindKey("windowId"); + if (!window_id_value || !window_id_value->is_int()) return CreateInvalidParamResponse(command_id, "windowId"); - HeadlessWebContentsImpl* web_contents = - browser_->GetWebContentsForWindowId(window_id); + web_contents = browser_->GetWebContentsForWindowId(window_id_value->GetInt()); + if (!web_contents) { return CreateErrorResponse(command_id, kErrorServerError, "Browser window not found"); } - const base::Value* value = nullptr; - const base::DictionaryValue* bounds_dict = nullptr; - if (!params->Get("bounds", &value) || !value->GetAsDictionary(&bounds_dict)) + const base::Value* bounds_value = params->FindKey("bounds"); + if (!bounds_value || !bounds_value->is_dict()) return CreateInvalidParamResponse(command_id, "bounds"); std::string window_state; - if (!bounds_dict->GetString("windowState", &window_state)) { + if (const base::Value* window_state_value = + bounds_value->FindKey("windowState")) { + window_state = window_state_value->GetString(); + if (window_state != "normal" && window_state != "minimized" && + window_state != "maximized" && window_state != "fullscreen") { + return CreateInvalidParamResponse(command_id, "windowState"); + } + } else { window_state = "normal"; - } else if (window_state != "normal" && window_state != "minimized" && - window_state != "maximized" && window_state != "fullscreen") { - return CreateInvalidParamResponse(command_id, "windowState"); } // Compute updated bounds when window state is normal. bool set_bounds = false; gfx::Rect bounds = web_contents->web_contents()->GetContainerBounds(); - int left, top, width, height; - if (bounds_dict->GetInteger("left", &left)) { - bounds.set_x(left); + if (const base::Value* left_value = bounds_value->FindKey("left")) { + bounds.set_x(left_value->GetInt()); set_bounds = true; } - if (bounds_dict->GetInteger("top", &top)) { - bounds.set_y(top); + + if (const base::Value* top_value = bounds_value->FindKey("top")) { + bounds.set_y(top_value->GetInt()); set_bounds = true; } - if (bounds_dict->GetInteger("width", &width)) { + + if (const base::Value* width_value = bounds_value->FindKey("width")) { + int width = width_value->GetInt(); if (width < 0) return CreateInvalidParamResponse(command_id, "width"); bounds.set_width(width); set_bounds = true; } - if (bounds_dict->GetInteger("height", &height)) { + + if (const base::Value* height_value = bounds_value->FindKey("height")) { + int height = height_value->GetInt(); if (height < 0) return CreateInvalidParamResponse(command_id, "height"); bounds.set_height(height); @@ -685,19 +748,26 @@ HeadlessDevToolsManagerDelegate::EmulateNetworkConditions( int command_id, const base::DictionaryValue* params) { // Associate NetworkConditions to context - HeadlessBrowserContextImpl* browser_context = - static_cast<HeadlessBrowserContextImpl*>( - browser_->GetDefaultBrowserContext()); - bool offline = false; - double latency = 0, download_throughput = 0, upload_throughput = 0; - params->GetBoolean("offline", &offline); - params->GetDouble("latency", &latency); - params->GetDouble("downloadThroughput", &download_throughput); - params->GetDouble("uploadThroughput", &upload_throughput); + std::vector<HeadlessBrowserContext*> browser_contexts = + browser_->GetAllBrowserContexts(); + if (browser_contexts.empty()) + return CreateSuccessResponse(command_id, nullptr); + const base::Value* offline_value = params->FindKey("offline"); + const base::Value* latency_value = params->FindKey("latency"); + const base::Value* download_throughput_value = + params->FindKey("downloadThroughput"); + const base::Value* upload_throughput_value = + params->FindKey("uploadThroughput"); HeadlessNetworkConditions conditions(HeadlessNetworkConditions( - offline, std::max(latency, 0.0), std::max(download_throughput, 0.0), - std::max(upload_throughput, 0.0))); - browser_context->SetNetworkConditions(conditions); + offline_value ? offline_value->GetBool() : false, + latency_value ? std::max(latency_value->GetDouble(), 0.0) : 0, + download_throughput_value + ? std::max(download_throughput_value->GetDouble(), 0.0) + : 0, + upload_throughput_value + ? std::max(upload_throughput_value->GetDouble(), 0.0) + : 0)); + SetNetworkConditions(browser_contexts, conditions); return CreateSuccessResponse(command_id, nullptr); } @@ -707,13 +777,26 @@ HeadlessDevToolsManagerDelegate::NetworkDisable( int session_id, int command_id, const base::DictionaryValue* params) { - HeadlessBrowserContextImpl* browser_context = - static_cast<HeadlessBrowserContextImpl*>( - browser_->GetDefaultBrowserContext()); - browser_context->SetNetworkConditions(HeadlessNetworkConditions()); + std::vector<HeadlessBrowserContext*> browser_contexts = + browser_->GetAllBrowserContexts(); + if (browser_contexts.empty()) + return CreateSuccessResponse(command_id, nullptr); + SetNetworkConditions(browser_contexts, HeadlessNetworkConditions()); return CreateSuccessResponse(command_id, nullptr); } +void HeadlessDevToolsManagerDelegate::SetNetworkConditions( + std::vector<HeadlessBrowserContext*> browser_contexts, + HeadlessNetworkConditions conditions) { + for (std::vector<HeadlessBrowserContext*>::iterator it = + browser_contexts.begin(); + it != browser_contexts.end(); ++it) { + HeadlessBrowserContextImpl* context = + static_cast<HeadlessBrowserContextImpl*>(*it); + context->SetNetworkConditions(conditions); + } +} + std::unique_ptr<base::DictionaryValue> HeadlessDevToolsManagerDelegate::EnableHeadlessExperimental( content::DevToolsAgentHost* agent_host, @@ -774,24 +857,21 @@ void HeadlessDevToolsManagerDelegate::BeginFrame( return; } - double frame_time_double = 0; - double deadline_double = 0; - double interval_double = 0; - base::Time frame_time; base::TimeTicks frame_timeticks; base::TimeTicks deadline; base::TimeDelta interval; - if (params->GetDouble("frameTime", &frame_time_double)) { - frame_time = base::Time::FromDoubleT(frame_time_double); + if (const base::Value* frame_time_value = params->FindKey("frameTime")) { + frame_time = base::Time::FromJsTime(frame_time_value->GetDouble()); base::TimeDelta delta = frame_time - base::Time::UnixEpoch(); frame_timeticks = base::TimeTicks::UnixEpoch() + delta; } else { frame_timeticks = base::TimeTicks::Now(); } - if (params->GetDouble("interval", &interval_double)) { + if (const base::Value* interval_value = params->FindKey("interval")) { + double interval_double = interval_value->GetDouble(); if (interval_double <= 0) { callback.Run(CreateErrorResponse(command_id, kErrorInvalidParam, "interval has to be greater than 0")); @@ -802,9 +882,9 @@ void HeadlessDevToolsManagerDelegate::BeginFrame( interval = viz::BeginFrameArgs::DefaultInterval(); } - if (params->GetDouble("deadline", &deadline_double)) { + if (const base::Value* deadline_value = params->FindKey("deadline")) { base::TimeDelta delta = - base::Time::FromDoubleT(deadline_double) - frame_time; + base::Time::FromDoubleT(deadline_value->GetDouble()) - frame_time; if (delta <= base::TimeDelta()) { callback.Run(CreateErrorResponse(command_id, kErrorInvalidParam, "deadline has to be after frameTime")); @@ -829,8 +909,8 @@ void HeadlessDevToolsManagerDelegate::BeginFrame( capture_screenshot = true; - std::string format; - if (screenshot_dict->GetString("format", &format)) { + if (const base::Value* format_value = screenshot_dict->FindKey("format")) { + const std::string& format = format_value->GetString(); if (format == kPng) { encoding = ImageEncoding::kPng; } else if (format == kJpeg) { @@ -842,12 +922,14 @@ void HeadlessDevToolsManagerDelegate::BeginFrame( } } - if (screenshot_dict->GetInteger("quality", &quality) && - (quality < 0 || quality > 100)) { - callback.Run( - CreateErrorResponse(command_id, kErrorInvalidParam, - "screenshot.quality has to be in range 0..100")); - return; + if (const base::Value* quality_value = screenshot_dict->FindKey("quality")) { + quality = quality_value->GetInt(); + if (quality < 0 || quality > 100) { + callback.Run(CreateErrorResponse( + command_id, kErrorInvalidParam, + "screenshot.quality has to be in range 0..100")); + return; + } } } diff --git a/chromium/headless/lib/browser/headless_devtools_manager_delegate.h b/chromium/headless/lib/browser/headless_devtools_manager_delegate.h index 9ad18ba1a07..b8fb8a81110 100644 --- a/chromium/headless/lib/browser/headless_devtools_manager_delegate.h +++ b/chromium/headless/lib/browser/headless_devtools_manager_delegate.h @@ -13,6 +13,8 @@ #include "base/memory/weak_ptr.h" #include "base/values.h" #include "content/public/browser/devtools_manager_delegate.h" +#include "headless/lib/browser/headless_network_conditions.h" +#include "headless/public/headless_browser_context.h" #include "printing/features/features.h" #if BUILDFLAG(ENABLE_BASIC_PRINTING) @@ -116,6 +118,10 @@ class HeadlessDevToolsManagerDelegate int command_id, const base::DictionaryValue* params); + void SetNetworkConditions( + std::vector<HeadlessBrowserContext*> browser_contexts, + HeadlessNetworkConditions conditions); + void PrintToPDF(content::DevToolsAgentHost* agent_host, int session_id, int command_id, diff --git a/chromium/headless/lib/browser/headless_focus_client.cc b/chromium/headless/lib/browser/headless_focus_client.cc index 9a4e806e86c..c406c703861 100644 --- a/chromium/headless/lib/browser/headless_focus_client.cc +++ b/chromium/headless/lib/browser/headless_focus_client.cc @@ -12,7 +12,7 @@ namespace headless { HeadlessFocusClient::HeadlessFocusClient() : focused_window_(NULL), observer_manager_(this) {} -HeadlessFocusClient::~HeadlessFocusClient() {} +HeadlessFocusClient::~HeadlessFocusClient() = default; void HeadlessFocusClient::AddObserver( aura::client::FocusChangeObserver* observer) { diff --git a/chromium/headless/lib/browser/headless_network_conditions.cc b/chromium/headless/lib/browser/headless_network_conditions.cc index 3b7c643569e..208208c9020 100644 --- a/chromium/headless/lib/browser/headless_network_conditions.cc +++ b/chromium/headless/lib/browser/headless_network_conditions.cc @@ -21,6 +21,6 @@ HeadlessNetworkConditions::HeadlessNetworkConditions(bool offline, download_throughput(download_throughput), upload_throughput(upload_throughput) {} -HeadlessNetworkConditions::~HeadlessNetworkConditions() {} +HeadlessNetworkConditions::~HeadlessNetworkConditions() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_network_delegate.cc b/chromium/headless/lib/browser/headless_network_delegate.cc index 28859f5f686..51e39600211 100644 --- a/chromium/headless/lib/browser/headless_network_delegate.cc +++ b/chromium/headless/lib/browser/headless_network_delegate.cc @@ -40,7 +40,9 @@ int HeadlessNetworkDelegate::OnBeforeURLRequest( net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) { - if (headless_browser_context_->ShouldRemoveHeaders()) { + base::AutoLock lock(lock_); + if (headless_browser_context_ && + headless_browser_context_->ShouldRemoveHeaders()) { request->RemoveRequestHeaderByName( kDevToolsEmulateNetworkConditionsClientId); } @@ -112,7 +114,7 @@ bool HeadlessNetworkDelegate::OnCanGetCookies( } bool HeadlessNetworkDelegate::OnCanSetCookie(const net::URLRequest& request, - const std::string& cookie_line, + const net::CanonicalCookie& cookie, net::CookieOptions* options) { return true; } diff --git a/chromium/headless/lib/browser/headless_network_delegate.h b/chromium/headless/lib/browser/headless_network_delegate.h index ccfb5f63976..66ed81528fc 100644 --- a/chromium/headless/lib/browser/headless_network_delegate.h +++ b/chromium/headless/lib/browser/headless_network_delegate.h @@ -66,7 +66,7 @@ class HeadlessNetworkDelegate : public net::NetworkDelegateImpl, const net::CookieList& cookie_list) override; bool OnCanSetCookie(const net::URLRequest& request, - const std::string& cookie_line, + const net::CanonicalCookie& cookie, net::CookieOptions* options) override; bool OnCanAccessFile(const net::URLRequest& request, diff --git a/chromium/headless/lib/browser/headless_permission_manager.cc b/chromium/headless/lib/browser/headless_permission_manager.cc index a75ee4c3481..8f0fc66e483 100644 --- a/chromium/headless/lib/browser/headless_permission_manager.cc +++ b/chromium/headless/lib/browser/headless_permission_manager.cc @@ -5,13 +5,16 @@ #include "headless/lib/browser/headless_permission_manager.h" #include "base/callback.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/permission_type.h" namespace headless { -HeadlessPermissionManager::HeadlessPermissionManager() : PermissionManager() {} +HeadlessPermissionManager::HeadlessPermissionManager( + content::BrowserContext* browser_context) + : browser_context_(browser_context) {} -HeadlessPermissionManager::~HeadlessPermissionManager() {} +HeadlessPermissionManager::~HeadlessPermissionManager() = default; int HeadlessPermissionManager::RequestPermission( content::PermissionType permission, @@ -20,7 +23,14 @@ int HeadlessPermissionManager::RequestPermission( bool user_gesture, const base::Callback<void(blink::mojom::PermissionStatus)>& callback) { // In headless mode we just pretent the user "closes" any permission prompt, - // without accepting or denying. + // without accepting or denying. Notifications are the exception to this, + // which are explicitly disabled in Incognito mode. + if (browser_context_->IsOffTheRecord() && + permission == content::PermissionType::NOTIFICATIONS) { + callback.Run(blink::mojom::PermissionStatus::DENIED); + return kNoPendingOperation; + } + callback.Run(blink::mojom::PermissionStatus::ASK); return kNoPendingOperation; } diff --git a/chromium/headless/lib/browser/headless_permission_manager.h b/chromium/headless/lib/browser/headless_permission_manager.h index 5eb31859cc3..f9a12522333 100644 --- a/chromium/headless/lib/browser/headless_permission_manager.h +++ b/chromium/headless/lib/browser/headless_permission_manager.h @@ -9,11 +9,15 @@ #include "base/macros.h" #include "content/public/browser/permission_manager.h" +namespace content { +class BrowserContext; +} + namespace headless { class HeadlessPermissionManager : public content::PermissionManager { public: - HeadlessPermissionManager(); + explicit HeadlessPermissionManager(content::BrowserContext* browser_context); ~HeadlessPermissionManager() override; // PermissionManager implementation. @@ -49,6 +53,8 @@ class HeadlessPermissionManager : public content::PermissionManager { void UnsubscribePermissionStatusChange(int subscription_id) override; private: + content::BrowserContext* browser_context_; + DISALLOW_COPY_AND_ASSIGN(HeadlessPermissionManager); }; diff --git a/chromium/headless/lib/browser/headless_platform_event_source.cc b/chromium/headless/lib/browser/headless_platform_event_source.cc index 7c3100ee4f2..598ec80d1cb 100644 --- a/chromium/headless/lib/browser/headless_platform_event_source.cc +++ b/chromium/headless/lib/browser/headless_platform_event_source.cc @@ -6,8 +6,8 @@ namespace headless { -HeadlessPlatformEventSource::HeadlessPlatformEventSource() {} +HeadlessPlatformEventSource::HeadlessPlatformEventSource() = default; -HeadlessPlatformEventSource::~HeadlessPlatformEventSource() {} +HeadlessPlatformEventSource::~HeadlessPlatformEventSource() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_print_manager.cc b/chromium/headless/lib/browser/headless_print_manager.cc index 2213796df0c..e7a816dcb45 100644 --- a/chromium/headless/lib/browser/headless_print_manager.cc +++ b/chromium/headless/lib/browser/headless_print_manager.cc @@ -51,7 +51,7 @@ HeadlessPrintManager::HeadlessPrintManager(content::WebContents* web_contents) Reset(); } -HeadlessPrintManager::~HeadlessPrintManager() {} +HeadlessPrintManager::~HeadlessPrintManager() = default; // static std::string HeadlessPrintManager::PrintResultToString(PrintResult result) { diff --git a/chromium/headless/lib/browser/headless_quota_permission_context.cc b/chromium/headless/lib/browser/headless_quota_permission_context.cc index 618cbe5c978..b75f01bcf42 100644 --- a/chromium/headless/lib/browser/headless_quota_permission_context.cc +++ b/chromium/headless/lib/browser/headless_quota_permission_context.cc @@ -8,7 +8,7 @@ namespace headless { -HeadlessQuotaPermissionContext::HeadlessQuotaPermissionContext() {} +HeadlessQuotaPermissionContext::HeadlessQuotaPermissionContext() = default; void HeadlessQuotaPermissionContext::RequestQuotaPermission( const content::StorageQuotaParams& params, @@ -24,6 +24,6 @@ void HeadlessQuotaPermissionContext::RequestQuotaPermission( callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW); } -HeadlessQuotaPermissionContext::~HeadlessQuotaPermissionContext() {} +HeadlessQuotaPermissionContext::~HeadlessQuotaPermissionContext() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.cc b/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.cc index b8feeb5a386..d7b4888c527 100644 --- a/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.cc +++ b/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.cc @@ -6,16 +6,10 @@ namespace headless { -HeadlessResourceDispatcherHostDelegate::HeadlessResourceDispatcherHostDelegate( - bool enable_resource_scheduler) - : enable_resource_scheduler_(enable_resource_scheduler) {} - HeadlessResourceDispatcherHostDelegate:: - ~HeadlessResourceDispatcherHostDelegate() {} + HeadlessResourceDispatcherHostDelegate() = default; -bool HeadlessResourceDispatcherHostDelegate::ShouldUseResourceScheduler() - const { - return enable_resource_scheduler_; -} +HeadlessResourceDispatcherHostDelegate:: + ~HeadlessResourceDispatcherHostDelegate() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.h b/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.h index 8e276489478..7600c9bfe05 100644 --- a/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.h +++ b/chromium/headless/lib/browser/headless_resource_dispatcher_host_delegate.h @@ -12,15 +12,10 @@ namespace headless { class HeadlessResourceDispatcherHostDelegate : public content::ResourceDispatcherHostDelegate { public: - explicit HeadlessResourceDispatcherHostDelegate( - bool enable_resource_scheduler); + HeadlessResourceDispatcherHostDelegate(); ~HeadlessResourceDispatcherHostDelegate() override; - bool ShouldUseResourceScheduler() const override; - private: - const bool enable_resource_scheduler_; - DISALLOW_COPY_AND_ASSIGN(HeadlessResourceDispatcherHostDelegate); }; diff --git a/chromium/headless/lib/browser/headless_screen.cc b/chromium/headless/lib/browser/headless_screen.cc index 1ee6b64a754..7ce5366b3fa 100644 --- a/chromium/headless/lib/browser/headless_screen.cc +++ b/chromium/headless/lib/browser/headless_screen.cc @@ -21,7 +21,7 @@ HeadlessScreen* HeadlessScreen::Create(const gfx::Size& size) { return new HeadlessScreen(gfx::Rect(size)); } -HeadlessScreen::~HeadlessScreen() {} +HeadlessScreen::~HeadlessScreen() = default; gfx::Point HeadlessScreen::GetCursorScreenPoint() { return aura::Env::GetInstance()->last_mouse_location(); diff --git a/chromium/headless/lib/browser/headless_tab_socket_impl.cc b/chromium/headless/lib/browser/headless_tab_socket_impl.cc index 05e562c4099..cbdb7dc5d79 100644 --- a/chromium/headless/lib/browser/headless_tab_socket_impl.cc +++ b/chromium/headless/lib/browser/headless_tab_socket_impl.cc @@ -19,7 +19,7 @@ HeadlessTabSocketImpl::HeadlessTabSocketImpl(content::WebContents* web_contents) listener_(nullptr), weak_ptr_factory_(this) {} -HeadlessTabSocketImpl::~HeadlessTabSocketImpl() {} +HeadlessTabSocketImpl::~HeadlessTabSocketImpl() = default; // Wrangles the async responses to // HeadlessRenderFrameControllerImpl::InstallTabSocket for which at most one @@ -68,7 +68,7 @@ class TabSocketInstallationController bool success_; friend class base::RefCounted<TabSocketInstallationController>; - ~TabSocketInstallationController() {} + ~TabSocketInstallationController() = default; }; void HeadlessTabSocketImpl::InstallHeadlessTabSocketBindings( diff --git a/chromium/headless/lib/browser/headless_url_request_context_getter.cc b/chromium/headless/lib/browser/headless_url_request_context_getter.cc index d2eaffad364..9df02187acc 100644 --- a/chromium/headless/lib/browser/headless_url_request_context_getter.cc +++ b/chromium/headless/lib/browser/headless_url_request_context_getter.cc @@ -10,18 +10,31 @@ #include "base/memory/ptr_util.h" #include "base/task_scheduler/post_task.h" +#include "build/build_config.h" +#include "components/cookie_config/cookie_store_util.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/cookie_store_factory.h" #include "content/public/browser/devtools_network_transaction_factory.h" +#include "headless/app/headless_shell_switches.h" #include "headless/lib/browser/headless_browser_context_impl.h" #include "headless/lib/browser/headless_browser_context_options.h" #include "headless/lib/browser/headless_network_delegate.h" +#include "net/cookies/cookie_store.h" #include "net/dns/mapped_host_resolver.h" #include "net/http/http_transaction_factory.h" #include "net/http/http_util.h" #include "net/proxy/proxy_service.h" +#include "net/ssl/channel_id_service.h" +#include "net/ssl/default_channel_id_store.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#include "base/command_line.h" +#include "components/os_crypt/key_storage_config_linux.h" +#include "components/os_crypt/os_crypt.h" +#endif + namespace headless { HeadlessURLRequestContextGetter::HeadlessURLRequestContextGetter( @@ -74,6 +87,51 @@ HeadlessURLRequestContextGetter::GetURLRequestContext() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (!url_request_context_) { net::URLRequestContextBuilder builder; + + { + base::AutoLock lock(lock_); + // Don't store cookies in incognito mode or if no user-data-dir was + // specified + // TODO: Enable this always once saving/restoring sessions is implemented + // (https://crbug.com/617931) + if (headless_browser_context_ && + !headless_browser_context_->IsOffTheRecord() && + !headless_browser_context_->options()->user_data_dir().empty()) { +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + std::unique_ptr<os_crypt::Config> config(new os_crypt::Config()); + base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + config->store = + command_line->GetSwitchValueASCII(switches::kPasswordStore); + config->product_name = "HeadlessChrome"; + // OSCrypt may target keyring, which requires calls from the main + // thread. + config->main_thread_runner = + content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::UI); + config->should_use_preference = false; + config->user_data_path = headless_browser_context_->GetPath(); + OSCrypt::SetConfig(std::move(config)); +#endif + + content::CookieStoreConfig cookie_config( + headless_browser_context_->GetPath().Append( + FILE_PATH_LITERAL("Cookies")), + content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, NULL); + cookie_config.crypto_delegate = + cookie_config::GetCookieCryptoDelegate(); + std::unique_ptr<net::CookieStore> cookie_store = + CreateCookieStore(cookie_config); + std::unique_ptr<net::ChannelIDService> channel_id_service = + base::MakeUnique<net::ChannelIDService>( + new net::DefaultChannelIDStore(nullptr)); + + cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID()); + builder.SetCookieAndChannelIdStores(std::move(cookie_store), + std::move(channel_id_service)); + } + } + builder.set_accept_language( net::HttpUtil::GenerateAcceptLanguageHeader(accept_language_)); builder.set_user_agent(user_agent_); diff --git a/chromium/headless/lib/browser/headless_url_request_context_getter.h b/chromium/headless/lib/browser/headless_url_request_context_getter.h index 92341b3b497..1fb71c9f48a 100644 --- a/chromium/headless/lib/browser/headless_url_request_context_getter.h +++ b/chromium/headless/lib/browser/headless_url_request_context_getter.h @@ -14,7 +14,6 @@ #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/content_browser_client.h" #include "headless/public/headless_browser.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_config_service.h" diff --git a/chromium/headless/lib/browser/headless_web_contents_impl.cc b/chromium/headless/lib/browser/headless_web_contents_impl.cc index a3d53b70e4d..cc0c7509625 100644 --- a/chromium/headless/lib/browser/headless_web_contents_impl.cc +++ b/chromium/headless/lib/browser/headless_web_contents_impl.cc @@ -207,13 +207,13 @@ void CreateTabSocketMojoServiceForContents( struct HeadlessWebContentsImpl::PendingFrame { public: - PendingFrame() {} - ~PendingFrame() {} + PendingFrame() = default; + ~PendingFrame() = default; bool MaybeRunCallback() { if (wait_for_copy_result || !display_did_finish_frame) return false; - callback.Run(has_damage, std::move(bitmap)); + callback.Run(has_damage, main_frame_content_updated, std::move(bitmap)); return true; } @@ -221,6 +221,7 @@ struct HeadlessWebContentsImpl::PendingFrame { bool wait_for_copy_result = false; bool display_did_finish_frame = false; bool has_damage = false; + bool main_frame_content_updated = false; std::unique_ptr<SkBitmap> bitmap; FrameFinishedCallback callback; @@ -321,6 +322,7 @@ HeadlessWebContentsImpl::HeadlessWebContentsImpl( weak_ptr_factory_(this) { #if BUILDFLAG(ENABLE_BASIC_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD) HeadlessPrintManager::CreateForWebContents(web_contents); +// TODO(weili): Add support for printing OOPIFs. #endif web_contents->GetMutableRendererPrefs()->accept_languages = browser_context->options()->accept_language(); @@ -595,6 +597,14 @@ void HeadlessWebContentsImpl::DidReceiveCompositorFrame() { for (int session_id : begin_frame_events_enabled_sessions_) agent_host_->SendProtocolMessageToClient(session_id, json_result); } + + // Set main_frame_content_updated on pending frames that the display hasn't + // completed yet. Pending frames that it did complete won't incorporate this + // CompositorFrame. In practice, this should only be a single PendingFrame. + for (const std::unique_ptr<PendingFrame>& pending_frame : pending_frames_) { + if (!pending_frame->display_did_finish_frame) + pending_frame->main_frame_content_updated = true; + } } void HeadlessWebContentsImpl::PendingFrameReadbackComplete( @@ -699,7 +709,7 @@ HeadlessWebContents* HeadlessWebContents::Builder::Build() { return browser_context_->CreateWebContents(this); } -HeadlessWebContents::Builder::MojoService::MojoService() {} +HeadlessWebContents::Builder::MojoService::MojoService() = default; HeadlessWebContents::Builder::MojoService::MojoService( const MojoService& other) = default; @@ -709,6 +719,6 @@ HeadlessWebContents::Builder::MojoService::MojoService( const ServiceFactoryCallback& service_factory) : service_name(service_name), service_factory(service_factory) {} -HeadlessWebContents::Builder::MojoService::~MojoService() {} +HeadlessWebContents::Builder::MojoService::~MojoService() = default; } // namespace headless diff --git a/chromium/headless/lib/browser/headless_web_contents_impl.h b/chromium/headless/lib/browser/headless_web_contents_impl.h index a2095d73f56..a4e06e025ae 100644 --- a/chromium/headless/lib/browser/headless_web_contents_impl.h +++ b/chromium/headless/lib/browser/headless_web_contents_impl.h @@ -143,7 +143,9 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl void SetBeginFrameEventsEnabled(int session_id, bool enabled); using FrameFinishedCallback = - base::Callback<void(bool /*has_damage*/, std::unique_ptr<SkBitmap>)>; + base::Callback<void(bool /* has_damage */, + bool /* main_frame_content_updated */, + std::unique_ptr<SkBitmap>)>; void BeginFrame(const base::TimeTicks& frame_timeticks, const base::TimeTicks& deadline, const base::TimeDelta& interval, @@ -170,7 +172,7 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl const SkBitmap& bitmap, content::ReadbackResponse response); - uint32_t begin_frame_source_id_ = viz::BeginFrameArgs::kManualSourceId; + uint64_t begin_frame_source_id_ = viz::BeginFrameArgs::kManualSourceId; uint64_t begin_frame_sequence_number_ = viz::BeginFrameArgs::kStartingFrameNumber; bool begin_frame_control_enabled_ = false; |