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