1// Copyright (c) 2011 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 "chrome/browser/ui/webui/chrome_web_ui_factory.h"
6
7#include "base/command_line.h"
8#include "chrome/browser/about_flags.h"
9#include "chrome/browser/extensions/extension_service.h"
10#include "chrome/browser/extensions/extension_web_ui.h"
11#include "chrome/browser/extensions/extensions_ui.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/webui/bookmarks_ui.h"
14#include "chrome/browser/ui/webui/bug_report_ui.h"
15#include "chrome/browser/ui/webui/constrained_html_ui.h"
16#include "chrome/browser/ui/webui/crashes_ui.h"
17#include "chrome/browser/ui/webui/devtools_ui.h"
18#include "chrome/browser/ui/webui/downloads_ui.h"
19#include "chrome/browser/ui/webui/flags_ui.h"
20#include "chrome/browser/ui/webui/gpu_internals_ui.h"
21#include "chrome/browser/ui/webui/history2_ui.h"
22#include "chrome/browser/ui/webui/history_ui.h"
23#include "chrome/browser/ui/webui/html_dialog_ui.h"
24#include "chrome/browser/ui/webui/net_internals_ui.h"
25#include "chrome/browser/ui/webui/new_tab_ui.h"
26#include "chrome/browser/ui/webui/options/options_ui.h"
27#include "chrome/browser/ui/webui/plugins_ui.h"
28#include "chrome/browser/ui/webui/print_preview_ui.h"
29#include "chrome/browser/ui/webui/remoting_ui.h"
30#include "chrome/browser/ui/webui/sync_internals_ui.h"
31#include "chrome/browser/ui/webui/textfields_ui.h"
32#include "chrome/common/chrome_switches.h"
33#include "chrome/common/extensions/extension_constants.h"
34#include "chrome/common/url_constants.h"
35#include "content/browser/tab_contents/tab_contents.h"
36#include "content/browser/webui/web_ui.h"
37#include "googleurl/src/gurl.h"
38
39#if defined(OS_CHROMEOS)
40#include "chrome/browser/ui/webui/chromeos/choose_mobile_network_ui.h"
41#include "chrome/browser/ui/webui/chromeos/enterprise_enrollment_ui.h"
42#include "chrome/browser/ui/webui/chromeos/imageburner_ui.h"
43#include "chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.h"
44#include "chrome/browser/ui/webui/chromeos/mobile_setup_ui.h"
45#include "chrome/browser/ui/webui/chromeos/proxy_settings_ui.h"
46#include "chrome/browser/ui/webui/chromeos/register_page_ui.h"
47#include "chrome/browser/ui/webui/chromeos/sim_unlock_ui.h"
48#include "chrome/browser/ui/webui/chromeos/system_info_ui.h"
49#include "chrome/browser/ui/webui/active_downloads_ui.h"
50#include "chrome/browser/ui/webui/mediaplayer_ui.h"
51#endif
52
53#if defined(TOUCH_UI)
54#include "chrome/browser/ui/webui/keyboard_ui.h"
55#endif
56
57#if defined(TOUCH_UI) && defined(OS_CHROMEOS)
58#include "chrome/browser/ui/webui/chromeos/login/login_ui.h"
59#endif
60
61#if defined(OS_WIN)
62#include "chrome/browser/ui/webui/conflicts_ui.h"
63#endif
64
65namespace {
66
67// A function for creating a new WebUI. The caller owns the return value, which
68// may be NULL (for example, if the URL refers to an non-existent extension).
69typedef WebUI* (*WebUIFactoryFunction)(TabContents* tab_contents,
70                                       const GURL& url);
71
72// Template for defining WebUIFactoryFunction.
73template<class T>
74WebUI* NewWebUI(TabContents* contents, const GURL& url) {
75  return new T(contents);
76}
77
78// Special case for extensions.
79template<>
80WebUI* NewWebUI<ExtensionWebUI>(TabContents* contents, const GURL& url) {
81  // Don't use a WebUI for incognito tabs because we require extensions to run
82  // within a single process.
83  ExtensionService* service = contents->profile()->GetExtensionService();
84  if (service &&
85      service->ExtensionBindingsAllowed(url)) {
86    return new ExtensionWebUI(contents, url);
87  }
88  return NULL;
89}
90
91// Returns a function that can be used to create the right type of WebUI for a
92// tab, based on its URL. Returns NULL if the URL doesn't have WebUI associated
93// with it. Even if the factory function is valid, it may yield a NULL WebUI
94// when invoked for a particular tab - see NewWebUI<ExtensionWebUI>.
95static WebUIFactoryFunction GetWebUIFactoryFunction(Profile* profile,
96                                                    const GURL& url) {
97  if (url.host() == chrome::kChromeUIDialogHost)
98    return &NewWebUI<ConstrainedHtmlUI>;
99
100  ExtensionService* service = profile ? profile->GetExtensionService() : NULL;
101  if (service && service->ExtensionBindingsAllowed(url))
102    return &NewWebUI<ExtensionWebUI>;
103
104  // All platform builds of Chrome will need to have a cloud printing
105  // dialog as backup.  It's just that on Chrome OS, it's the only
106  // print dialog.
107  if (url.host() == chrome::kCloudPrintResourcesHost)
108    return &NewWebUI<ExternalHtmlDialogUI>;
109
110  // This will get called a lot to check all URLs, so do a quick check of other
111  // schemes to filter out most URLs.
112  if (!url.SchemeIs(chrome::kChromeDevToolsScheme) &&
113      !url.SchemeIs(chrome::kChromeInternalScheme) &&
114      !url.SchemeIs(chrome::kChromeUIScheme))
115    return NULL;
116
117  if (url.host() == chrome::kChromeUISyncResourcesHost ||
118      url.host() == chrome::kChromeUIRemotingResourcesHost ||
119      url.host() == chrome::kCloudPrintSetupHost)
120    return &NewWebUI<HtmlDialogUI>;
121
122  // Special case the new tab page. In older versions of Chrome, the new tab
123  // page was hosted at chrome-internal:<blah>. This might be in people's saved
124  // sessions or bookmarks, so we say any URL with that scheme triggers the new
125  // tab page.
126  if (url.host() == chrome::kChromeUINewTabHost ||
127      url.SchemeIs(chrome::kChromeInternalScheme))
128    return &NewWebUI<NewTabUI>;
129
130  // Give about:about a generic Web UI so it can navigate to pages with Web UIs.
131  if (url.spec() == chrome::kChromeUIAboutAboutURL)
132    return &NewWebUI<WebUI>;
133
134  // We must compare hosts only since some of the Web UIs append extra stuff
135  // after the host name.
136  if (url.host() == chrome::kChromeUIBookmarksHost)
137    return &NewWebUI<BookmarksUI>;
138  if (url.host() == chrome::kChromeUIBugReportHost)
139    return &NewWebUI<BugReportUI>;
140  if (url.host() == chrome::kChromeUICrashesHost)
141    return &NewWebUI<CrashesUI>;
142  if (url.host() == chrome::kChromeUIDevToolsHost)
143    return &NewWebUI<DevToolsUI>;
144#if defined(OS_WIN)
145  if (url.host() == chrome::kChromeUIConflictsHost)
146    return &NewWebUI<ConflictsUI>;
147#endif
148  if (url.host() == chrome::kChromeUIDownloadsHost)
149    return &NewWebUI<DownloadsUI>;
150  if (url.host() == chrome::kChromeUITextfieldsHost)
151    return &NewWebUI<TextfieldsUI>;
152  if (url.host() == chrome::kChromeUIExtensionsHost)
153    return &NewWebUI<ExtensionsUI>;
154  if (url.host() == chrome::kChromeUIHistoryHost)
155    return &NewWebUI<HistoryUI>;
156  if (url.host() == chrome::kChromeUIHistory2Host)
157    return &NewWebUI<HistoryUI2>;
158  if (url.host() == chrome::kChromeUIFlagsHost)
159    return &NewWebUI<FlagsUI>;
160#if defined(TOUCH_UI)
161  if (url.host() == chrome::kChromeUIKeyboardHost)
162    return &NewWebUI<KeyboardUI>;
163#endif
164  if (url.host() == chrome::kChromeUIGpuInternalsHost)
165    return &NewWebUI<GpuInternalsUI>;
166  if (url.host() == chrome::kChromeUINetInternalsHost)
167    return &NewWebUI<NetInternalsUI>;
168  if (url.host() == chrome::kChromeUIPluginsHost)
169    return &NewWebUI<PluginsUI>;
170  if (url.host() == chrome::kChromeUISyncInternalsHost)
171    return &NewWebUI<SyncInternalsUI>;
172#if defined(ENABLE_REMOTING)
173  if (url.host() == chrome::kChromeUIRemotingHost) {
174    if (CommandLine::ForCurrentProcess()->HasSwitch(
175        switches::kEnableRemoting)) {
176      return &NewWebUI<RemotingUI>;
177    }
178  }
179#endif
180
181#if defined(OS_CHROMEOS)
182  if (url.host() == chrome::kChromeUIChooseMobileNetworkHost)
183    return &NewWebUI<chromeos::ChooseMobileNetworkUI>;
184  if (url.host() == chrome::kChromeUICollectedCookiesHost ||
185      url.host() == chrome::kChromeUIHttpAuthHost) {
186    return &NewWebUI<ConstrainedHtmlUI>;
187  }
188  if (url.host() == chrome::kChromeUIActiveDownloadsHost)
189    return &NewWebUI<ActiveDownloadsUI>;
190  if (url.host() == chrome::kChromeUIImageBurnerHost)
191    return &NewWebUI<ImageBurnUI>;
192  if (url.host() == chrome::kChromeUIKeyboardOverlayHost)
193    return &NewWebUI<KeyboardOverlayUI>;
194  if (url.host() == chrome::kChromeUIMediaplayerHost)
195    return &NewWebUI<MediaplayerUI>;
196  if (url.host() == chrome::kChromeUIMobileSetupHost)
197    return &NewWebUI<MobileSetupUI>;
198  if (url.host() == chrome::kChromeUIProxySettingsHost)
199    return &NewWebUI<chromeos::ProxySettingsUI>;
200  if (url.host() == chrome::kChromeUIRegisterPageHost)
201    return &NewWebUI<RegisterPageUI>;
202  if (url.host() == chrome::kChromeUISettingsHost)
203    return &NewWebUI<OptionsUI>;
204  if (url.host() == chrome::kChromeUISimUnlockHost)
205    return &NewWebUI<chromeos::SimUnlockUI>;
206  if (url.host() == chrome::kChromeUISystemInfoHost)
207    return &NewWebUI<SystemInfoUI>;
208  if (url.host() == chrome::kChromeUIEnterpriseEnrollmentHost)
209    return &NewWebUI<chromeos::EnterpriseEnrollmentUI>;
210#else
211  if (url.host() == chrome::kChromeUISettingsHost)
212    return &NewWebUI<OptionsUI>;
213  if (url.host() == chrome::kChromeUIPrintHost) {
214    if (CommandLine::ForCurrentProcess()->HasSwitch(
215        switches::kEnablePrintPreview)) {
216      return &NewWebUI<PrintPreviewUI>;
217    }
218  }
219#endif  // defined(OS_CHROMEOS)
220
221#if defined(TOUCH_UI) && defined(OS_CHROMEOS)
222  if (url.host() == chrome::kChromeUILoginHost)
223    return &NewWebUI<chromeos::LoginUI>;
224#endif
225
226  if (url.spec() == chrome::kChromeUIConstrainedHTMLTestURL)
227    return &NewWebUI<ConstrainedHtmlUI>;
228
229  return NULL;
230}
231
232}  // namespace
233
234WebUI::TypeID ChromeWebUIFactory::GetWebUIType(Profile* profile,
235                                               const GURL& url) const {
236  WebUIFactoryFunction function = GetWebUIFactoryFunction(profile, url);
237  return function ? reinterpret_cast<WebUI::TypeID>(function) : WebUI::kNoWebUI;
238}
239
240bool ChromeWebUIFactory::UseWebUIForURL(Profile* profile,
241                                        const GURL& url) const {
242  return GetWebUIType(profile, url) != WebUI::kNoWebUI;
243}
244
245bool ChromeWebUIFactory::HasWebUIScheme(const GURL& url) const {
246  return url.SchemeIs(chrome::kChromeDevToolsScheme) ||
247         url.SchemeIs(chrome::kChromeInternalScheme) ||
248         url.SchemeIs(chrome::kChromeUIScheme) ||
249         url.SchemeIs(chrome::kExtensionScheme);
250}
251
252bool ChromeWebUIFactory::IsURLAcceptableForWebUI(
253    Profile* profile,
254    const GURL& url) const {
255  return UseWebUIForURL(profile, url) ||
256      // javacsript: URLs are allowed to run in Web UI pages
257      url.SchemeIs(chrome::kJavaScriptScheme) ||
258      // It's possible to load about:blank in a Web UI renderer.
259      // See http://crbug.com/42547
260      url.spec() == chrome::kAboutBlankURL ||
261      // about:crash, about:kill, about:hang, and about:shorthang are allowed.
262      url.spec() == chrome::kAboutCrashURL ||
263      url.spec() == chrome::kAboutKillURL ||
264      url.spec() == chrome::kAboutHangURL ||
265      url.spec() == chrome::kAboutShorthangURL;
266}
267
268WebUI* ChromeWebUIFactory::CreateWebUIForURL(
269    TabContents* tab_contents,
270    const GURL& url) const {
271  WebUIFactoryFunction function = GetWebUIFactoryFunction(
272      tab_contents->profile(), url);
273  if (!function)
274    return NULL;
275  return (*function)(tab_contents, url);
276}
277
278void ChromeWebUIFactory::GetFaviconForURL(
279    Profile* profile,
280    FaviconService::GetFaviconRequest* request,
281    const GURL& page_url) const {
282  // All extensions but the bookmark manager get their favicon from the icons
283  // part of the manifest.
284  if (page_url.SchemeIs(chrome::kExtensionScheme) &&
285      page_url.host() != extension_misc::kBookmarkManagerId) {
286    ExtensionWebUI::GetFaviconForURL(profile, request, page_url);
287  } else {
288    history::FaviconData favicon;
289    favicon.image_data = scoped_refptr<RefCountedMemory>(
290        GetFaviconResourceBytes(page_url));
291    favicon.known_icon = favicon.image_data.get() != NULL &&
292                             favicon.image_data->size() > 0;
293    request->ForwardResultAsync(
294        FaviconService::FaviconDataCallback::TupleType(request->handle(),
295                                                       favicon));
296  }
297}
298
299// static
300ChromeWebUIFactory* ChromeWebUIFactory::GetInstance() {
301  return Singleton<ChromeWebUIFactory>::get();
302}
303
304ChromeWebUIFactory::ChromeWebUIFactory() {
305}
306
307ChromeWebUIFactory::~ChromeWebUIFactory() {
308}
309
310RefCountedMemory* ChromeWebUIFactory::GetFaviconResourceBytes(
311    const GURL& page_url) const  {
312  // The bookmark manager is a chrome extension, so we have to check for it
313  // before we check for extension scheme.
314  if (page_url.host() == extension_misc::kBookmarkManagerId)
315    return BookmarksUI::GetFaviconResourceBytes();
316
317  // The extension scheme is handled in GetFaviconForURL.
318  if (page_url.SchemeIs(chrome::kExtensionScheme)) {
319    NOTREACHED();
320    return NULL;
321  }
322
323  if (!HasWebUIScheme(page_url))
324    return NULL;
325
326#if defined(OS_WIN)
327  if (page_url.host() == chrome::kChromeUIConflictsHost)
328    return ConflictsUI::GetFaviconResourceBytes();
329#endif
330
331  if (page_url.host() == chrome::kChromeUICrashesHost)
332    return CrashesUI::GetFaviconResourceBytes();
333
334  if (page_url.host() == chrome::kChromeUIDownloadsHost)
335    return DownloadsUI::GetFaviconResourceBytes();
336
337  if (page_url.host() == chrome::kChromeUIExtensionsHost)
338    return ExtensionsUI::GetFaviconResourceBytes();
339
340  if (page_url.host() == chrome::kChromeUIHistoryHost)
341    return HistoryUI::GetFaviconResourceBytes();
342
343  if (page_url.host() == chrome::kChromeUIHistory2Host)
344    return HistoryUI2::GetFaviconResourceBytes();
345
346  if (page_url.host() == chrome::kChromeUIFlagsHost)
347    return FlagsUI::GetFaviconResourceBytes();
348
349  if (page_url.host() == chrome::kChromeUISettingsHost)
350    return OptionsUI::GetFaviconResourceBytes();
351
352  if (page_url.host() == chrome::kChromeUIPluginsHost)
353    return PluginsUI::GetFaviconResourceBytes();
354
355#if defined(ENABLE_REMOTING)
356  if (page_url.host() == chrome::kChromeUIRemotingHost)
357    return RemotingUI::GetFaviconResourceBytes();
358#endif
359
360  return NULL;
361}
362