web_app.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/web_applications/web_app.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/file_util.h"
10#include "base/i18n/file_util_icu.h"
11#include "base/string_util.h"
12#include "base/threading/thread.h"
13#include "base/utf_string_conversions.h"
14#include "chrome/common/extensions/extension.h"
15#include "chrome/common/chrome_constants.h"
16#include "chrome/common/url_constants.h"
17#include "content/public/browser/browser_thread.h"
18
19using content::BrowserThread;
20
21namespace {
22
23#if defined(TOOLKIT_VIEWS)
24// Predicator for sorting images from largest to smallest.
25bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
26                  const WebApplicationInfo::IconInfo& right) {
27  return left.width < right.width;
28}
29#endif
30
31void DeleteShortcutsOnFileThread(
32    const ShellIntegration::ShortcutInfo& shortcut_info) {
33  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
34
35  FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
36      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
37  return web_app::internals::DeletePlatformShortcuts(
38      shortcut_data_dir, shortcut_info);
39}
40
41void UpdateShortcutsOnFileThread(
42    const ShellIntegration::ShortcutInfo& shortcut_info) {
43  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
44
45  FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
46      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
47  return web_app::internals::UpdatePlatformShortcuts(
48      shortcut_data_dir, shortcut_info);
49}
50
51}  // namespace
52
53namespace web_app {
54
55// The following string is used to build the directory name for
56// shortcuts to chrome applications (the kind which are installed
57// from a CRX).  Application shortcuts to URLs use the {host}_{path}
58// for the name of this directory.  Hosts can't include an underscore.
59// By starting this string with an underscore, we ensure that there
60// are no naming conflicts.
61static const char* kCrxAppPrefix = "_crx_";
62
63namespace internals {
64
65FilePath GetSanitizedFileName(const string16& name) {
66#if defined(OS_WIN)
67  string16 file_name = name;
68#else
69  std::string file_name = UTF16ToUTF8(name);
70#endif
71  file_util::ReplaceIllegalCharactersInPath(&file_name, '_');
72  return FilePath(file_name);
73}
74
75}  // namespace internals
76
77FilePath GetWebAppDataDirectory(const FilePath& profile_path,
78                                const std::string& extension_id,
79                                const GURL& url) {
80  DCHECK(!profile_path.empty());
81  FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
82
83  if (!extension_id.empty()) {
84    return app_data_dir.AppendASCII(
85        GenerateApplicationNameFromExtensionId(extension_id));
86  }
87
88  std::string host(url.host());
89  std::string scheme(url.has_scheme() ? url.scheme() : "http");
90  std::string port(url.has_port() ? url.port() : "80");
91  std::string scheme_port(scheme + "_" + port);
92
93#if defined(OS_WIN)
94  FilePath::StringType host_path(UTF8ToUTF16(host));
95  FilePath::StringType scheme_port_path(UTF8ToUTF16(scheme_port));
96#elif defined(OS_POSIX)
97  FilePath::StringType host_path(host);
98  FilePath::StringType scheme_port_path(scheme_port);
99#endif
100
101  return app_data_dir.Append(host_path).Append(scheme_port_path);
102}
103
104FilePath GetWebAppDataDirectory(const FilePath& profile_path,
105                                const extensions::Extension& extension) {
106  return GetWebAppDataDirectory(
107      profile_path, extension.id(), GURL(extension.launch_web_url()));
108}
109
110std::string GenerateApplicationNameFromInfo(
111    const ShellIntegration::ShortcutInfo& shortcut_info) {
112  if (!shortcut_info.extension_id.empty()) {
113    return web_app::GenerateApplicationNameFromExtensionId(
114        shortcut_info.extension_id);
115  } else {
116    return web_app::GenerateApplicationNameFromURL(
117        shortcut_info.url);
118  }
119}
120
121std::string GenerateApplicationNameFromURL(const GURL& url) {
122  std::string t;
123  t.append(url.host());
124  t.append("_");
125  t.append(url.path());
126  return t;
127}
128
129std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
130  std::string t(web_app::kCrxAppPrefix);
131  t.append(id);
132  return t;
133}
134
135std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
136  std::string prefix(kCrxAppPrefix);
137  if (app_name.substr(0, prefix.length()) != prefix)
138    return std::string();
139  return app_name.substr(prefix.length());
140}
141
142void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
143  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144
145  BrowserThread::PostTask(
146      BrowserThread::FILE,
147      FROM_HERE,
148      base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
149                 shortcut_info));
150}
151
152void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
153  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
154
155  BrowserThread::PostTask(
156      BrowserThread::FILE,
157      FROM_HERE,
158      base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
159}
160
161void UpdateAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
162  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163
164  BrowserThread::PostTask(
165      BrowserThread::FILE,
166      FROM_HERE,
167      base::Bind(&UpdateShortcutsOnFileThread, shortcut_info));
168}
169
170bool CreateShortcutsOnFileThread(
171    const ShellIntegration::ShortcutInfo& shortcut_info) {
172  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
173
174  FilePath shortcut_data_dir = GetWebAppDataDirectory(
175      shortcut_info.profile_path, shortcut_info.extension_id,
176      shortcut_info.url);
177  return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info);
178}
179
180bool IsValidUrl(const GURL& url) {
181  static const char* const kValidUrlSchemes[] = {
182      chrome::kFileScheme,
183      chrome::kFileSystemScheme,
184      chrome::kFtpScheme,
185      chrome::kHttpScheme,
186      chrome::kHttpsScheme,
187      chrome::kExtensionScheme,
188  };
189
190  for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
191    if (url.SchemeIs(kValidUrlSchemes[i]))
192      return true;
193  }
194
195  return false;
196}
197
198#if defined(TOOLKIT_VIEWS)
199void GetIconsInfo(const WebApplicationInfo& app_info,
200                  IconInfoList* icons) {
201  DCHECK(icons);
202
203  icons->clear();
204  for (size_t i = 0; i < app_info.icons.size(); ++i) {
205    // We only take square shaped icons (i.e. width == height).
206    if (app_info.icons[i].width == app_info.icons[i].height) {
207      icons->push_back(app_info.icons[i]);
208    }
209  }
210
211  std::sort(icons->begin(), icons->end(), &IconPrecedes);
212}
213#endif
214
215#if defined(TOOLKIT_GTK)
216std::string GetWMClassFromAppName(std::string app_name) {
217  file_util::ReplaceIllegalCharactersInPath(&app_name, '_');
218  TrimString(app_name, "_", &app_name);
219  return app_name;
220}
221#endif
222
223}  // namespace web_app
224