1 // Copyright (c) 2012 The Chromium Embedded Framework Authors.
2 // Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "libcef/browser/net/chrome_scheme_handler.h"
7
8 #include <algorithm>
9 #include <map>
10 #include <string>
11 #include <utility>
12
13 #include "include/cef_version.h"
14 #include "include/cef_web_plugin.h"
15 #include "libcef/browser/extensions/chrome_api_registration.h"
16 #include "libcef/browser/frame_host_impl.h"
17 #include "libcef/browser/net/internal_scheme_handler.h"
18 #include "libcef/browser/thread_util.h"
19 #include "libcef/common/app_manager.h"
20 #include "libcef/features/runtime.h"
21
22 #include "base/command_line.h"
23 #include "base/files/file_util.h"
24 #include "base/lazy_instance.h"
25 #include "base/logging.h"
26 #include "base/memory/ptr_util.h"
27 #include "base/path_service.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "base/values.h"
32 #include "cef/grit/cef_resources.h"
33 #include "chrome/browser/browser_about_handler.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/ui/webui/chrome_untrusted_web_ui_controller_factory.h"
36 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
37 #include "chrome/browser/ui/webui/theme_source.h"
38 #include "chrome/common/url_constants.h"
39 #include "content/browser/renderer_host/debug_urls.h"
40 #include "content/browser/webui/content_web_ui_controller_factory.h"
41 #include "content/public/browser/browser_url_handler.h"
42 #include "content/public/browser/content_browser_client.h"
43 #include "content/public/browser/url_data_source.h"
44 #include "content/public/browser/web_ui_controller.h"
45 #include "content/public/common/url_constants.h"
46 #include "content/public/common/url_utils.h"
47 #include "content/public/common/user_agent.h"
48 #include "ipc/ipc_channel.h"
49 #include "third_party/blink/public/common/chrome_debug_urls.h"
50 #include "ui/base/resource/resource_bundle.h"
51 #include "v8/include/v8.h"
52
53 using extensions::api::cef::kSupportedAPIs;
54
55 namespace scheme {
56
57 const char kChromeURL[] = "chrome://";
58
59 namespace {
60
61 const char kChromeUIExtensionsSupportHost[] = "extensions-support";
62 const char kChromeUILicenseHost[] = "license";
63 const char kChromeUIWebUIHostsHost[] = "webui-hosts";
64
65 // TODO(network): Consider handling content::kChromeDevToolsScheme via WebUI
66 // (DevToolsUI class) with the following changes:
67 // 1. Add an entry for content::kChromeDevToolsScheme in
68 // AlloyContentBrowserClient::GetAdditionalWebUISchemes.
69 // 2. Allow the scheme in CefWebUIControllerFactory::AllowWebUIForURL.
70 // 3. Add an entry for chrome::kChromeUIDevToolsHost in kAllowedWebUIHosts and
71 // kUnlistedHosts.
72 // 4. Remove scheme::RegisterInternalHandlers and related plumbing.
73
74 // Chrome hosts implemented by WebUI.
75 // Some WebUI handlers have Chrome dependencies that may fail in CEF without
76 // additional changes. Do not add new hosts to this list without also manually
77 // testing all related functionality in CEF.
78 const char* kAllowedWebUIHosts[] = {
79 chrome::kChromeUIAccessibilityHost,
80 content::kChromeUIBlobInternalsHost,
81 chrome::kChromeUIChromeURLsHost,
82 chrome::kChromeUICreditsHost,
83 kChromeUIExtensionsSupportHost,
84 content::kChromeUIGpuHost,
85 content::kChromeUIHistogramHost,
86 content::kChromeUIIndexedDBInternalsHost,
87 kChromeUILicenseHost,
88 content::kChromeUIMediaInternalsHost,
89 chrome::kChromeUINetExportHost,
90 chrome::kChromeUINetInternalsHost,
91 content::kChromeUINetworkErrorHost,
92 content::kChromeUINetworkErrorsListingHost,
93 chrome::kChromeUIPrintHost,
94 content::kChromeUIProcessInternalsHost,
95 content::kChromeUIResourcesHost,
96 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
97 chrome::kChromeUISandboxHost,
98 #endif
99 content::kChromeUIServiceWorkerInternalsHost,
100 chrome::kChromeUISystemInfoHost,
101 chrome::kChromeUIThemeHost,
102 content::kChromeUITracingHost,
103 chrome::kChromeUIVersionHost,
104 content::kChromeUIWebRTCInternalsHost,
105 kChromeUIWebUIHostsHost,
106 };
107
108 // Hosts that don't have useful output when linked directly. They'll be excluded
109 // from the "chrome://webui-hosts" listing.
110 const char* kUnlistedHosts[] = {
111 content::kChromeUINetworkErrorHost,
112 content::kChromeUIResourcesHost,
113 chrome::kChromeUIThemeHost,
114 };
115
116 enum ChromeHostId {
117 CHROME_UNKNOWN = 0,
118 CHROME_EXTENSIONS_SUPPORT,
119 CHROME_LICENSE,
120 CHROME_VERSION,
121 CHROME_WEBUI_HOSTS,
122 };
123
124 // Chrome hosts implemented by CEF.
125 const struct {
126 const char* host;
127 ChromeHostId host_id;
128 } kAllowedCefHosts[] = {
129 {chrome::kChromeUIChromeURLsHost, CHROME_WEBUI_HOSTS},
130 {kChromeUIExtensionsSupportHost, CHROME_EXTENSIONS_SUPPORT},
131 {kChromeUILicenseHost, CHROME_LICENSE},
132 {chrome::kChromeUIVersionHost, CHROME_VERSION},
133 {kChromeUIWebUIHostsHost, CHROME_WEBUI_HOSTS},
134 };
135
GetChromeHostId(const std::string & host)136 ChromeHostId GetChromeHostId(const std::string& host) {
137 for (size_t i = 0; i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]);
138 ++i) {
139 if (base::EqualsCaseInsensitiveASCII(kAllowedCefHosts[i].host,
140 host.c_str())) {
141 return kAllowedCefHosts[i].host_id;
142 }
143 }
144
145 return CHROME_UNKNOWN;
146 }
147
148 // Returns WebUI hosts. Does not include chrome debug hosts (for crashing, etc).
GetAllowedHosts(std::vector<std::string> * hosts)149 void GetAllowedHosts(std::vector<std::string>* hosts) {
150 // Explicitly whitelisted WebUI hosts.
151 for (size_t i = 0;
152 i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
153 hosts->push_back(kAllowedWebUIHosts[i]);
154 }
155 }
156
157 // Returns true if a host should not be listed on "chrome://webui-hosts".
IsUnlistedHost(const std::string & host)158 bool IsUnlistedHost(const std::string& host) {
159 for (size_t i = 0; i < sizeof(kUnlistedHosts) / sizeof(kUnlistedHosts[0]);
160 ++i) {
161 if (host == kUnlistedHosts[i])
162 return true;
163 }
164 return false;
165 }
166
167 // Returns true if a host is WebUI and should be allowed to load.
IsAllowedWebUIHost(const std::string & host)168 bool IsAllowedWebUIHost(const std::string& host) {
169 // Chrome runtime allows all WebUI hosts.
170 if (cef::IsChromeRuntimeEnabled())
171 return true;
172
173 // Explicitly whitelisted WebUI hosts.
174 for (size_t i = 0;
175 i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
176 if (base::EqualsCaseInsensitiveASCII(kAllowedWebUIHosts[i], host.c_str())) {
177 return true;
178 }
179 }
180
181 return false;
182 }
183
184 // Additional debug URLs that are not included in chrome::kChromeDebugURLs.
185 const char* kAllowedDebugURLs[] = {
186 blink::kChromeUIBrowserCrashURL,
187 };
188
GetDebugURLs(std::vector<std::string> * urls)189 void GetDebugURLs(std::vector<std::string>* urls) {
190 for (size_t i = 0; i < chrome::kNumberOfChromeDebugURLs; ++i) {
191 urls->push_back(chrome::kChromeDebugURLs[i]);
192 }
193
194 for (size_t i = 0;
195 i < sizeof(kAllowedDebugURLs) / sizeof(kAllowedDebugURLs[0]); ++i) {
196 urls->push_back(kAllowedDebugURLs[i]);
197 }
198 }
199
GetOSType()200 std::string GetOSType() {
201 #if BUILDFLAG(IS_WIN)
202 return "Windows";
203 #elif BUILDFLAG(IS_MAC)
204 return "Mac OS X";
205 #elif BUILDFLAG(IS_LINUX)
206 return "Linux";
207 #else
208 return "Unknown";
209 #endif
210 }
211
GetCommandLine()212 std::string GetCommandLine() {
213 #if BUILDFLAG(IS_WIN)
214 return base::WideToUTF8(
215 base::CommandLine::ForCurrentProcess()->GetCommandLineString());
216 #elif BUILDFLAG(IS_POSIX)
217 std::string command_line = "";
218 using ArgvList = std::vector<std::string>;
219 const ArgvList& argv = base::CommandLine::ForCurrentProcess()->argv();
220 for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++)
221 command_line += " " + *iter;
222 // TODO(viettrungluu): |command_line| could really have any encoding, whereas
223 // below we assumes it's UTF-8.
224 return command_line;
225 #endif
226 }
227
GetModulePath()228 std::string GetModulePath() {
229 base::FilePath path;
230 if (base::PathService::Get(base::FILE_MODULE, &path))
231 return CefString(path.value());
232 return std::string();
233 }
234
235 class TemplateParser {
236 public:
TemplateParser()237 TemplateParser() : ident_start_("$$"), ident_end_("$$") {}
238
TemplateParser(const std::string & ident_start,const std::string & ident_end)239 TemplateParser(const std::string& ident_start, const std::string& ident_end)
240 : ident_start_(ident_start), ident_end_(ident_end) {}
241
Add(const std::string & key,const std::string & value)242 void Add(const std::string& key, const std::string& value) {
243 values_.insert(std::make_pair(key, value));
244 }
245
Parse(std::string * tmpl)246 void Parse(std::string* tmpl) {
247 int start_pos, end_pos = 0;
248 int ident_start_len = ident_start_.length();
249 int ident_end_len = ident_end_.length();
250
251 while (true) {
252 start_pos = tmpl->find(ident_start_, end_pos);
253 if (start_pos >= 0) {
254 end_pos = tmpl->find(ident_end_, start_pos + ident_start_len);
255 if (end_pos >= 0) {
256 // Found an identifier. Check if a substitution exists.
257 std::string key = tmpl->substr(start_pos + ident_start_len,
258 end_pos - start_pos - ident_start_len);
259 KeyMap::const_iterator it = values_.find(key);
260 if (it != values_.end()) {
261 // Peform the substitution.
262 tmpl->replace(start_pos, end_pos + ident_end_len - start_pos,
263 it->second);
264 end_pos = start_pos + it->second.length();
265 } else {
266 // Leave the unknown identifier in place.
267 end_pos += ident_end_len;
268 }
269
270 if (end_pos >= static_cast<int>(tmpl->length()) - ident_start_len -
271 ident_end_len) {
272 // Not enough room remaining for more identifiers.
273 break;
274 }
275 } else {
276 // No end identifier found.
277 break;
278 }
279 } else {
280 // No start identifier found.
281 break;
282 }
283 }
284 }
285
286 private:
287 using KeyMap = std::map<std::string, std::string>;
288 KeyMap values_;
289 std::string ident_start_;
290 std::string ident_end_;
291 };
292
OnExtensionsSupportUI(std::string * mime_type,std::string * output)293 bool OnExtensionsSupportUI(std::string* mime_type, std::string* output) {
294 *mime_type = "text/html";
295
296 if (cef::IsChromeRuntimeEnabled()) {
297 // Redirect to the Chrome documentation.
298 *output =
299 "<html><head>\n"
300 "<meta http-equiv=\"refresh\" "
301 "content=\"0;URL='https://developer.chrome.com/docs/extensions/'\"/>\n"
302 "</head></html>\n";
303 return true;
304 }
305
306 static const char kDevURL[] = "https://developer.chrome.com/extensions/";
307
308 std::string html =
309 "<html>\n<head><title>Extensions Support</title></head>\n"
310 "<body bgcolor=\"white\"><h3>Supported Chrome Extensions "
311 "APIs</h3>\nFollow <a "
312 "href=\"https://bitbucket.org/chromiumembedded/cef/issues/1947\" "
313 "target=\"new\">issue #1947</a> for development progress.\n<ul>\n";
314
315 bool has_top_level_name = false;
316 for (size_t i = 0; kSupportedAPIs[i] != nullptr; ++i) {
317 const std::string& api_name = kSupportedAPIs[i];
318 if (api_name.find("Private") != std::string::npos) {
319 // Don't list private APIs.
320 continue;
321 }
322
323 const size_t dot_pos = api_name.find('.');
324 if (dot_pos == std::string::npos) {
325 if (has_top_level_name) {
326 // End the previous top-level API entry.
327 html += "</ul></li>\n";
328 } else {
329 has_top_level_name = true;
330 }
331
332 // Start a new top-level API entry.
333 html += "<li><a href=\"" + std::string(kDevURL) + api_name +
334 "\" target=\"new\">" + api_name + "</a><ul>\n";
335 } else {
336 // Function name.
337 const std::string& group_name = api_name.substr(0, dot_pos);
338 const std::string& function_name = api_name.substr(dot_pos + 1);
339 html += "\t<li><a href=\"" + std::string(kDevURL) + group_name +
340 "#method-" + function_name + "\" target=\"new\">" + api_name +
341 "</a></li>\n";
342 }
343 }
344
345 if (has_top_level_name) {
346 // End the last top-level API entry.
347 html += "</ul></li>\n";
348 }
349
350 html += "</ul>\n</body>\n</html>";
351
352 *output = html;
353 return true;
354 }
355
OnLicenseUI(std::string * mime_type,std::string * output)356 bool OnLicenseUI(std::string* mime_type, std::string* output) {
357 std::string piece =
358 ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
359 IDR_CEF_LICENSE_TXT);
360 if (piece.empty()) {
361 NOTREACHED() << "Failed to load license txt resource.";
362 return false;
363 }
364
365 *mime_type = "text/html";
366 *output = "<html><head><title>License</title></head><body><pre>" + piece +
367 "</pre></body></html>";
368
369 return true;
370 }
371
OnVersionUI(Profile * profile,std::string * mime_type,std::string * output)372 bool OnVersionUI(Profile* profile,
373 std::string* mime_type,
374 std::string* output) {
375 std::string tmpl =
376 ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
377 IDR_CEF_VERSION_HTML);
378 if (tmpl.empty()) {
379 NOTREACHED() << "Failed to load version html resource.";
380 return false;
381 }
382
383 TemplateParser parser;
384 parser.Add("YEAR", MAKE_STRING(COPYRIGHT_YEAR));
385 parser.Add("CEF", CEF_VERSION);
386 parser.Add("CHROMIUM",
387 base::StringPrintf("%d.%d.%d.%d", CHROME_VERSION_MAJOR,
388 CHROME_VERSION_MINOR, CHROME_VERSION_BUILD,
389 CHROME_VERSION_PATCH));
390 parser.Add("OS", GetOSType());
391 parser.Add("WEBKIT", content::GetWebKitVersion());
392 parser.Add("JAVASCRIPT", v8::V8::GetVersion());
393 parser.Add(
394 "USERAGENT",
395 CefAppManager::Get()->GetContentClient()->browser()->GetUserAgent());
396 parser.Add("COMMANDLINE", GetCommandLine());
397 parser.Add("MODULEPATH", GetModulePath());
398 parser.Add("CACHEPATH", CefString(profile->GetPath().value()));
399
400 parser.Parse(&tmpl);
401
402 *mime_type = "text/html";
403 *output = tmpl;
404
405 return true;
406 }
407
OnWebUIHostsUI(std::string * mime_type,std::string * output)408 bool OnWebUIHostsUI(std::string* mime_type, std::string* output) {
409 std::string html =
410 "<html>\n<head><title>Chrome URLs</title></head>\n"
411 "<body bgcolor=\"white\"><h3>List of Chrome URLs</h3>\n<ul>\n";
412
413 std::vector<std::string> list;
414 GetAllowedHosts(&list);
415 std::sort(list.begin(), list.end());
416
417 for (size_t i = 0U; i < list.size(); ++i) {
418 if (IsUnlistedHost(list[i]))
419 continue;
420
421 html += "<li><a href=\"chrome://" + list[i] + "\">chrome://" + list[i] +
422 "</a></li>\n";
423 }
424
425 list.clear();
426 GetDebugURLs(&list);
427 std::sort(list.begin(), list.end());
428
429 html +=
430 "</ul>\n<h3>For Debug</h3>\n"
431 "<p>The following pages are for debugging purposes only. Because they "
432 "crash or hang the renderer, they're not linked directly; you can type "
433 "them into the address bar if you need them.</p>\n<ul>\n";
434 for (size_t i = 0U; i < list.size(); ++i) {
435 html += "<li>" + std::string(list[i]) + "</li>\n";
436 }
437 html += "</ul>\n";
438
439 html += "</body>\n</html>";
440
441 *mime_type = "text/html";
442 *output = html;
443
444 return true;
445 }
446
447 const content::WebUI::TypeID kCefWebUITypeID = &kCefWebUITypeID;
448
449 class CefURLDataSource : public content::URLDataSource {
450 public:
CefURLDataSource(const std::string & host,ChromeHostId host_id,Profile * profile)451 CefURLDataSource(const std::string& host,
452 ChromeHostId host_id,
453 Profile* profile)
454 : host_(host), host_id_(host_id), profile_(profile) {
455 CEF_REQUIRE_UIT();
456 output_ = new base::RefCountedString();
457 bool handled = false;
458 switch (host_id_) {
459 case CHROME_EXTENSIONS_SUPPORT:
460 handled = OnExtensionsSupportUI(&mime_type_, &output_->data());
461 break;
462 case CHROME_LICENSE:
463 handled = OnLicenseUI(&mime_type_, &output_->data());
464 break;
465 case CHROME_VERSION:
466 handled = OnVersionUI(profile_, &mime_type_, &output_->data());
467 break;
468 case CHROME_WEBUI_HOSTS:
469 handled = OnWebUIHostsUI(&mime_type_, &output_->data());
470 break;
471 default:
472 break;
473 }
474 DCHECK(handled) << "Unhandled WebUI host: " << host;
475 }
476
477 CefURLDataSource(const CefURLDataSource&) = delete;
478 CefURLDataSource& operator=(const CefURLDataSource&) = delete;
479
480 ~CefURLDataSource() override = default;
481
482 // content::URLDataSource implementation.
GetSource()483 std::string GetSource() override { return host_; }
484
StartDataRequest(const GURL & path,const content::WebContents::Getter & wc_getter,content::URLDataSource::GotDataCallback callback)485 void StartDataRequest(
486 const GURL& path,
487 const content::WebContents::Getter& wc_getter,
488 content::URLDataSource::GotDataCallback callback) override {
489 std::move(callback).Run(output_);
490 }
491
GetMimeType(const std::string & path)492 std::string GetMimeType(const std::string& path) override {
493 return mime_type_;
494 }
495
AllowCaching()496 bool AllowCaching() override { return false; }
497
498 private:
499 const std::string host_;
500 const ChromeHostId host_id_;
501 Profile* const profile_;
502
503 std::string mime_type_;
504 scoped_refptr<base::RefCountedString> output_;
505 };
506
507 class CefWebUIController : public content::WebUIController {
508 public:
CefWebUIController(content::WebUI * web_ui,const std::string & host,ChromeHostId host_id)509 CefWebUIController(content::WebUI* web_ui,
510 const std::string& host,
511 ChromeHostId host_id)
512 : content::WebUIController(web_ui) {
513 Profile* profile = Profile::FromWebUI(web_ui);
514 content::URLDataSource::Add(
515 profile, std::make_unique<CefURLDataSource>(host, host_id, profile));
516 }
517
518 CefWebUIController(const CefWebUIController&) = delete;
519 CefWebUIController& operator=(const CefWebUIController&) = delete;
520
521 ~CefWebUIController() override = default;
522 };
523
524 // Intercepts all WebUI calls and either blocks them or forwards them to the
525 // Content or Chrome WebUI factory as appropriate.
526 class CefWebUIControllerFactory : public content::WebUIControllerFactory {
527 public:
528 CefWebUIControllerFactory(const CefWebUIControllerFactory&) = delete;
529 CefWebUIControllerFactory& operator=(const CefWebUIControllerFactory&) =
530 delete;
531
532 // Returns true if WebUI is allowed to handle the specified |url|.
AllowWebUIForURL(const GURL & url)533 static bool AllowWebUIForURL(const GURL& url) {
534 if (!url.SchemeIs(content::kChromeUIScheme) &&
535 !url.SchemeIs(content::kChromeUIUntrustedScheme)) {
536 return false;
537 }
538
539 if (IsAllowedWebUIHost(url.host()))
540 return true;
541
542 return false;
543 }
544
545 // Returns true if WebUI is allowed to make network requests.
IsWebUIAllowedToMakeNetworkRequests(const url::Origin & origin)546 static bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) {
547 if (!AllowWebUIForURL(origin.GetURL()))
548 return false;
549
550 if (ChromeWebUIControllerFactory::IsWebUIAllowedToMakeNetworkRequests(
551 origin)) {
552 return true;
553 }
554
555 return false;
556 }
557
CreateWebUIControllerForURL(content::WebUI * web_ui,const GURL & url)558 std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
559 content::WebUI* web_ui,
560 const GURL& url) override {
561 std::unique_ptr<content::WebUIController> controller;
562 if (!AllowWebUIForURL(url))
563 return controller;
564
565 // Set up the chrome://theme/ source. These URLs are referenced from many
566 // places (WebUI and chrome://resources which live in //ui). WebUI code
567 // can live in both //content and //chrome. Since ThemeSource lives in
568 // //chrome the WebUI from //content is not performing this setup despite
569 // the fact that it's needed for proper handling of theme resource requests.
570 // See https://crbug.com/1011280.
571 Profile* profile = Profile::FromWebUI(web_ui);
572 content::URLDataSource::Add(profile,
573 std::make_unique<ThemeSource>(profile));
574
575 const auto host_id = GetChromeHostId(url.host());
576 if (host_id != CHROME_UNKNOWN) {
577 return std::make_unique<CefWebUIController>(web_ui, url.host(), host_id);
578 }
579
580 controller = content::ContentWebUIControllerFactory::GetInstance()
581 ->CreateWebUIControllerForURL(web_ui, url);
582 if (controller.get())
583 return controller;
584
585 controller = ChromeUntrustedWebUIControllerFactory::GetInstance()
586 ->CreateWebUIControllerForURL(web_ui, url);
587 if (controller.get())
588 return controller;
589
590 return ChromeWebUIControllerFactory::GetInstance()
591 ->CreateWebUIControllerForURL(web_ui, url);
592 }
593
GetWebUIType(content::BrowserContext * browser_context,const GURL & url)594 content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
595 const GURL& url) override {
596 content::WebUI::TypeID type = content::WebUI::kNoWebUI;
597 if (!AllowWebUIForURL(url))
598 return type;
599
600 const auto host_id = GetChromeHostId(url.host());
601 if (host_id != CHROME_UNKNOWN) {
602 return kCefWebUITypeID;
603 }
604
605 type = content::ContentWebUIControllerFactory::GetInstance()->GetWebUIType(
606 browser_context, url);
607 if (type != content::WebUI::kNoWebUI)
608 return type;
609
610 type = ChromeUntrustedWebUIControllerFactory::GetInstance()->GetWebUIType(
611 browser_context, url);
612 if (type != content::WebUI::kNoWebUI)
613 return type;
614
615 type = ChromeWebUIControllerFactory::GetInstance()->GetWebUIType(
616 browser_context, url);
617 if (type != content::WebUI::kNoWebUI)
618 return type;
619
620 return content::WebUI::kNoWebUI;
621 }
622
UseWebUIForURL(content::BrowserContext * browser_context,const GURL & url)623 bool UseWebUIForURL(content::BrowserContext* browser_context,
624 const GURL& url) override {
625 if (!AllowWebUIForURL(url))
626 return false;
627
628 const auto host_id = GetChromeHostId(url.host());
629 if (host_id != CHROME_UNKNOWN) {
630 return true;
631 }
632
633 if (content::ContentWebUIControllerFactory::GetInstance()->UseWebUIForURL(
634 browser_context, url) ||
635 ChromeUntrustedWebUIControllerFactory::GetInstance()->UseWebUIForURL(
636 browser_context, url) ||
637 ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
638 browser_context, url)) {
639 return true;
640 }
641
642 return false;
643 }
644
BrowserURLHandlerCreated(content::BrowserURLHandler * handler)645 static void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) {
646 // For Chrome runtime this is registered in
647 // ChromeContentBrowserClient::BrowserURLHandlerCreated().
648 if (cef::IsAlloyRuntimeEnabled()) {
649 // Handler to rewrite chrome://about and chrome://sync URLs.
650 handler->AddHandlerPair(&HandleChromeAboutAndChromeSyncRewrite,
651 content::BrowserURLHandler::null_handler());
652 }
653
654 // chrome: & friends. For Chrome runtime the default registration is
655 // disabled is ChromeContentBrowserClient::BrowserURLHandlerCreated().
656 handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse);
657 }
658
659 static CefWebUIControllerFactory* GetInstance();
660
661 protected:
662 CefWebUIControllerFactory() = default;
663 ~CefWebUIControllerFactory() override = default;
664
665 private:
666 friend struct base::LazyInstanceTraitsBase<CefWebUIControllerFactory>;
667
668 // From chrome/browser/chrome_content_browser_client.cc
669
670 // Handles rewriting Web UI URLs.
HandleWebUI(GURL * url,content::BrowserContext * browser_context)671 static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) {
672 if (!GetInstance()->UseWebUIForURL(browser_context, *url))
673 return false;
674
675 return true;
676 }
677
678 // Reverse URL handler for Web UI.
HandleWebUIReverse(GURL * url,content::BrowserContext * browser_context)679 static bool HandleWebUIReverse(GURL* url,
680 content::BrowserContext* browser_context) {
681 // No need to actually reverse-rewrite the URL.
682 return false;
683 }
684 };
685
686 base::LazyInstance<CefWebUIControllerFactory>::Leaky
687 g_web_ui_controller_factory = LAZY_INSTANCE_INITIALIZER;
688
689 // static
GetInstance()690 CefWebUIControllerFactory* CefWebUIControllerFactory::GetInstance() {
691 return &g_web_ui_controller_factory.Get();
692 }
693
694 } // namespace
695
RegisterWebUIControllerFactory()696 void RegisterWebUIControllerFactory() {
697 // Channel all WebUI handling through CefWebUIControllerFactory.
698 content::WebUIControllerFactory::UnregisterFactoryForTesting(
699 content::ContentWebUIControllerFactory::GetInstance());
700
701 content::WebUIControllerFactory::RegisterFactory(
702 CefWebUIControllerFactory::GetInstance());
703 }
704
BrowserURLHandlerCreated(content::BrowserURLHandler * handler)705 void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) {
706 CefWebUIControllerFactory::BrowserURLHandlerCreated(handler);
707 }
708
IsWebUIAllowedToMakeNetworkRequests(const url::Origin & origin)709 bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) {
710 return CefWebUIControllerFactory::IsWebUIAllowedToMakeNetworkRequests(origin);
711 }
712
713 } // namespace scheme
714