1 // Copyright 2014 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.
8 #include "base/at_exit.h"
9 #include "base/base_paths.h"
10 #include "base/basictypes.h"
11 #include "base/command_line.h"
12 #include "base/i18n/streaming_utf8_validator.h"
13 #include "base/json/json_reader.h"
14 #include "base/logging.h"
15 #include "base/logging_win.h"
16 #include "base/path_service.h"
17 #include "base/process/launch.h"
18 #include "base/strings/sys_string_conversions.h"
19 #include "base/values.h"
20 #include "chrome/app_installer/win/app_installer_util.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/chrome_version_info.h"
23 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
24 #include "chrome/installer/util/util_constants.h"
25 #include "content/public/common/user_agent.h"
27 namespace app_installer
{
31 // Log provider UUID. Required for logging to Sawbuck.
32 // {d82c3b59-bacd-4625-8282-4d570c4dad12}
33 DEFINE_GUID(kAppInstallerLogProvider
,
37 0x82, 0x82, 0x4d, 0x57, 0x0c, 0x4d, 0xad, 0x12);
39 const wchar_t kChromeServer
[] = L
"chrome.google.com";
41 const wchar_t kInlineInstallDetail
[] = L
"/webstore/inlineinstall/detail/";
46 int WINAPI
wWinMain(HINSTANCE instance
,
47 HINSTANCE prev_instance
,
48 wchar_t* command_line
,
50 base::AtExitManager exit_manager
;
51 base::CommandLine::Init(0, NULL
);
52 logging::LogEventProvider::Initialize(kAppInstallerLogProvider
);
53 logging::LoggingSettings settings
;
54 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
55 logging::InitLogging(settings
);
58 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
60 const char* sxs
= installer::switches::kChromeSxS
;
61 // --chrome-sxs on the command line takes precedence over chrome-sxs in the
63 bool is_canary
= base::CommandLine::ForCurrentProcess()->HasSwitch(sxs
);
65 // --app-id on the command line inhibits tag parsing altogether.
67 base::FilePath current_exe
;
68 if (!PathService::Get(base::FILE_EXE
, ¤t_exe
))
69 return COULD_NOT_GET_FILE_PATH
;
71 // Get the tag added by dl.google.com. Note that this is passed in via URL
72 // parameters when requesting a file to download, so it must be validated
74 std::string tag
= GetTag(current_exe
);
76 return COULD_NOT_READ_TAG
;
78 DVLOG(1) << "Tag: " << tag
;
80 std::map
<std::string
, std::string
> parsed_pairs
;
81 if (!ParseTag(tag
, &parsed_pairs
))
82 return COULD_NOT_PARSE_TAG
;
84 auto result
= parsed_pairs
.find(switches::kAppId
);
85 if (result
!= parsed_pairs
.end())
86 app_id
= result
->second
;
89 result
= parsed_pairs
.find(sxs
);
90 is_canary
= result
!= parsed_pairs
.end() && result
->second
== "1";
94 if (!IsValidAppId(app_id
))
95 return INVALID_APP_ID
;
97 // Get the inline install data for this app. We need to set the user agent
98 // string to be Chrome's, otherwise webstore will serve a different response
99 // (since inline installs don't work on non-Chrome).
100 std::vector
<uint8_t> response_data
;
101 if (!FetchUrl(base::SysUTF8ToWide(content::BuildUserAgentFromProduct(
102 chrome::VersionInfo().ProductNameAndVersionForUserAgent())),
104 kInlineInstallDetail
+ base::SysUTF8ToWide(app_id
),
106 response_data
.empty()) {
107 return COULD_NOT_FETCH_INLINE_INSTALL_DATA
;
110 // Check that the response is valid UTF-8.
111 std::string
inline_install_json(response_data
.begin(), response_data
.end());
112 if (!base::StreamingUtf8Validator::Validate(inline_install_json
))
113 return COULD_NOT_PARSE_INLINE_INSTALL_DATA
;
115 // Parse the data to check it's valid JSON. The download page will just eval
117 base::JSONReader json_reader
;
118 scoped_ptr
<base::Value
> inline_install_data(
119 json_reader
.ReadToValue(inline_install_json
));
120 if (!inline_install_data
) {
121 LOG(ERROR
) << json_reader
.GetErrorMessage();
122 return COULD_NOT_PARSE_INLINE_INSTALL_DATA
;
125 base::FilePath chrome_path
=
126 chrome_launcher_support::GetAnyChromePath(is_canary
);
127 // If none found, show EULA, download, and install Chrome.
128 if (chrome_path
.empty()) {
129 ExitCode get_chrome_result
= GetChrome(is_canary
, inline_install_json
);
130 if (get_chrome_result
!= SUCCESS
)
131 return get_chrome_result
;
133 chrome_path
= chrome_launcher_support::GetAnyChromePath(is_canary
);
134 if (chrome_path
.empty())
135 return COULD_NOT_FIND_CHROME
;
138 base::CommandLine
cmd(chrome_path
);
139 cmd
.AppendSwitchASCII(kInstallChromeApp
, app_id
);
140 DVLOG(1) << "Install command: " << cmd
.GetCommandLineString();
141 bool launched
= base::LaunchProcess(cmd
, base::LaunchOptions()).IsValid();
142 DVLOG(1) << "Launch " << (launched
? "success." : "failed.");
147 } // namespace app_installer