1// Copyright (c) 2012 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/browser_about_handler.h"
6
7#include <string>
8
9#include "base/logging.h"
10#include "base/strings/string_util.h"
11#include "chrome/browser/lifetime/application_lifetime.h"
12#include "chrome/browser/ui/browser_dialogs.h"
13#include "chrome/common/chrome_switches.h"
14#include "chrome/common/url_constants.h"
15#include "components/url_fixer/url_fixer.h"
16
17bool WillHandleBrowserAboutURL(GURL* url,
18                               content::BrowserContext* browser_context) {
19  // TODO(msw): Eliminate "about:*" constants and literals from code and tests,
20  //            then hopefully we can remove this forced fixup.
21  *url = url_fixer::FixupURL(url->possibly_invalid_spec(), std::string());
22
23  // Check that about: URLs are fixed up to chrome: by url_fixer::FixupURL.
24  DCHECK((*url == GURL(url::kAboutBlankURL)) ||
25         !url->SchemeIs(url::kAboutScheme));
26
27  // Only handle chrome://foo/, url_fixer::FixupURL translates about:foo.
28  if (!url->SchemeIs(content::kChromeUIScheme))
29    return false;
30
31  std::string host(url->host());
32  std::string path;
33  // Replace about with chrome-urls.
34  if (host == chrome::kChromeUIAboutHost)
35    host = chrome::kChromeUIChromeURLsHost;
36  // Replace cache with view-http-cache.
37  if (host == chrome::kChromeUICacheHost) {
38    host = content::kChromeUINetworkViewCacheHost;
39  // Replace sync with sync-internals (for legacy reasons).
40  } else if (host == chrome::kChromeUISyncHost) {
41    host = chrome::kChromeUISyncInternalsHost;
42  // Redirect chrome://extensions.
43  } else if (host == chrome::kChromeUIExtensionsHost) {
44    host = chrome::kChromeUIUberHost;
45    path = chrome::kChromeUIExtensionsHost + url->path();
46  // Redirect chrome://settings/extensions (legacy URL).
47  } else if (host == chrome::kChromeUISettingsHost &&
48      url->path() == std::string("/") + chrome::kExtensionsSubPage) {
49    host = chrome::kChromeUIUberHost;
50    path = chrome::kChromeUIExtensionsHost;
51  // Redirect chrome://history.
52  } else if (host == chrome::kChromeUIHistoryHost) {
53#if defined(OS_ANDROID)
54    // On Android, redirect directly to chrome://history-frame since
55    // uber page is unsupported.
56    host = chrome::kChromeUIHistoryFrameHost;
57#else
58    host = chrome::kChromeUIUberHost;
59    path = chrome::kChromeUIHistoryHost + url->path();
60#endif
61  // Redirect chrome://settings
62  } else if (host == chrome::kChromeUISettingsHost) {
63    if (::switches::AboutInSettingsEnabled()) {
64      host = chrome::kChromeUISettingsFrameHost;
65    } else {
66      host = chrome::kChromeUIUberHost;
67      path = chrome::kChromeUISettingsHost + url->path();
68    }
69  // Redirect chrome://help
70  } else if (host == chrome::kChromeUIHelpHost) {
71    if (::switches::AboutInSettingsEnabled()) {
72      host = chrome::kChromeUISettingsFrameHost;
73      if (url->path().empty() || url->path() == "/")
74        path = chrome::kChromeUIHelpHost;
75    } else {
76      host = chrome::kChromeUIUberHost;
77      path = chrome::kChromeUIHelpHost + url->path();
78    }
79  }
80
81  GURL::Replacements replacements;
82  replacements.SetHostStr(host);
83  if (!path.empty())
84    replacements.SetPathStr(path);
85  *url = url->ReplaceComponents(replacements);
86
87  // Having re-written the URL, make the chrome: handler process it.
88  return false;
89}
90
91bool HandleNonNavigationAboutURL(const GURL& url) {
92  const std::string spec(url.spec());
93
94  if (LowerCaseEqualsASCII(spec, chrome::kChromeUIRestartURL)) {
95    // Call AttemptRestart after chrome::Navigate() completes to avoid access of
96    // gtk objects after they are destroyed by BrowserWindowGtk::Close().
97    base::MessageLoop::current()->PostTask(FROM_HERE,
98        base::Bind(&chrome::AttemptRestart));
99    return true;
100  } else if (LowerCaseEqualsASCII(spec, chrome::kChromeUIQuitURL)) {
101    base::MessageLoop::current()->PostTask(FROM_HERE,
102        base::Bind(&chrome::AttemptExit));
103    return true;
104  }
105
106  // chrome://ipc/ is currently buggy, so we disable it for official builds.
107#if !defined(OFFICIAL_BUILD)
108
109#if (defined(OS_MACOSX) || defined(OS_WIN)) && defined(IPC_MESSAGE_LOG_ENABLED)
110  if (LowerCaseEqualsASCII(spec, chrome::kChromeUIIPCURL)) {
111    // Run the dialog. This will re-use the existing one if it's already up.
112    chrome::ShowAboutIPCDialog();
113    return true;
114  }
115#endif
116
117#endif  // OFFICIAL_BUILD
118
119  return false;
120}
121