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