1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "headless/lib/browser/headless_browser_context_impl.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/guid.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/path_service.h"
15 #include "base/task/post_task.h"
16 #include "components/keyed_service/core/simple_key_map.h"
17 #include "content/public/browser/browser_task_traits.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/storage_partition.h"
20 #include "headless/grit/headless_lib_resources.h"
21 #include "headless/lib/browser/headless_browser_context_options.h"
22 #include "headless/lib/browser/headless_browser_impl.h"
23 #include "headless/lib/browser/headless_browser_main_parts.h"
24 #include "headless/lib/browser/headless_permission_manager.h"
25 #include "headless/lib/browser/headless_web_contents_impl.h"
26 #include "ui/base/resource/resource_bundle.h"
27 
28 namespace headless {
29 
HeadlessBrowserContextImpl(HeadlessBrowserImpl * browser,std::unique_ptr<HeadlessBrowserContextOptions> context_options)30 HeadlessBrowserContextImpl::HeadlessBrowserContextImpl(
31     HeadlessBrowserImpl* browser,
32     std::unique_ptr<HeadlessBrowserContextOptions> context_options)
33     : browser_(browser),
34       context_options_(std::move(context_options)),
35       permission_controller_delegate_(
36           std::make_unique<HeadlessPermissionManager>(this)) {
37   InitWhileIOAllowed();
38   simple_factory_key_ =
39       std::make_unique<SimpleFactoryKey>(GetPath(), IsOffTheRecord());
40   SimpleKeyMap::GetInstance()->Associate(this, simple_factory_key_.get());
41   base::FilePath user_data_path =
42       IsOffTheRecord() || context_options_->user_data_dir().empty()
43           ? base::FilePath()
44           : path_;
45   request_context_manager_ = std::make_unique<HeadlessRequestContextManager>(
46       context_options_.get(), user_data_path);
47 }
48 
~HeadlessBrowserContextImpl()49 HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() {
50   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
51   SimpleKeyMap::GetInstance()->Dissociate(this);
52   NotifyWillBeDestroyed(this);
53 
54   // Destroy all web contents before shutting down storage partitions.
55   web_contents_map_.clear();
56 
57   if (request_context_manager_) {
58     base::DeleteSoon(FROM_HERE, {content::BrowserThread::IO},
59                      request_context_manager_.release());
60   }
61 
62   ShutdownStoragePartitions();
63 }
64 
65 // static
From(HeadlessBrowserContext * browser_context)66 HeadlessBrowserContextImpl* HeadlessBrowserContextImpl::From(
67     HeadlessBrowserContext* browser_context) {
68   return static_cast<HeadlessBrowserContextImpl*>(browser_context);
69 }
70 
71 // static
From(content::BrowserContext * browser_context)72 HeadlessBrowserContextImpl* HeadlessBrowserContextImpl::From(
73     content::BrowserContext* browser_context) {
74   return static_cast<HeadlessBrowserContextImpl*>(browser_context);
75 }
76 
77 // static
Create(HeadlessBrowserContext::Builder * builder)78 std::unique_ptr<HeadlessBrowserContextImpl> HeadlessBrowserContextImpl::Create(
79     HeadlessBrowserContext::Builder* builder) {
80   return base::WrapUnique(new HeadlessBrowserContextImpl(
81       builder->browser_, std::move(builder->options_)));
82 }
83 
84 HeadlessWebContents::Builder
CreateWebContentsBuilder()85 HeadlessBrowserContextImpl::CreateWebContentsBuilder() {
86   DCHECK(browser_->BrowserMainThread()->BelongsToCurrentThread());
87   return HeadlessWebContents::Builder(this);
88 }
89 
90 std::vector<HeadlessWebContents*>
GetAllWebContents()91 HeadlessBrowserContextImpl::GetAllWebContents() {
92   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
93 
94   std::vector<HeadlessWebContents*> result;
95   result.reserve(web_contents_map_.size());
96 
97   for (const auto& web_contents_pair : web_contents_map_) {
98     result.push_back(web_contents_pair.second.get());
99   }
100 
101   return result;
102 }
103 
SetDevToolsFrameToken(int render_process_id,int render_frame_routing_id,const base::UnguessableToken & devtools_frame_token,int frame_tree_node_id)104 void HeadlessBrowserContextImpl::SetDevToolsFrameToken(
105     int render_process_id,
106     int render_frame_routing_id,
107     const base::UnguessableToken& devtools_frame_token,
108     int frame_tree_node_id) {
109   base::AutoLock lock(devtools_frame_token_map_lock_);
110   devtools_frame_token_map_[content::GlobalFrameRoutingId(
111       render_process_id, render_frame_routing_id)] = devtools_frame_token;
112   frame_tree_node_id_to_devtools_frame_token_map_[frame_tree_node_id] =
113       devtools_frame_token;
114 }
115 
RemoveDevToolsFrameToken(int render_process_id,int render_frame_routing_id,int frame_tree_node_id)116 void HeadlessBrowserContextImpl::RemoveDevToolsFrameToken(
117     int render_process_id,
118     int render_frame_routing_id,
119     int frame_tree_node_id) {
120   base::AutoLock lock(devtools_frame_token_map_lock_);
121   devtools_frame_token_map_.erase(content::GlobalFrameRoutingId(
122       render_process_id, render_frame_routing_id));
123   frame_tree_node_id_to_devtools_frame_token_map_.erase(frame_tree_node_id);
124 }
125 
GetDevToolsFrameToken(int render_process_id,int render_frame_id) const126 const base::UnguessableToken* HeadlessBrowserContextImpl::GetDevToolsFrameToken(
127     int render_process_id,
128     int render_frame_id) const {
129   base::AutoLock lock(devtools_frame_token_map_lock_);
130   const auto& find_it = devtools_frame_token_map_.find(
131       content::GlobalFrameRoutingId(render_process_id, render_frame_id));
132   if (find_it == devtools_frame_token_map_.end())
133     return nullptr;
134   return &find_it->second;
135 }
136 
137 const base::UnguessableToken*
GetDevToolsFrameTokenForFrameTreeNodeId(int frame_tree_node_id) const138 HeadlessBrowserContextImpl::GetDevToolsFrameTokenForFrameTreeNodeId(
139     int frame_tree_node_id) const {
140   base::AutoLock lock(devtools_frame_token_map_lock_);
141   const auto& find_it =
142       frame_tree_node_id_to_devtools_frame_token_map_.find(frame_tree_node_id);
143   if (find_it == frame_tree_node_id_to_devtools_frame_token_map_.end())
144     return nullptr;
145   return &find_it->second;
146 }
147 
Close()148 void HeadlessBrowserContextImpl::Close() {
149   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
150   browser_->DestroyBrowserContext(this);
151 }
152 
InitWhileIOAllowed()153 void HeadlessBrowserContextImpl::InitWhileIOAllowed() {
154   if (!context_options_->user_data_dir().empty()) {
155     path_ = context_options_->user_data_dir().Append(kDefaultProfileName);
156   } else {
157     base::PathService::Get(base::DIR_EXE, &path_);
158   }
159   BrowserContext::Initialize(this, path_);
160 }
161 
162 std::unique_ptr<content::ZoomLevelDelegate>
CreateZoomLevelDelegate(const base::FilePath & partition_path)163 HeadlessBrowserContextImpl::CreateZoomLevelDelegate(
164     const base::FilePath& partition_path) {
165   return std::unique_ptr<content::ZoomLevelDelegate>();
166 }
167 
GetPath()168 base::FilePath HeadlessBrowserContextImpl::GetPath() {
169   return path_;
170 }
171 
IsOffTheRecord()172 bool HeadlessBrowserContextImpl::IsOffTheRecord() {
173   return context_options_->incognito_mode();
174 }
175 
GetResourceContext()176 content::ResourceContext* HeadlessBrowserContextImpl::GetResourceContext() {
177   return request_context_manager_->GetResourceContext();
178 }
179 
180 content::DownloadManagerDelegate*
GetDownloadManagerDelegate()181 HeadlessBrowserContextImpl::GetDownloadManagerDelegate() {
182   return nullptr;
183 }
184 
185 content::BrowserPluginGuestManager*
GetGuestManager()186 HeadlessBrowserContextImpl::GetGuestManager() {
187   // TODO(altimin): Should be non-null? (is null in content/shell).
188   return nullptr;
189 }
190 
191 storage::SpecialStoragePolicy*
GetSpecialStoragePolicy()192 HeadlessBrowserContextImpl::GetSpecialStoragePolicy() {
193   return nullptr;
194 }
195 
196 content::PushMessagingService*
GetPushMessagingService()197 HeadlessBrowserContextImpl::GetPushMessagingService() {
198   return nullptr;
199 }
200 
201 content::StorageNotificationService*
GetStorageNotificationService()202 HeadlessBrowserContextImpl::GetStorageNotificationService() {
203   return nullptr;
204 }
205 content::SSLHostStateDelegate*
GetSSLHostStateDelegate()206 HeadlessBrowserContextImpl::GetSSLHostStateDelegate() {
207   return nullptr;
208 }
209 
210 content::PermissionControllerDelegate*
GetPermissionControllerDelegate()211 HeadlessBrowserContextImpl::GetPermissionControllerDelegate() {
212   return permission_controller_delegate_.get();
213 }
214 
215 content::ClientHintsControllerDelegate*
GetClientHintsControllerDelegate()216 HeadlessBrowserContextImpl::GetClientHintsControllerDelegate() {
217   return nullptr;
218 }
219 
220 content::BackgroundFetchDelegate*
GetBackgroundFetchDelegate()221 HeadlessBrowserContextImpl::GetBackgroundFetchDelegate() {
222   return nullptr;
223 }
224 
225 content::BackgroundSyncController*
GetBackgroundSyncController()226 HeadlessBrowserContextImpl::GetBackgroundSyncController() {
227   return nullptr;
228 }
229 
230 content::BrowsingDataRemoverDelegate*
GetBrowsingDataRemoverDelegate()231 HeadlessBrowserContextImpl::GetBrowsingDataRemoverDelegate() {
232   return nullptr;
233 }
234 
CreateWebContents(HeadlessWebContents::Builder * builder)235 HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents(
236     HeadlessWebContents::Builder* builder) {
237   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238 
239   std::unique_ptr<HeadlessWebContentsImpl> headless_web_contents =
240       HeadlessWebContentsImpl::Create(builder);
241 
242   if (!headless_web_contents) {
243     return nullptr;
244   }
245 
246   HeadlessWebContents* result = headless_web_contents.get();
247 
248   RegisterWebContents(std::move(headless_web_contents));
249 
250   return result;
251 }
252 
RegisterWebContents(std::unique_ptr<HeadlessWebContentsImpl> web_contents)253 void HeadlessBrowserContextImpl::RegisterWebContents(
254     std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
255   DCHECK(web_contents);
256   web_contents_map_[web_contents->GetDevToolsAgentHostId()] =
257       std::move(web_contents);
258 }
259 
DestroyWebContents(HeadlessWebContentsImpl * web_contents)260 void HeadlessBrowserContextImpl::DestroyWebContents(
261     HeadlessWebContentsImpl* web_contents) {
262   auto it = web_contents_map_.find(web_contents->GetDevToolsAgentHostId());
263   DCHECK(it != web_contents_map_.end());
264   web_contents_map_.erase(it);
265 }
266 
267 HeadlessWebContents*
GetWebContentsForDevToolsAgentHostId(const std::string & devtools_agent_host_id)268 HeadlessBrowserContextImpl::GetWebContentsForDevToolsAgentHostId(
269     const std::string& devtools_agent_host_id) {
270   auto find_it = web_contents_map_.find(devtools_agent_host_id);
271   if (find_it == web_contents_map_.end())
272     return nullptr;
273   return find_it->second.get();
274 }
275 
browser() const276 HeadlessBrowserImpl* HeadlessBrowserContextImpl::browser() const {
277   return browser_;
278 }
279 
options() const280 const HeadlessBrowserContextOptions* HeadlessBrowserContextImpl::options()
281     const {
282   return context_options_.get();
283 }
284 
Id()285 const std::string& HeadlessBrowserContextImpl::Id() {
286   return UniqueId();
287 }
288 
289 mojo::Remote<::network::mojom::NetworkContext>
CreateNetworkContext(bool in_memory,const base::FilePath & relative_partition_path)290 HeadlessBrowserContextImpl::CreateNetworkContext(
291     bool in_memory,
292     const base::FilePath& relative_partition_path) {
293   return request_context_manager_->CreateNetworkContext(
294       in_memory, relative_partition_path);
295 }
296 
Builder(HeadlessBrowserImpl * browser)297 HeadlessBrowserContext::Builder::Builder(HeadlessBrowserImpl* browser)
298     : browser_(browser),
299       options_(new HeadlessBrowserContextOptions(browser->options())) {}
300 
301 HeadlessBrowserContext::Builder::~Builder() = default;
302 
303 HeadlessBrowserContext::Builder::Builder(Builder&&) = default;
304 
305 HeadlessBrowserContext::Builder&
SetProductNameAndVersion(const std::string & product_name_and_version)306 HeadlessBrowserContext::Builder::SetProductNameAndVersion(
307     const std::string& product_name_and_version) {
308   options_->product_name_and_version_ = product_name_and_version;
309   return *this;
310 }
311 
SetUserAgent(const std::string & user_agent)312 HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::SetUserAgent(
313     const std::string& user_agent) {
314   options_->user_agent_ = user_agent;
315   return *this;
316 }
317 
318 HeadlessBrowserContext::Builder&
SetAcceptLanguage(const std::string & accept_language)319 HeadlessBrowserContext::Builder::SetAcceptLanguage(
320     const std::string& accept_language) {
321   options_->accept_language_ = accept_language;
322   return *this;
323 }
324 
325 HeadlessBrowserContext::Builder&
SetProxyConfig(std::unique_ptr<net::ProxyConfig> proxy_config)326 HeadlessBrowserContext::Builder::SetProxyConfig(
327     std::unique_ptr<net::ProxyConfig> proxy_config) {
328   options_->proxy_config_ = std::move(proxy_config);
329   return *this;
330 }
331 
SetWindowSize(const gfx::Size & window_size)332 HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::SetWindowSize(
333     const gfx::Size& window_size) {
334   options_->window_size_ = window_size;
335   return *this;
336 }
337 
338 HeadlessBrowserContext::Builder&
SetUserDataDir(const base::FilePath & user_data_dir)339 HeadlessBrowserContext::Builder::SetUserDataDir(
340     const base::FilePath& user_data_dir) {
341   options_->user_data_dir_ = user_data_dir;
342   return *this;
343 }
344 
345 HeadlessBrowserContext::Builder&
SetIncognitoMode(bool incognito_mode)346 HeadlessBrowserContext::Builder::SetIncognitoMode(bool incognito_mode) {
347   options_->incognito_mode_ = incognito_mode;
348   return *this;
349 }
350 
351 HeadlessBrowserContext::Builder&
SetBlockNewWebContents(bool block_new_web_contents)352 HeadlessBrowserContext::Builder::SetBlockNewWebContents(
353     bool block_new_web_contents) {
354   options_->block_new_web_contents_ = block_new_web_contents;
355   return *this;
356 }
357 
358 HeadlessBrowserContext::Builder&
SetOverrideWebPreferencesCallback(base::RepeatingCallback<void (WebPreferences *)> callback)359 HeadlessBrowserContext::Builder::SetOverrideWebPreferencesCallback(
360     base::RepeatingCallback<void(WebPreferences*)> callback) {
361   options_->override_web_preferences_callback_ = std::move(callback);
362   return *this;
363 }
364 
Build()365 HeadlessBrowserContext* HeadlessBrowserContext::Builder::Build() {
366   return browser_->CreateBrowserContext(this);
367 }
368 
369 HeadlessBrowserContext::Builder::MojoBindings::MojoBindings() = default;
370 
MojoBindings(const std::string & mojom_name,const std::string & js_bindings)371 HeadlessBrowserContext::Builder::MojoBindings::MojoBindings(
372     const std::string& mojom_name,
373     const std::string& js_bindings)
374     : mojom_name(mojom_name), js_bindings(js_bindings) {}
375 
376 HeadlessBrowserContext::Builder::MojoBindings::~MojoBindings() = default;
377 
378 }  // namespace headless
379