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/util/util_constants.h"
24 #include "content/public/common/user_agent.h"
26 namespace app_installer
{
30 // Log provider UUID. Required for logging to Sawbuck.
31 // {d82c3b59-bacd-4625-8282-4d570c4dad12}
32 DEFINE_GUID(kAppInstallerLogProvider
,
36 0x82, 0x82, 0x4d, 0x57, 0x0c, 0x4d, 0xad, 0x12);
38 const wchar_t kChromeServer
[] = L
"chrome.google.com";
40 const wchar_t kInlineInstallDetail
[] = L
"/webstore/inlineinstall/detail/";
45 int WINAPI
wWinMain(HINSTANCE instance
,
46 HINSTANCE prev_instance
,
47 wchar_t* command_line
,
49 base::AtExitManager exit_manager
;
50 base::CommandLine::Init(0, NULL
);
51 logging::LogEventProvider::Initialize(kAppInstallerLogProvider
);
52 logging::LoggingSettings settings
;
53 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
54 logging::InitLogging(settings
);
57 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
59 const char* sxs
= installer::switches::kChromeSxS
;
60 // --chrome-sxs on the command line takes precedence over chrome-sxs in the
62 bool is_canary
= base::CommandLine::ForCurrentProcess()->HasSwitch(sxs
);
64 // --app-id on the command line inhibits tag parsing altogether.
66 base::FilePath current_exe
;
67 if (!PathService::Get(base::FILE_EXE
, ¤t_exe
))
68 return COULD_NOT_GET_FILE_PATH
;
70 // Get the tag added by dl.google.com. Note that this is passed in via URL
71 // parameters when requesting a file to download, so it must be validated
73 std::string tag
= GetTag(current_exe
);
75 return COULD_NOT_READ_TAG
;
77 DVLOG(1) << "Tag: " << tag
;
79 std::map
<std::string
, std::string
> parsed_pairs
;
80 if (!ParseTag(tag
, &parsed_pairs
))
81 return COULD_NOT_PARSE_TAG
;
83 auto result
= parsed_pairs
.find(switches::kAppId
);
84 if (result
!= parsed_pairs
.end())
85 app_id
= result
->second
;
88 result
= parsed_pairs
.find(sxs
);
89 is_canary
= result
!= parsed_pairs
.end() && result
->second
== "1";
93 if (!IsValidAppId(app_id
))
94 return INVALID_APP_ID
;
96 // Get the inline install data for this app. We need to set the user agent
97 // string to be Chrome's, otherwise webstore will serve a different response
98 // (since inline installs don't work on non-Chrome).
99 std::vector
<uint8_t> response_data
;
100 if (!FetchUrl(base::SysUTF8ToWide(content::BuildUserAgentFromProduct(
101 chrome::VersionInfo().ProductNameAndVersionForUserAgent())),
103 kInlineInstallDetail
+ base::SysUTF8ToWide(app_id
),
105 response_data
.empty()) {
106 return COULD_NOT_FETCH_INLINE_INSTALL_DATA
;
109 // Check that the response is valid UTF-8.
110 std::string
inline_install_json(response_data
.begin(), response_data
.end());
111 if (!base::StreamingUtf8Validator::Validate(inline_install_json
))
112 return COULD_NOT_PARSE_INLINE_INSTALL_DATA
;
114 // Parse the data to check it's valid JSON. The download page will just eval
116 base::JSONReader json_reader
;
117 scoped_ptr
<base::Value
> inline_install_data(
118 json_reader
.ReadToValue(inline_install_json
));
119 if (!inline_install_data
) {
120 LOG(ERROR
) << json_reader
.GetErrorMessage();
121 return COULD_NOT_PARSE_INLINE_INSTALL_DATA
;
124 base::FilePath chrome_path
= GetChromeExePath(is_canary
);
125 // If none found, show EULA, download, and install Chrome.
126 if (chrome_path
.empty()) {
127 ExitCode get_chrome_result
= GetChrome(is_canary
, inline_install_json
);
128 if (get_chrome_result
!= SUCCESS
)
129 return get_chrome_result
;
131 chrome_path
= GetChromeExePath(is_canary
);
132 if (chrome_path
.empty())
133 return COULD_NOT_FIND_CHROME
;
136 base::CommandLine
cmd(chrome_path
);
137 cmd
.AppendSwitchASCII(kInstallChromeApp
, app_id
);
138 DVLOG(1) << "Install command: " << cmd
.GetCommandLineString();
139 bool launched
= base::LaunchProcess(cmd
, base::LaunchOptions(), NULL
);
140 DVLOG(1) << "Launch " << (launched
? "success." : "failed.");
145 } // namespace app_installer