summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/shell_integration.cc41
-rw-r--r--chrome/browser/shell_integration.h15
-rw-r--r--chrome/browser/shell_integration_linux.cc70
-rw-r--r--chrome/browser/shell_integration_unittest.cc22
-rw-r--r--chrome/browser/web_applications/web_app.cc19
5 files changed, 109 insertions, 58 deletions
diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc
index cb5fde3..0b66d07 100644
--- a/chrome/browser/shell_integration.cc
+++ b/chrome/browser/shell_integration.cc
@@ -23,56 +23,41 @@ ShellIntegration::ShortcutInfo::ShortcutInfo()
ShellIntegration::ShortcutInfo::~ShortcutInfo() {}
-std::string ShellIntegration::GetCommandLineArgumentsCommon(
+// static
+CommandLine ShellIntegration::CommandLineArgsForLauncher(
const GURL& url,
const std::string& extension_app_id) {
- const CommandLine cmd = *CommandLine::ForCurrentProcess();
- std::wstring arguments_w;
+ const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+ CommandLine new_cmd_line(CommandLine::NO_PROGRAM);
// Use the same UserDataDir for new launches that we currently have set.
- FilePath user_data_dir = cmd.GetSwitchValuePath(switches::kUserDataDir);
- if (!user_data_dir.value().empty()) {
+ FilePath user_data_dir = cmd_line.GetSwitchValuePath(switches::kUserDataDir);
+ if (!user_data_dir.empty()) {
// Make sure user_data_dir is an absolute path.
if (file_util::AbsolutePath(&user_data_dir) &&
file_util::PathExists(user_data_dir)) {
- // TODO: This is wrong in pathological quoting scenarios; we shouldn't be
- // passing around command lines as strings at all.
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kUserDataDir) +
- L"=\"" + user_data_dir.ToWStringHack() + L"\" ";
+ new_cmd_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
}
}
#if defined(OS_CHROMEOS)
- FilePath profile = cmd.GetSwitchValuePath(switches::kLoginProfile);
- if (!profile.empty()) {
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kLoginProfile) +
- L"=\"" + profile.ToWStringHack() + L"\" ";
- }
+ FilePath profile = cmd_line.GetSwitchValuePath(switches::kLoginProfile);
+ if (!profile.empty())
+ new_cmd_line.AppendSwitchPath(switches::kLoginProfile, profile);
#endif
// If |extension_app_id| is present, we use the kAppId switch rather than
// the kApp switch (the launch url will be read from the extension app
// during launch.
if (!extension_app_id.empty()) {
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kAppId) +
- L"=\"" + ASCIIToWide(extension_app_id) + L"\"";
+ new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
} else {
// Use '--app=url' instead of just 'url' to launch the browser with minimal
// chrome.
// Note: Do not change this flag! Old Gears shortcuts will break if you do!
- std::string url_string = url.spec();
- ReplaceSubstringsAfterOffset(&url_string, 0, "\\", "%5C");
- ReplaceSubstringsAfterOffset(&url_string, 0, "\"", "%22");
- ReplaceSubstringsAfterOffset(&url_string, 0, ";", "%3B");
- ReplaceSubstringsAfterOffset(&url_string, 0, "$", "%24");
-#if defined(OS_WIN) // Windows shortcuts can't escape % so we use \x instead.
- ReplaceSubstringsAfterOffset(&url_string, 0, "%", "\\x");
-#endif
- std::wstring url_w = UTF8ToWide(url_string);
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kApp) +
- L"=\"" + url_w + L"\"";
+ new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
}
- return WideToUTF8(arguments_w);
+ return new_cmd_line;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 450c11b..0df0ed7 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -14,6 +14,7 @@
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkBitmap.h"
+class CommandLine;
class FilePath;
class PrefService;
@@ -72,14 +73,12 @@ class ShellIntegration {
bool create_in_quick_launch_bar;
};
- // Re-implementation of chrome_plugin_utill::CPB_GetCommandLineArgumentsCommon
- // which is deprecated. If |extension_app_id| is non-empty, an arguments
- // string is created using the kAppId=<id> flag. Otherwise, the kApp=<url> is
- // used.
- // NOTE: This function is dangerous, do not use! You cannot treat
- // command lines as plain strings as there are metacharacters.
- // TODO(evanm): remove it.
- static std::string GetCommandLineArgumentsCommon(
+ // Set up command line arguments for launching a URL or an app.
+ // The new command line reuses the current process's user data directory (and
+ // login profile, for ChromeOS).
+ // If |extension_app_id| is non-empty, the arguments use kAppId=<id>.
+ // Otherwise, kApp=<url> is used.
+ static CommandLine CommandLineArgsForLauncher(
const GURL& url,
const std::string& extension_app_id);
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 5e8a3f3..c4fe208 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -175,6 +175,52 @@ void CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
LaunchXdgUtility(argv);
}
+// Quote a string such that it appears as one verbatim argument for the Exec
+// key in a desktop file.
+std::string QuoteArgForDesktopFileExec(const std::string& arg) {
+ // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
+
+ // Quoting is only necessary if the argument has a reserved character.
+ if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos)
+ return arg; // No quoting necessary.
+
+ std::string quoted = "\"";
+ for (size_t i = 0; i < arg.size(); ++i) {
+ // Note that the set of backslashed characters is smaller than the
+ // set of reserved characters.
+ switch (arg[i]) {
+ case '"':
+ case '`':
+ case '$':
+ case '\\':
+ quoted += '\\';
+ break;
+ }
+ quoted += arg[i];
+ }
+ quoted += '"';
+
+ return quoted;
+}
+
+// Escape a string if needed for the right side of a Key=Value
+// construct in a desktop file. (Note that for Exec= lines this
+// should be used in conjunction with QuoteArgForDesktopFileExec,
+// possibly escaping a backslash twice.)
+std::string EscapeStringForDesktopFile(const std::string& arg) {
+ // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s03.html
+ if (arg.find('\\') == std::string::npos)
+ return arg;
+
+ std::string escaped;
+ for (size_t i = 0; i < arg.size(); ++i) {
+ if (arg[i] == '\\')
+ escaped += '\\';
+ escaped += arg[i];
+ }
+ return escaped;
+}
+
} // namespace
// static
@@ -328,13 +374,25 @@ std::string ShellIntegration::GetDesktopFileContents(
std::string exec_path = tokenizer.token().substr(5);
StringTokenizer exec_tokenizer(exec_path, " ");
std::string final_path;
- while (exec_tokenizer.GetNext()) {
- if (exec_tokenizer.token() != "%U")
- final_path += exec_tokenizer.token() + " ";
+ while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") {
+ if (!final_path.empty())
+ final_path += " ";
+ final_path += exec_tokenizer.token();
+ }
+ CommandLine cmd_line =
+ ShellIntegration::CommandLineArgsForLauncher(url, extension_id);
+ const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches();
+ for (CommandLine::SwitchMap::const_iterator i = switch_map.begin();
+ i != switch_map.end(); ++i) {
+ if (i->second.empty()) {
+ final_path += " --" + i->first;
+ } else {
+ final_path += " " + QuoteArgForDesktopFileExec("--" + i->first +
+ "=" + i->second);
+ }
}
- std::string switches =
- ShellIntegration::GetCommandLineArgumentsCommon(url, extension_id);
- output_buffer += std::string("Exec=") + final_path + switches + "\n";
+ output_buffer += std::string("Exec=") +
+ EscapeStringForDesktopFile(final_path) + "\n";
} else if (tokenizer.token().substr(0, 5) == "Name=") {
std::string final_title = UTF16ToUTF8(title);
// Make sure no endline characters can slip in and possibly introduce
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index 9a86b58..1a6b9795 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -191,7 +191,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"Version=1.0\n"
"Encoding=UTF-8\n"
"Name=GMail\n"
- "Exec=/opt/google/chrome/google-chrome --app=\"http://gmail.com/\"\n"
+ "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
"Terminal=false\n"
"Icon=chrome-http__gmail.com\n"
"Type=Application\n"
@@ -209,7 +209,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=GMail\n"
- "Exec=/opt/google/chrome/google-chrome --app=\"http://gmail.com/\"\n"
+ "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
},
// Make sure i18n-ed comments are removed.
@@ -223,7 +223,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=GMail\n"
- "Exec=/opt/google/chrome/google-chrome --app=\"http://gmail.com/\"\n"
+ "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
},
// Make sure that empty icons are replaced by the chrome icon.
@@ -238,7 +238,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=GMail\n"
- "Exec=/opt/google/chrome/google-chrome --app=\"http://gmail.com/\"\n"
+ "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
"Icon=/opt/google/chrome/product_logo_48.png\n"
},
@@ -253,7 +253,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=http://evil.com/evil%20--join-the-b0tnet\n"
"Exec=/opt/google/chrome/google-chrome "
- "--app=\"http://evil.com/evil%20--join-the-b0tnet\"\n"
+ "--app=http://evil.com/evil%20--join-the-b0tnet\n"
},
{ "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
"Innocent Title",
@@ -265,8 +265,11 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=Innocent Title\n"
"Exec=/opt/google/chrome/google-chrome "
- "--app=\"http://evil.com/evil%3B%20rm%20-rf%20/%3B%20%22%3B%20rm%20"
- "-rf%20%24HOME%20%3Eownz0red\"\n"
+ "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
+ // Note: $ is escaped as \$ within an arg to Exec, and then
+ // the \ is escaped as \\ as all strings in a Desktop file should
+ // be; finally, \\ becomes \\\\ when represented in a C++ string!
+ "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
},
{ "http://evil.com/evil | cat `echo ownz0red` >/dev/null",
"Innocent Title",
@@ -278,11 +281,12 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
"#!/usr/bin/env xdg-open\n"
"Name=Innocent Title\n"
"Exec=/opt/google/chrome/google-chrome "
- "--app=\"http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
- "%60%20%3E/dev/null\"\n"
+ "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
+ "%60%20%3E/dev/null\n"
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
+ SCOPED_TRACE(i);
EXPECT_EQ(test_cases[i].expected_output,
ShellIntegration::GetDesktopFileContents(
test_cases[i].template_contents,
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 2e77928..8cd0028 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -14,6 +14,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/md5.h"
#include "base/message_loop.h"
@@ -93,8 +94,8 @@ FilePath GetSanitizedFileName(const string16& name) {
// Returns relative directory of given web app url.
FilePath GetWebAppDir(const ShellIntegration::ShortcutInfo& info) {
if (!info.extension_id.empty()) {
- std::string app_name = web_app::GenerateApplicationNameFromExtensionId(
- info.extension_id);
+ std::string app_name =
+ web_app::GenerateApplicationNameFromExtensionId(info.extension_id);
#if defined(OS_WIN)
return FilePath(UTF8ToWide(app_name));
#elif defined(OS_POSIX)
@@ -378,10 +379,14 @@ bool CreateShortcutTask::CreateShortcut() {
// Working directory.
FilePath chrome_folder = chrome_exe.DirName();
- std::string switches =
- ShellIntegration::GetCommandLineArgumentsCommon(shortcut_info_.url,
- shortcut_info_.extension_id);
- std::wstring wide_switchs(UTF8ToWide(switches));
+ CommandLine cmd_line =
+ ShellIntegration::CommandLineArgsForLauncher(shortcut_info_.url,
+ shortcut_info_.extension_id);
+ // TODO(evan): we rely on the fact that command_line_string() is
+ // properly quoted for a Windows command line. The method on
+ // CommandLine should probably be renamed to better reflect that
+ // fact.
+ std::wstring wide_switches(cmd_line.command_line_string());
// Sanitize description
if (shortcut_info_.description.length() >= MAX_PATH)
@@ -417,7 +422,7 @@ bool CreateShortcutTask::CreateShortcut() {
success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(),
shortcut_file.value().c_str(),
chrome_folder.value().c_str(),
- wide_switchs.c_str(),
+ wide_switches.c_str(),
shortcut_info_.description.c_str(),
icon_file.value().c_str(),
0,