blob: 240cec21573785713a7a7f3aaa2931b2219bde52 [file] [log] [blame]
[email protected]b90d7e802011-01-09 16:32:201// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]f7817822009-09-24 05:11:582// 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_frame/test/chrome_frame_test_utils.h"
6
[email protected]6e58a952011-01-12 19:28:507#include <atlapp.h>
8#include <atlmisc.h>
[email protected]f7817822009-09-24 05:11:589#include <iepmapi.h>
[email protected]42d7c022009-11-20 22:44:5810#include <sddl.h>
[email protected]874d5dd62011-04-19 07:03:1811#include <shlobj.h>
[email protected]f7817822009-09-24 05:11:5812
[email protected]5d91c9e2010-07-28 17:25:2813#include "base/command_line.h"
[email protected]59aa617b2010-09-02 22:02:0914#include "base/file_path.h"
[email protected]874d5dd62011-04-19 07:03:1815#include "base/file_util.h"
[email protected]d8b83b212010-04-07 18:27:5216#include "base/file_version_info.h"
[email protected]3b63f8f42011-03-28 01:54:1517#include "base/memory/scoped_ptr.h"
[email protected]d23ca372010-02-16 20:36:0918#include "base/path_service.h"
[email protected]d9f92192010-06-23 14:51:3219#include "base/process_util.h"
[email protected]5d91c9e2010-07-28 17:25:2820#include "base/string_util.h"
[email protected]d3451d832010-10-01 11:17:3721#include "base/stringprintf.h"
[email protected]d55194ca2010-03-11 18:25:4522#include "base/utf_string_conversions.h"
[email protected]2d6503982010-10-17 04:41:5423#include "base/win/registry.h"
[email protected]b90d7e802011-01-09 16:32:2024#include "base/win/scoped_handle.h"
[email protected]935aa542010-10-15 01:59:1525#include "base/win/windows_version.h"
[email protected]bc73b4e52010-03-26 04:16:2026#include "chrome/common/chrome_paths.h"
27#include "chrome/common/chrome_paths_internal.h"
[email protected]8ee65ba2011-04-12 20:53:2328#include "chrome/common/chrome_switches.h"
[email protected]7bc272f2009-12-09 01:09:2829#include "chrome_frame/utils.h"
[email protected]7dd06a02010-12-09 02:56:2430#include "testing/gtest/include/gtest/gtest.h"
[email protected]2dfeaf92011-01-10 21:08:2131#include "ui/base/clipboard/clipboard.h"
32#include "ui/base/clipboard/scoped_clipboard_writer.h"
[email protected]bc73b4e52010-03-26 04:16:2033
[email protected]f7817822009-09-24 05:11:5834namespace chrome_frame_test {
35
[email protected]2014db002010-09-28 13:46:1036const wchar_t kCrashServicePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
37
38const DWORD kCrashServicePipeDesiredAccess = FILE_READ_DATA |
39 FILE_WRITE_DATA |
40 FILE_WRITE_ATTRIBUTES;
41
42const DWORD kCrashServicePipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
43 SECURITY_SQOS_PRESENT;
44const int kCrashServiceStartupTimeoutMs = 500;
45
[email protected]f7817822009-09-24 05:11:5846const wchar_t kIEImageName[] = L"iexplore.exe";
47const wchar_t kIEBrokerImageName[] = L"ieuser.exe";
[email protected]bcd840c2010-05-27 10:43:0048const char kChromeImageName[] = "chrome.exe";
[email protected]d8b83b212010-04-07 18:27:5249const wchar_t kIEProfileName[] = L"iexplore";
[email protected]128f9d92010-04-12 15:58:5250const wchar_t kChromeLauncher[] = L"chrome_launcher.exe";
[email protected]ba443b72010-05-14 23:34:3851const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
[email protected]0cc270a2011-02-03 21:08:0052const int kChromeFrameVeryLongNavigationTimeoutInSeconds = 30;
[email protected]f7817822009-09-24 05:11:5853
[email protected]7dd06a02010-12-09 02:56:2454const wchar_t TempRegKeyOverride::kTempTestKeyPath[] =
55 L"Software\\Chromium\\TempTestKeys";
56
[email protected]f7817822009-09-24 05:11:5857// Callback function for EnumThreadWindows.
58BOOL CALLBACK CloseWindowsThreadCallback(HWND hwnd, LPARAM param) {
59 int& count = *reinterpret_cast<int*>(param);
60 if (IsWindowVisible(hwnd)) {
61 if (IsWindowEnabled(hwnd)) {
62 DWORD results = 0;
63 if (!::SendMessageTimeout(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0, SMTO_BLOCK,
64 10000, &results)) {
[email protected]d3451d832010-10-01 11:17:3765 LOG(WARNING) << "Window hung: " << base::StringPrintf(L"%08X", hwnd);
[email protected]f7817822009-09-24 05:11:5866 }
67 count++;
68 } else {
69 DLOG(WARNING) << "Skipping disabled window: "
[email protected]d3451d832010-10-01 11:17:3770 << base::StringPrintf(L"%08X", hwnd);
[email protected]f7817822009-09-24 05:11:5871 }
72 }
73 return TRUE; // continue enumeration
74}
75
76// Attempts to close all non-child, visible windows on the given thread.
77// The return value is the number of visible windows a close request was
78// sent to.
79int CloseVisibleTopLevelWindowsOnThread(DWORD thread_id) {
80 int window_close_attempts = 0;
81 EnumThreadWindows(thread_id, CloseWindowsThreadCallback,
82 reinterpret_cast<LPARAM>(&window_close_attempts));
83 return window_close_attempts;
84}
85
86// Enumerates the threads of a process and attempts to close visible non-child
87// windows on all threads of the process.
88// The return value is the number of visible windows a close request was
89// sent to.
90int CloseVisibleWindowsOnAllThreads(HANDLE process) {
91 DWORD process_id = ::GetProcessId(process);
92 if (process_id == 0) {
93 NOTREACHED();
94 return 0;
95 }
96
[email protected]b90d7e802011-01-09 16:32:2097 base::win::ScopedHandle snapshot(
98 CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0));
[email protected]f7817822009-09-24 05:11:5899 if (!snapshot.IsValid()) {
100 NOTREACHED();
101 return 0;
102 }
103
104 int window_close_attempts = 0;
105 THREADENTRY32 te = { sizeof(THREADENTRY32) };
106 if (Thread32First(snapshot, &te)) {
107 do {
108 if (RTL_CONTAINS_FIELD(&te, te.dwSize, th32OwnerProcessID) &&
109 te.th32OwnerProcessID == process_id) {
110 window_close_attempts +=
111 CloseVisibleTopLevelWindowsOnThread(te.th32ThreadID);
112 }
113 te.dwSize = sizeof(te);
114 } while (Thread32Next(snapshot, &te));
115 }
116
117 return window_close_attempts;
118}
119
[email protected]f7817822009-09-24 05:11:58120std::wstring GetExecutableAppPath(const std::wstring& file) {
121 std::wstring kAppPathsKey =
122 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\";
123
124 std::wstring app_path;
[email protected]2d6503982010-10-17 04:41:54125 base::win::RegKey key(HKEY_LOCAL_MACHINE, (kAppPathsKey + file).c_str(),
126 KEY_READ);
[email protected]f7817822009-09-24 05:11:58127 if (key.Handle()) {
128 key.ReadValue(NULL, &app_path);
129 }
130
131 return app_path;
132}
133
134std::wstring FormatCommandForApp(const std::wstring& exe_name,
135 const std::wstring& argument) {
[email protected]d3451d832010-10-01 11:17:37136 std::wstring reg_path(
137 base::StringPrintf(L"Applications\\%ls\\shell\\open\\command",
138 exe_name.c_str()));
[email protected]2d6503982010-10-17 04:41:54139 base::win::RegKey key(HKEY_CLASSES_ROOT, reg_path.c_str(), KEY_READ);
[email protected]f7817822009-09-24 05:11:58140
141 std::wstring command;
142 if (key.Handle()) {
143 key.ReadValue(NULL, &command);
144 int found = command.find(L"%1");
145 if (found >= 0) {
146 command.replace(found, 2, argument);
147 }
148 }
149 return command;
150}
151
152base::ProcessHandle LaunchExecutable(const std::wstring& executable,
153 const std::wstring& argument) {
154 base::ProcessHandle process = NULL;
155 std::wstring path = GetExecutableAppPath(executable);
156 if (path.empty()) {
157 path = FormatCommandForApp(executable, argument);
158 if (path.empty()) {
[email protected]7ec1f4e2010-05-19 18:43:21159 LOG(ERROR) << "Failed to find executable: " << executable;
[email protected]f7817822009-09-24 05:11:58160 } else {
[email protected]51343d5a2009-10-26 22:39:33161 CommandLine cmdline = CommandLine::FromString(path);
[email protected]e5992182011-07-15 16:47:02162 if (!base::LaunchProcess(cmdline, base::LaunchOptions(), &process)) {
[email protected]adda8692011-07-14 20:55:30163 LOG(ERROR) << "LaunchProcess failed: " << ::GetLastError();
[email protected]7ec1f4e2010-05-19 18:43:21164 }
[email protected]f7817822009-09-24 05:11:58165 }
166 } else {
[email protected]d1540c82009-10-27 00:18:32167 CommandLine cmdline((FilePath(path)));
[email protected]0445eb42010-08-13 22:10:30168 cmdline.AppendArgNative(argument);
[email protected]e5992182011-07-15 16:47:02169 if (!base::LaunchProcess(cmdline, base::LaunchOptions(), &process)) {
[email protected]adda8692011-07-14 20:55:30170 LOG(ERROR) << "LaunchProcess failed: " << ::GetLastError();
[email protected]7ec1f4e2010-05-19 18:43:21171 }
[email protected]f7817822009-09-24 05:11:58172 }
173 return process;
174}
175
[email protected]f7817822009-09-24 05:11:58176base::ProcessHandle LaunchChrome(const std::wstring& url) {
[email protected]bcd840c2010-05-27 10:43:00177 FilePath path;
[email protected]d23ca372010-02-16 20:36:09178 PathService::Get(base::DIR_MODULE, &path);
[email protected]bcd840c2010-05-27 10:43:00179 path = path.AppendASCII(kChromeImageName);
[email protected]d23ca372010-02-16 20:36:09180
[email protected]bcd840c2010-05-27 10:43:00181 CommandLine cmd(path);
[email protected]0445eb42010-08-13 22:10:30182 cmd.AppendSwitch(switches::kNoFirstRun);
183 cmd.AppendArgNative(url);
[email protected]d23ca372010-02-16 20:36:09184
185 base::ProcessHandle process = NULL;
[email protected]e5992182011-07-15 16:47:02186 base::LaunchProcess(cmd, base::LaunchOptions(), &process);
[email protected]d23ca372010-02-16 20:36:09187 return process;
[email protected]f7817822009-09-24 05:11:58188}
189
[email protected]f7817822009-09-24 05:11:58190base::ProcessHandle LaunchIEOnVista(const std::wstring& url) {
191 typedef HRESULT (WINAPI* IELaunchURLPtr)(
192 const wchar_t* url,
193 PROCESS_INFORMATION *pi,
194 VOID *info);
195
196 IELaunchURLPtr launch;
197 PROCESS_INFORMATION pi = {0};
198 IELAUNCHURLINFO info = {sizeof info, 0};
199 HMODULE h = LoadLibrary(L"ieframe.dll");
[email protected]7ec1f4e2010-05-19 18:43:21200 if (!h) {
201 LOG(ERROR) << "Failed to load ieframe.dll: " << ::GetLastError();
[email protected]f7817822009-09-24 05:11:58202 return NULL;
[email protected]7ec1f4e2010-05-19 18:43:21203 }
[email protected]f7817822009-09-24 05:11:58204 launch = reinterpret_cast<IELaunchURLPtr>(GetProcAddress(h, "IELaunchURL"));
[email protected]7ec1f4e2010-05-19 18:43:21205 CHECK(launch);
[email protected]f7817822009-09-24 05:11:58206 HRESULT hr = launch(url.c_str(), &pi, &info);
207 FreeLibrary(h);
[email protected]7ec1f4e2010-05-19 18:43:21208 if (SUCCEEDED(hr)) {
[email protected]f7817822009-09-24 05:11:58209 CloseHandle(pi.hThread);
[email protected]7ec1f4e2010-05-19 18:43:21210 } else {
[email protected]d3451d832010-10-01 11:17:37211 LOG(ERROR) << base::StringPrintf("IELaunchURL failed: 0x%08X", hr);
[email protected]7ec1f4e2010-05-19 18:43:21212 }
[email protected]f7817822009-09-24 05:11:58213 return pi.hProcess;
214}
215
216base::ProcessHandle LaunchIE(const std::wstring& url) {
[email protected]874d5dd62011-04-19 07:03:18217 if (GetInstalledIEVersion() >= IE_8) {
218 chrome_frame_test::ClearIESessionHistory();
219 }
220
[email protected]935aa542010-10-15 01:59:15221 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
[email protected]f7817822009-09-24 05:11:58222 return LaunchIEOnVista(url);
[email protected]f7817822009-09-24 05:11:58223 }
[email protected]935aa542010-10-15 01:59:15224 return LaunchExecutable(kIEImageName, url);
[email protected]f7817822009-09-24 05:11:58225}
226
227int CloseAllIEWindows() {
228 int ret = 0;
229
[email protected]8ee65ba2011-04-12 20:53:23230 base::win::ScopedComPtr<IShellWindows> windows;
[email protected]f7817822009-09-24 05:11:58231 HRESULT hr = ::CoCreateInstance(__uuidof(ShellWindows), NULL, CLSCTX_ALL,
232 IID_IShellWindows, reinterpret_cast<void**>(windows.Receive()));
233 DCHECK(SUCCEEDED(hr));
234
235 if (SUCCEEDED(hr)) {
236 long count = 0; // NOLINT
237 windows->get_Count(&count);
238 VARIANT i = { VT_I4 };
239 for (i.lVal = 0; i.lVal < count; ++i.lVal) {
[email protected]8ee65ba2011-04-12 20:53:23240 base::win::ScopedComPtr<IDispatch> folder;
[email protected]f7817822009-09-24 05:11:58241 windows->Item(i, folder.Receive());
242 if (folder != NULL) {
[email protected]8ee65ba2011-04-12 20:53:23243 base::win::ScopedComPtr<IWebBrowser2> browser;
[email protected]f7817822009-09-24 05:11:58244 if (SUCCEEDED(browser.QueryFrom(folder))) {
[email protected]59aa617b2010-09-02 22:02:09245 bool is_ie = true;
246 HWND window = NULL;
247 // Check the class of the browser window to make sure we only close
248 // IE windows.
249 if (browser->get_HWND(reinterpret_cast<SHANDLE_PTR*>(window))) {
250 wchar_t class_name[MAX_PATH];
251 if (::GetClassName(window, class_name, arraysize(class_name))) {
252 is_ie = _wcsicmp(class_name, L"IEFrame") == 0;
253 }
254 }
255 if (is_ie) {
256 browser->Quit();
257 ++ret;
258 }
[email protected]f7817822009-09-24 05:11:58259 }
260 }
261 }
262 }
263
264 return ret;
265}
266
[email protected]42d7c022009-11-20 22:44:58267
268LowIntegrityToken::LowIntegrityToken() : impersonated_(false) {
269}
270
271LowIntegrityToken::~LowIntegrityToken() {
272 RevertToSelf();
273}
274
275BOOL LowIntegrityToken::RevertToSelf() {
276 BOOL ok = TRUE;
277 if (impersonated_) {
278 DCHECK(IsImpersonated());
279 ok = ::RevertToSelf();
280 if (ok)
281 impersonated_ = false;
282 }
283
284 return ok;
285}
286
287BOOL LowIntegrityToken::Impersonate() {
288 DCHECK(!impersonated_);
289 DCHECK(!IsImpersonated());
290 HANDLE process_token_handle = NULL;
291 BOOL ok = ::OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE,
292 &process_token_handle);
293 if (!ok) {
294 DLOG(ERROR) << "::OpenProcessToken failed: " << GetLastError();
295 return ok;
296 }
297
[email protected]b90d7e802011-01-09 16:32:20298 base::win::ScopedHandle process_token(process_token_handle);
[email protected]42d7c022009-11-20 22:44:58299 // Create impersonation low integrity token.
300 HANDLE impersonation_token_handle = NULL;
301 ok = ::DuplicateTokenEx(process_token,
302 TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, NULL,
303 SecurityImpersonation, TokenImpersonation, &impersonation_token_handle);
304 if (!ok) {
305 DLOG(ERROR) << "::DuplicateTokenEx failed: " << GetLastError();
306 return ok;
307 }
308
[email protected]7ec1f4e2010-05-19 18:43:21309 // TODO(stoyan): sandbox/src/restricted_token_utils.cc has
310 // SetTokenIntegrityLevel function already.
[email protected]b90d7e802011-01-09 16:32:20311 base::win::ScopedHandle impersonation_token(impersonation_token_handle);
[email protected]42d7c022009-11-20 22:44:58312 PSID integrity_sid = NULL;
313 TOKEN_MANDATORY_LABEL tml = {0};
314 ok = ::ConvertStringSidToSid(SDDL_ML_LOW, &integrity_sid);
315 if (!ok) {
316 DLOG(ERROR) << "::ConvertStringSidToSid failed: " << GetLastError();
317 return ok;
318 }
319
320 tml.Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
321 tml.Label.Sid = integrity_sid;
322 ok = ::SetTokenInformation(impersonation_token, TokenIntegrityLevel,
323 &tml, sizeof(tml) + ::GetLengthSid(integrity_sid));
324 ::LocalFree(integrity_sid);
325 if (!ok) {
326 DLOG(ERROR) << "::SetTokenInformation failed: " << GetLastError();
327 return ok;
328 }
329
330 // Switch current thread to low integrity.
331 ok = ::ImpersonateLoggedOnUser(impersonation_token);
332 if (ok) {
333 impersonated_ = true;
334 } else {
335 DLOG(ERROR) << "::ImpersonateLoggedOnUser failed: " << GetLastError();
336 }
337
338 return ok;
339}
340
341bool LowIntegrityToken::IsImpersonated() {
342 HANDLE token = NULL;
343 if (!::OpenThreadToken(::GetCurrentThread(), 0, false, &token) &&
344 ::GetLastError() != ERROR_NO_TOKEN) {
345 return true;
346 }
347
348 if (token)
349 ::CloseHandle(token);
350
351 return false;
352}
353
[email protected]7bc272f2009-12-09 01:09:28354HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) {
355 if (!web_browser)
356 return E_INVALIDARG;
357
[email protected]874d5dd62011-04-19 07:03:18358 if (GetInstalledIEVersion() >= IE_8) {
359 chrome_frame_test::ClearIESessionHistory();
360 }
361
[email protected]7aa8d972010-02-17 04:24:49362 AllowSetForegroundWindow(ASFW_ANY);
363
[email protected]7bc272f2009-12-09 01:09:28364 HRESULT hr = S_OK;
365 DWORD cocreate_flags = CLSCTX_LOCAL_SERVER;
366 chrome_frame_test::LowIntegrityToken token;
367 // Vista has a bug which manifests itself when a medium integrity process
368 // launches a COM server like IE which runs in protected mode due to UAC.
369 // This causes the IWebBrowser2 interface which is returned to be useless,
370 // i.e it does not receive any events, etc. Our workaround for this is
371 // to impersonate a low integrity token and then launch IE.
[email protected]935aa542010-10-15 01:59:15372 if (base::win::GetVersion() == base::win::VERSION_VISTA &&
[email protected]6448b3ab2010-07-12 22:07:03373 GetInstalledIEVersion() == IE_7) {
[email protected]7bc272f2009-12-09 01:09:28374 // Create medium integrity browser that will launch IE broker.
[email protected]8ee65ba2011-04-12 20:53:23375 base::win::ScopedComPtr<IWebBrowser2> medium_integrity_browser;
[email protected]7bc272f2009-12-09 01:09:28376 hr = medium_integrity_browser.CreateInstance(CLSID_InternetExplorer, NULL,
377 CLSCTX_LOCAL_SERVER);
378 if (FAILED(hr))
379 return hr;
380 medium_integrity_browser->Quit();
381 // Broker remains alive.
382 if (!token.Impersonate()) {
383 hr = HRESULT_FROM_WIN32(GetLastError());
384 return hr;
385 }
386
387 cocreate_flags |= CLSCTX_ENABLE_CLOAKING;
388 }
389
390 hr = ::CoCreateInstance(CLSID_InternetExplorer, NULL,
391 cocreate_flags, IID_IWebBrowser2,
392 reinterpret_cast<void**>(web_browser));
393 // ~LowIntegrityToken() will switch integrity back to medium.
394 return hr;
395}
396
[email protected]38f57abb2010-12-01 19:58:30397// TODO([email protected]) Could share this code with chrome_frame_plugin.h
[email protected]bc73b4e52010-03-26 04:16:20398FilePath GetProfilePath(const std::wstring& profile_name) {
399 FilePath profile_path;
400 chrome::GetChromeFrameUserDataDirectory(&profile_path);
401 return profile_path.Append(profile_name);
402}
403
[email protected]1da35172010-04-22 02:30:03404std::wstring GetExeVersion(const std::wstring& exe_path) {
405 scoped_ptr<FileVersionInfo> ie_version_info(
406 FileVersionInfo::CreateFileVersionInfo(FilePath(exe_path)));
407 return ie_version_info->product_version();
408}
409
410IEVersion GetInstalledIEVersion() {
411 std::wstring path = chrome_frame_test::GetExecutableAppPath(kIEImageName);
412 std::wstring version = GetExeVersion(path);
413
414 switch (version[0]) {
415 case '6':
416 return IE_6;
417 case '7':
418 return IE_7;
419 case '8':
420 return IE_8;
[email protected]d8e13512010-09-22 17:02:58421 case '9':
422 return IE_9;
[email protected]1da35172010-04-22 02:30:03423 default:
424 break;
425 }
426
427 return IE_UNSUPPORTED;
428}
429
[email protected]d8b83b212010-04-07 18:27:52430FilePath GetProfilePathForIE() {
431 FilePath profile_path;
432 // Browsers without IDeleteBrowsingHistory in non-priv mode
433 // have their profiles moved into "Temporary Internet Files".
434 // The code below basically retrieves the version of IE and computes
435 // the profile directory accordingly.
[email protected]d9ca776c2011-01-31 21:44:26436 if (GetInstalledIEVersion() <= IE_7) {
[email protected]d8b83b212010-04-07 18:27:52437 profile_path = GetIETemporaryFilesFolder();
438 profile_path = profile_path.Append(L"Google Chrome Frame");
[email protected]38f57abb2010-12-01 19:58:30439 } else {
440 profile_path = GetProfilePath(kIEProfileName);
[email protected]d8b83b212010-04-07 18:27:52441 }
442 return profile_path;
443}
444
[email protected]6448b3ab2010-07-12 22:07:03445FilePath GetTestDataFolder() {
446 FilePath test_dir;
447 PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
448 test_dir = test_dir.Append(FILE_PATH_LITERAL("chrome_frame"))
449 .Append(FILE_PATH_LITERAL("test"))
450 .Append(FILE_PATH_LITERAL("data"));
451 return test_dir;
452}
453
[email protected]5b811ad2010-11-24 15:24:05454FilePath GetSeleniumTestFolder() {
455 FilePath test_dir;
456 PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
457 test_dir = test_dir.Append(FILE_PATH_LITERAL("data"))
458 .Append(FILE_PATH_LITERAL("selenium_core"));
459 return test_dir;
460}
461
[email protected]6448b3ab2010-07-12 22:07:03462std::wstring GetPathFromUrl(const std::wstring& url) {
463 string16 url16 = WideToUTF16(url);
464 GURL gurl = GURL(url16);
465 if (gurl.has_query()) {
466 GURL::Replacements replacements;
467 replacements.ClearQuery();
468 gurl = gurl.ReplaceComponents(replacements);
469 }
470 return UTF8ToWide(gurl.PathForRequest());
471}
472
473std::wstring GetPathAndQueryFromUrl(const std::wstring& url) {
474 string16 url16 = WideToUTF16(url);
475 GURL gurl = GURL(url16);
476 return UTF8ToWide(gurl.PathForRequest());
477}
478
[email protected]fe30d762010-11-30 17:37:19479std::wstring GetClipboardText() {
[email protected]2dfeaf92011-01-10 21:08:21480 ui::Clipboard clipboard;
[email protected]fe30d762010-11-30 17:37:19481 string16 text16;
[email protected]2dfeaf92011-01-10 21:08:21482 clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &text16);
[email protected]fe30d762010-11-30 17:37:19483 return UTF16ToWide(text16);
484}
485
486void SetClipboardText(const std::wstring& text) {
[email protected]2dfeaf92011-01-10 21:08:21487 ui::Clipboard clipboard;
[email protected]fe30d762010-11-30 17:37:19488 {
[email protected]2dfeaf92011-01-10 21:08:21489 ui::ScopedClipboardWriter clipboard_writer(&clipboard);
[email protected]fe30d762010-11-30 17:37:19490 clipboard_writer.WriteText(WideToUTF16(text));
491 }
492}
493
[email protected]6448b3ab2010-07-12 22:07:03494bool AddCFMetaTag(std::string* html_data) {
495 if (!html_data) {
496 NOTREACHED();
497 return false;
498 }
[email protected]59aa617b2010-09-02 22:02:09499 std::string lower = StringToLowerASCII(*html_data);
500 size_t head = lower.find("<head>");
[email protected]6448b3ab2010-07-12 22:07:03501 if (head == std::string::npos) {
502 // Add missing head section.
[email protected]59aa617b2010-09-02 22:02:09503 size_t html = lower.find("<html>");
[email protected]6448b3ab2010-07-12 22:07:03504 if (html != std::string::npos) {
[email protected]59aa617b2010-09-02 22:02:09505 head = html + strlen("<html>");
506 html_data->insert(head, "<head></head>");
507 } else {
508 DLOG(ERROR) << "Meta tag will not be injected "
509 << "because the html tag could not be found";
[email protected]6448b3ab2010-07-12 22:07:03510 }
511 }
512 if (head != std::string::npos) {
513 html_data->insert(
514 head + strlen("<head>"),
515 "<meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />");
516 }
517 return head != std::string::npos;
518}
519
[email protected]5d91c9e2010-07-28 17:25:28520CloseIeAtEndOfScope::~CloseIeAtEndOfScope() {
521 int closed = CloseAllIEWindows();
522 DLOG_IF(ERROR, closed != 0) << "Closed " << closed << " windows forcefully";
523}
524
[email protected]2014db002010-09-28 13:46:10525// Attempt to connect to a running crash_service instance. Success occurs if we
526// can actually connect to the service's pipe or we receive ERROR_PIPE_BUSY.
527// Waits up to |timeout_ms| for success. |timeout_ms| may be 0, meaning only try
528// once, or negative, meaning wait forever.
529bool DetectRunningCrashService(int timeout_ms) {
530 // Wait for the crash_service.exe to be ready for clients.
531 base::Time start = base::Time::Now();
[email protected]b90d7e802011-01-09 16:32:20532 base::win::ScopedHandle new_pipe;
[email protected]2014db002010-09-28 13:46:10533
534 while (true) {
535 new_pipe.Set(::CreateFile(kCrashServicePipeName,
536 kCrashServicePipeDesiredAccess,
537 0, // dwShareMode
538 NULL, // lpSecurityAttributes
539 OPEN_EXISTING,
540 kCrashServicePipeFlagsAndAttributes,
541 NULL)); // hTemplateFile
542
543 if (new_pipe.IsValid()) {
544 return true;
545 }
546
547 switch (::GetLastError()) {
548 case ERROR_PIPE_BUSY:
549 // OK, it exists, let's assume that clients will eventually be able to
550 // connect to it.
551 return true;
552 case ERROR_FILE_NOT_FOUND:
553 // Wait a bit longer
554 break;
555 default:
[email protected]6e58a952011-01-12 19:28:50556 DPLOG(WARNING) << "Unexpected error while checking crash_service.exe's "
557 << "pipe.";
[email protected]2014db002010-09-28 13:46:10558 // Go ahead and wait in case it clears up.
559 break;
560 }
561
562 if (timeout_ms == 0) {
563 return false;
564 } else if (timeout_ms > 0) {
565 base::TimeDelta duration = base::Time::Now() - start;
566 if (duration.InMilliseconds() > timeout_ms) {
567 return false;
568 }
569 }
570
571 Sleep(10);
572 }
573}
574
[email protected]d9f92192010-06-23 14:51:32575base::ProcessHandle StartCrashService() {
[email protected]2014db002010-09-28 13:46:10576 if (DetectRunningCrashService(kCrashServiceStartupTimeoutMs)) {
[email protected]2b9a9f162010-10-19 20:30:45577 DVLOG(1) << "crash_service.exe is already running. We will use the "
578 "existing process and leave it running after tests complete.";
[email protected]2014db002010-09-28 13:46:10579 return NULL;
580 }
581
[email protected]d9f92192010-06-23 14:51:32582 FilePath exe_dir;
583 if (!PathService::Get(base::DIR_EXE, &exe_dir)) {
584 DCHECK(false);
585 return NULL;
586 }
587
588 base::ProcessHandle crash_service = NULL;
589
[email protected]2b9a9f162010-10-19 20:30:45590 DVLOG(1) << "Starting crash_service.exe so you know if a test crashes!";
[email protected]2014db002010-09-28 13:46:10591
[email protected]d9f92192010-06-23 14:51:32592 FilePath crash_service_path = exe_dir.AppendASCII("crash_service.exe");
[email protected]e5992182011-07-15 16:47:02593 if (!base::LaunchProcess(crash_service_path.value(), base::LaunchOptions(),
594 &crash_service)) {
[email protected]d9f92192010-06-23 14:51:32595 DLOG(ERROR) << "Couldn't start crash_service.exe";
596 return NULL;
597 }
598
[email protected]2014db002010-09-28 13:46:10599 base::Time start = base::Time::Now();
600
601 if (DetectRunningCrashService(kCrashServiceStartupTimeoutMs)) {
[email protected]2b9a9f162010-10-19 20:30:45602 DVLOG(1) << "crash_service.exe is ready for clients in "
603 << (base::Time::Now() - start).InMilliseconds() << " ms.";
[email protected]2014db002010-09-28 13:46:10604 return crash_service;
605 } else {
606 DLOG(ERROR) << "crash_service.exe failed to accept client connections "
[email protected]2b9a9f162010-10-19 20:30:45607 "within " << kCrashServiceStartupTimeoutMs << " ms. "
608 "Terminating it now.";
[email protected]2014db002010-09-28 13:46:10609
610 // First check to see if it's even still running just to minimize the
611 // likelihood of spurious error messages from KillProcess.
612 if (WAIT_OBJECT_0 != ::WaitForSingleObject(crash_service, 0)) {
613 base::KillProcess(crash_service, 0, false);
614 }
615 return NULL;
616 }
[email protected]d9f92192010-06-23 14:51:32617}
618
[email protected]7dd06a02010-12-09 02:56:24619TempRegKeyOverride::TempRegKeyOverride(HKEY override, const wchar_t* temp_name)
620 : override_(override), temp_name_(temp_name) {
621 DCHECK(temp_name && lstrlenW(temp_name));
622 std::wstring key_path(kTempTestKeyPath);
623 key_path += L"\\" + temp_name_;
[email protected]e06f4d52011-01-19 07:28:46624 EXPECT_EQ(ERROR_SUCCESS, temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(),
625 KEY_ALL_ACCESS));
[email protected]7dd06a02010-12-09 02:56:24626 EXPECT_EQ(ERROR_SUCCESS,
627 ::RegOverridePredefKey(override_, temp_key_.Handle()));
628}
629
630TempRegKeyOverride::~TempRegKeyOverride() {
631 ::RegOverridePredefKey(override_, NULL);
632 // The temp key will be deleted via a call to DeleteAllTempKeys().
633}
634
635// static
636void TempRegKeyOverride::DeleteAllTempKeys() {
637 base::win::RegKey key;
[email protected]e06f4d52011-01-19 07:28:46638 if (key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS) == ERROR_SUCCESS) {
[email protected]7dd06a02010-12-09 02:56:24639 key.DeleteKey(kTempTestKeyPath);
640 }
641}
642
643ScopedVirtualizeHklmAndHkcu::ScopedVirtualizeHklmAndHkcu() {
644 TempRegKeyOverride::DeleteAllTempKeys();
645 hklm_.reset(new TempRegKeyOverride(HKEY_LOCAL_MACHINE, L"hklm_fake"));
646 hkcu_.reset(new TempRegKeyOverride(HKEY_CURRENT_USER, L"hkcu_fake"));
647}
648
649ScopedVirtualizeHklmAndHkcu::~ScopedVirtualizeHklmAndHkcu() {
650 hkcu_.reset(NULL);
651 hklm_.reset(NULL);
652 TempRegKeyOverride::DeleteAllTempKeys();
653}
654
[email protected]3c8a5c52010-12-22 00:07:15655bool KillProcesses(const std::wstring& executable_name, int exit_code,
656 bool wait) {
657 bool result = true;
658 base::NamedProcessIterator iter(executable_name, NULL);
659 while (const base::ProcessEntry* entry = iter.NextProcessEntry()) {
660 result &= base::KillProcessById(entry->pid(), exit_code, wait);
661 }
662 return result;
663}
664
[email protected]cf5912b2011-02-01 22:20:44665ScopedChromeFrameRegistrar::RegistrationType GetTestBedType() {
666 if (GetConfigBool(false, L"PerUserTestBed")) {
667 return ScopedChromeFrameRegistrar::PER_USER;
668 } else {
669 return ScopedChromeFrameRegistrar::SYSTEM_LEVEL;
670 }
671}
672
[email protected]874d5dd62011-04-19 07:03:18673void ClearIESessionHistory() {
674 wchar_t local_app_data_path[MAX_PATH + 1] = {0};
675 SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
676 local_app_data_path);
677
678 std::wstring session_history_path = local_app_data_path;
679 session_history_path += L"\\Microsoft\\Internet Explorer\\Recovery";
680 file_util::Delete(session_history_path, true);
681}
682
[email protected]f7817822009-09-24 05:11:58683} // namespace chrome_frame_test