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_frame/test/test_with_web_server.h"
6
7#include "base/base_paths.h"
8#include "base/file_util.h"
9#include "base/file_version_info.h"
10#include "base/files/memory_mapped_file.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/path_service.h"
13#include "base/process/kill.h"
14#include "base/strings/stringprintf.h"
15#include "base/strings/utf_string_conversions.h"
16#include "base/test/test_timeouts.h"
17#include "base/win/windows_version.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/installer/util/helper.h"
20#include "chrome/installer/util/install_util.h"
21#include "chrome/installer/util/product.h"
22#include "chrome_frame/html_utils.h"
23#include "chrome_frame/test/chrome_frame_test_utils.h"
24#include "chrome_frame/test/mock_ie_event_sink_actions.h"
25#include "chrome_frame/test/mock_ie_event_sink_test.h"
26#include "chrome_frame/test/test_scrubber.h"
27#include "chrome_frame/utils.h"
28#include "net/base/mime_util.h"
29#include "net/http/http_util.h"
30#include "net/socket/stream_listen_socket.h"
31
32using chrome_frame_test::kChromeFrameLongNavigationTimeout;
33using chrome_frame_test::kChromeFrameVeryLongNavigationTimeout;
34
35using testing::_;
36using testing::StrCaseEq;
37
38const wchar_t kDocRoot[] = L"chrome_frame\\test\\data";
39
40namespace {
41
42// Helper method for creating the appropriate HTTP response headers.
43std::string CreateHttpHeaders(CFInvocation invocation,
44                              bool add_no_cache_header,
45                              const std::string& content_type) {
46  std::ostringstream ss;
47  ss << "HTTP/1.1 200 OK\r\n"
48     << "Connection: close\r\n"
49     << "Content-Type: " << content_type << "\r\n";
50  if (invocation.type() == CFInvocation::HTTP_HEADER)
51    ss << "X-UA-Compatible: chrome=1\r\n";
52  if (add_no_cache_header) {
53    ss << "Cache-Control: no-cache\r\n";
54    ss << "Expires: Tue, 15 Nov 1994 08:12:31 GMT\r\n";
55  }
56  return ss.str();
57}
58
59std::string GetMockHttpHeaders(const base::FilePath& mock_http_headers_path) {
60  std::string headers;
61  file_util::ReadFileToString(mock_http_headers_path, &headers);
62  return headers;
63}
64
65class ChromeFrameTestEnvironment: public testing::Environment {
66 public:
67  virtual ~ChromeFrameTestEnvironment() {}
68  virtual void SetUp() OVERRIDE {
69    ScopedChromeFrameRegistrar::RegisterDefaults();
70  }
71};
72
73::testing::Environment* const chrome_frame_env =
74    ::testing::AddGlobalTestEnvironment(new ChromeFrameTestEnvironment);
75
76}  // namespace
77
78base::FilePath ChromeFrameTestWithWebServer::test_file_path_;
79base::FilePath ChromeFrameTestWithWebServer::results_dir_;
80base::FilePath ChromeFrameTestWithWebServer::CFInstall_path_;
81base::FilePath ChromeFrameTestWithWebServer::CFInstance_path_;
82base::ScopedTempDir ChromeFrameTestWithWebServer::temp_dir_;
83base::FilePath ChromeFrameTestWithWebServer::chrome_user_data_dir_;
84chrome_frame_test::TimedMsgLoop* ChromeFrameTestWithWebServer::loop_;
85std::string ChromeFrameTestWithWebServer::local_address_;
86testing::StrictMock<MockWebServerListener>*
87    ChromeFrameTestWithWebServer::listener_mock_;
88testing::StrictMock<MockWebServer>* ChromeFrameTestWithWebServer::server_mock_;
89
90ChromeFrameTestWithWebServer::ChromeFrameTestWithWebServer() {
91}
92
93// static
94void ChromeFrameTestWithWebServer::SetUpTestCase() {
95  base::FilePath chrome_frame_source_path;
96  PathService::Get(base::DIR_SOURCE_ROOT, &chrome_frame_source_path);
97  chrome_frame_source_path = chrome_frame_source_path.Append(
98      FILE_PATH_LITERAL("chrome_frame"));
99
100  test_file_path_ = chrome_frame_source_path
101      .Append(FILE_PATH_LITERAL("test"))
102      .Append(FILE_PATH_LITERAL("data"));
103
104  results_dir_ = chrome_frame_test::GetTestDataFolder().AppendASCII("dump");
105
106  // Copy the CFInstance.js and CFInstall.js files from src\chrome_frame to
107  // src\chrome_frame\test\data.
108  base::FilePath CFInstance_src_path;
109  base::FilePath CFInstall_src_path;
110
111  CFInstance_src_path = chrome_frame_source_path.AppendASCII("CFInstance.js");
112  CFInstance_path_ = test_file_path_.AppendASCII("CFInstance.js");
113
114  ASSERT_TRUE(base::CopyFile(CFInstance_src_path, CFInstance_path_));
115
116  CFInstall_src_path = chrome_frame_source_path.AppendASCII("CFInstall.js");
117  CFInstall_path_ = test_file_path_.AppendASCII("CFInstall.js");
118
119  ASSERT_TRUE(base::CopyFile(CFInstall_src_path, CFInstall_path_));
120
121  loop_ = new chrome_frame_test::TimedMsgLoop();
122  loop_->set_snapshot_on_timeout(true);
123  local_address_ = chrome_frame_test::GetLocalIPv4Address();
124  listener_mock_ = new testing::StrictMock<MockWebServerListener>();
125  server_mock_ = new testing::StrictMock<MockWebServer>(
126      1337, ASCIIToWide(local_address_),
127      chrome_frame_test::GetTestDataFolder());
128  server_mock_->set_listener(listener_mock_);
129}
130
131// static
132void ChromeFrameTestWithWebServer::TearDownTestCase() {
133  delete server_mock_;
134  server_mock_ = NULL;
135  delete listener_mock_;
136  listener_mock_ = NULL;
137  local_address_.clear();
138  delete loop_;
139  loop_ = NULL;
140  base::DeleteFile(CFInstall_path_, false);
141  base::DeleteFile(CFInstance_path_, false);
142  if (temp_dir_.IsValid())
143    EXPECT_TRUE(temp_dir_.Delete());
144}
145
146// static
147const base::FilePath&
148ChromeFrameTestWithWebServer::GetChromeUserDataDirectory() {
149  if (!temp_dir_.IsValid()) {
150    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
151    chrome_user_data_dir_ = temp_dir_.path().AppendASCII("User Data");
152  }
153  return chrome_user_data_dir_;
154}
155
156void ChromeFrameTestWithWebServer::SetUp() {
157  // Make sure that we are not accidentally enabling gcf protocol.
158  SetConfigBool(kAllowUnsafeURLs, false);
159
160  server_mock().ClearResults();
161  server_mock().ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
162  server_mock().set_expected_result("OK");
163}
164
165void ChromeFrameTestWithWebServer::TearDown() {
166  CloseBrowser();
167  loop().RunUntilIdle();
168  testing::Mock::VerifyAndClear(listener_mock_);
169  testing::Mock::VerifyAndClear(server_mock_);
170}
171
172bool ChromeFrameTestWithWebServer::LaunchBrowser(BrowserKind browser,
173                                                 const wchar_t* page) {
174  std::wstring url = page;
175
176  // We should resolve the URL only if it is a relative url.
177  GURL parsed_url(WideToUTF8(page));
178  if (!parsed_url.has_scheme()) {
179    url = server_mock().Resolve(page);
180  }
181
182  browser_ = browser;
183  if (browser == IE) {
184    browser_handle_.Set(chrome_frame_test::LaunchIE(url));
185  } else if (browser == CHROME) {
186    const base::FilePath& user_data_dir = GetChromeUserDataDirectory();
187    chrome_frame_test::OverrideDataDirectoryForThisTest(user_data_dir.value());
188    browser_handle_.Set(chrome_frame_test::LaunchChrome(url, user_data_dir));
189  } else {
190    NOTREACHED();
191  }
192
193  return browser_handle_.IsValid();
194}
195
196void ChromeFrameTestWithWebServer::CloseBrowser() {
197  if (!browser_handle_.IsValid())
198    return;
199
200  int attempts = 0;
201  if (browser_ == IE) {
202    attempts = chrome_frame_test::CloseAllIEWindows();
203  } else {
204    attempts = chrome_frame_test::CloseVisibleWindowsOnAllThreads(
205                                                               browser_handle_);
206  }
207
208  if (attempts > 0) {
209    DWORD wait = ::WaitForSingleObject(browser_handle_, 20000);
210    if (wait == WAIT_OBJECT_0) {
211      browser_handle_.Close();
212    } else {
213      LOG(ERROR) << "WaitForSingleObject returned " << wait;
214    }
215  } else {
216    LOG(ERROR) << "No attempts to close browser windows";
217  }
218
219  if (browser_handle_.IsValid()) {
220    DWORD exit_code = 0;
221    if (!::GetExitCodeProcess(browser_handle_, &exit_code) ||
222        exit_code == STILL_ACTIVE) {
223      LOG(ERROR) << L"Forcefully killing browser process. Exit:" << exit_code;
224      base::KillProcess(browser_handle_, 0, true);
225    }
226    browser_handle_.Close();
227  }
228}
229
230bool ChromeFrameTestWithWebServer::BringBrowserToTop() {
231  return simulate_input::EnsureProcessInForeground(
232      GetProcessId(browser_handle_));
233}
234
235bool ChromeFrameTestWithWebServer::WaitForTestToComplete(
236    base::TimeDelta duration) {
237  loop().RunFor(duration);
238  return !loop().WasTimedOut();
239}
240
241bool ChromeFrameTestWithWebServer::WaitForOnLoad(int milliseconds) {
242  return false;
243}
244
245const wchar_t kPostedResultSubstring[] = L"/writefile/";
246
247void ChromeFrameTestWithWebServer::SimpleBrowserTestExpectedResult(
248    BrowserKind browser, const wchar_t* page, const char* result) {
249  if (browser == IE && chrome_frame_test::GetInstalledIEVersion() >= IE_9) {
250    LOG(INFO) << "Temporarily disabling IE9 web server tests. "
251                 "See http://crbug.com/143699";
252    return;
253  }
254
255  int tries = 0;
256  ExpectAndHandlePostedResult();
257  // Retry tests that timeout once; see http://crbug.com/96449.
258  do {
259    // NOTE: Failed ASSERTs cause this function to exit immediately.
260    // Don't take a snapshot on the first try.
261    loop().set_snapshot_on_timeout(tries != 0);
262    ASSERT_TRUE(LaunchBrowser(browser, page));
263    if (WaitForTestToComplete(TestTimeouts::action_max_timeout())) {
264      // The test exited without timing out.  Confirm that the expected response
265      // was posted and return.
266      ASSERT_EQ(result, server_mock().posted_result());
267      break;
268    }
269    ASSERT_EQ(std::string(), server_mock().posted_result())
270        << "Test timed out yet provided a result.";
271    ASSERT_EQ(0, tries++) << "Failing test due to two timeouts.";
272    // Close the browser and try a second time.
273    CloseBrowser();
274    LOG(ERROR) << "Retrying test once since it timed out.";
275  } while (true);
276  loop().set_snapshot_on_timeout(true);
277}
278
279void ChromeFrameTestWithWebServer::SimpleBrowserTest(BrowserKind browser,
280    const wchar_t* page) {
281  SimpleBrowserTestExpectedResult(browser, page, "OK");
282}
283
284void ChromeFrameTestWithWebServer::ExpectAndHandlePostedResult() {
285  EXPECT_CALL(listener_mock(), OnExpectedResponse())
286      .WillRepeatedly(QUIT_LOOP_SOON(loop(),
287                                     base::TimeDelta::FromMilliseconds(100)));
288  server_mock().ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
289                                            kPostedResultSubstring);
290}
291
292void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser,
293    const wchar_t* page) {
294  base::FilePath plugin_path;
295  PathService::Get(base::DIR_MODULE, &plugin_path);
296  plugin_path = plugin_path.Append(kChromeFrameDllName);
297
298  static FileVersionInfo* version_info =
299      FileVersionInfo::CreateFileVersionInfo(plugin_path);
300
301  std::wstring version;
302  if (version_info)
303    version = version_info->product_version();
304
305  // If we can't find the Chrome Frame DLL in the src tree, we turn to
306  // the directory where chrome is installed.
307  if (!version_info) {
308    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
309    Version ver_system;
310    InstallUtil::GetChromeVersion(dist, true, &ver_system);
311    Version ver_user;
312    InstallUtil::GetChromeVersion(dist, false, &ver_system);
313    ASSERT_TRUE(ver_system.IsValid() || ver_user.IsValid());
314
315    bool system_install = ver_system.IsValid();
316    base::FilePath cf_dll_path(installer::GetChromeInstallPath(system_install, dist));
317    cf_dll_path = cf_dll_path.Append(UTF8ToWide(
318        ver_system.IsValid() ? ver_system.GetString() : ver_user.GetString()));
319    cf_dll_path = cf_dll_path.Append(kChromeFrameDllName);
320    version_info = FileVersionInfo::CreateFileVersionInfo(cf_dll_path);
321    if (version_info)
322      version = version_info->product_version();
323  }
324
325  server_mock().set_expected_result(WideToUTF8(version));
326
327  EXPECT_TRUE(version_info);
328  EXPECT_FALSE(version.empty());
329
330  SimpleBrowserTestExpectedResult(browser, page, WideToASCII(version).c_str());
331}
332
333// MockWebServer methods
334void MockWebServer::ExpectAndServeRequest(CFInvocation invocation,
335                                          const std::wstring& url) {
336  ExpectAndServeRequestWithCardinality(invocation, url, testing::Exactly(1));
337}
338
339void MockWebServer::ExpectAndServeRequestWithCardinality(
340    CFInvocation invocation, const std::wstring& url,
341    testing::Cardinality cardinality) {
342  EXPECT_CALL(*this, Get(_, chrome_frame_test::UrlPathEq(url), _))
343      .Times(cardinality)
344      .WillRepeatedly(SendResponse(this, invocation));
345}
346
347void MockWebServer::ExpectAndServeRequestAllowCache(CFInvocation invocation,
348                                                    const std::wstring &url) {
349  EXPECT_CALL(*this, Get(_, chrome_frame_test::UrlPathEq(url), _))
350      .WillOnce(SendResponse(this, invocation));
351}
352
353void MockWebServer::ExpectAndServeRequestAnyNumberTimes(
354    CFInvocation invocation, const std::wstring& path_prefix) {
355  EXPECT_CALL(*this, Get(_, testing::StartsWith(path_prefix), _))
356      .WillRepeatedly(SendResponse(this, invocation));
357}
358
359void MockWebServer::ExpectAndHandlePostedResult(
360    CFInvocation invocation, const std::wstring& post_suffix) {
361  EXPECT_CALL(*this, Post(_, testing::HasSubstr(post_suffix), _))
362      .WillRepeatedly(HandlePostedResponseHelper(this, invocation));
363}
364
365void MockWebServer::HandlePostedResponse(
366    test_server::ConfigurableConnection* connection,
367    const test_server::Request& request) {
368  posted_result_ = request.content();
369  if (listener_ && posted_result_ == expected_result_)
370    listener_->OnExpectedResponse();
371  connection->Send("HTTP/1.1 200 OK\r\n", "");
372}
373
374void MockWebServer::SendResponseHelper(
375    test_server::ConfigurableConnection* connection,
376    const std::wstring& request_uri,
377    const test_server::Request& request,
378    CFInvocation invocation,
379    bool add_no_cache_header) {
380  static const wchar_t kEchoHeader[] = L"/echoheader?";
381  if (request_uri.find(kEchoHeader) != std::wstring::npos) {
382    std::wstring header = request_uri.substr(
383        wcslen(kEchoHeader),
384        request_uri.length() - wcslen(kEchoHeader));
385
386    std::string header_value = http_utils::GetHttpHeaderFromHeaderList(
387        WideToUTF8(header), request.headers());
388    connection->Send(header_value, "");
389    return;
390  }
391  // Convert |request_uri| to a path.
392  std::wstring path = request_uri;
393  size_t query_index = request_uri.find(L"?");
394  if (query_index != std::string::npos) {
395    path = path.erase(query_index);
396  }
397  base::FilePath file_path = root_dir_;
398  if (path.size())
399    file_path = file_path.Append(path.substr(1));  // remove first '/'
400
401  std::string headers, body;
402  std::string content_type;
403  if (base::PathExists(file_path) &&
404      !base::DirectoryExists(file_path)) {
405    base::FilePath mock_http_headers(file_path.value() + L".mock-http-headers");
406    if (base::PathExists(mock_http_headers)) {
407      headers = GetMockHttpHeaders(mock_http_headers);
408      content_type = http_utils::GetHttpHeaderFromHeaderList("Content-type",
409                                                             headers);
410    } else {
411      EXPECT_TRUE(net::GetMimeTypeFromFile(file_path, &content_type));
412      VLOG(1) << "Going to send file (" << WideToUTF8(file_path.value())
413              << ") with content type (" << content_type << ")";
414      headers = CreateHttpHeaders(invocation, add_no_cache_header,
415                                  content_type);
416    }
417
418    EXPECT_FALSE(headers.empty());
419
420    EXPECT_TRUE(file_util::ReadFileToString(file_path, &body))
421        << "Could not read file (" << WideToUTF8(file_path.value()) << ")";
422    if (invocation.type() == CFInvocation::META_TAG &&
423        StartsWithASCII(content_type, "text/html", false)) {
424      EXPECT_TRUE(chrome_frame_test::AddCFMetaTag(&body)) << "Could not add "
425          << "meta tag to HTML file.";
426    }
427  } else {
428    VLOG(1) << "Going to send 404 for non-existent file ("
429            << WideToUTF8(file_path.value()) << ")";
430    headers = "HTTP/1.1 404 Not Found";
431    body = "";
432  }
433  connection->Send(headers, body);
434}
435
436const wchar_t kPostMessageBasicPage[] = L"postmessage_basic_host.html";
437
438TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PostMessageBasic) {
439  SimpleBrowserTest(IE, kPostMessageBasicPage);
440}
441
442TEST_F(ChromeFrameTestWithWebServer, FullTabIE_MIMEFilterBasic) {
443  const wchar_t kMIMEFilterBasicPage[] =
444      L"chrome_frame_mime_filter_test.html";
445
446  // If this test fails for IE8 then it is possible that prebinding is enabled.
447  // A known workaround is to disable it until CF properly handles it.
448  //
449  // HKCU\Software\Microsoft\Internet Explorer\Main
450  // Value name: EnablePreBinding (REG_DWORD)
451  // Value: 0
452  SimpleBrowserTest(IE, kMIMEFilterBasicPage);
453}
454
455// Times out: http://crbug.com/163728
456TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_Resize) {
457  SimpleBrowserTest(IE, L"chrome_frame_resize.html");
458}
459
460const wchar_t kNavigateURLAbsolutePage[] =
461    L"navigateurl_absolute_host.html";
462
463TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_NavigateURLAbsolute) {
464  SimpleBrowserTest(IE, kNavigateURLAbsolutePage);
465}
466
467const wchar_t kNavigateURLRelativePage[] =
468    L"navigateurl_relative_host.html";
469
470// Flaky, crbug.com/160497.
471TEST_F(ChromeFrameTestWithWebServer,
472       DISABLED_WidgetModeIE_NavigateURLRelative) {
473  SimpleBrowserTest(IE, kNavigateURLRelativePage);
474}
475
476const wchar_t kNavigateSimpleObjectFocus[] = L"simple_object_focus.html";
477
478TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_ObjectFocus) {
479  SimpleBrowserTest(IE, kNavigateSimpleObjectFocus);
480}
481
482const wchar_t kiframeBasicPage[] = L"iframe_basic_host.html";
483
484
485// Flaky, crbug.com/160497.
486TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_iframeBasic) {
487  SimpleBrowserTest(IE, kiframeBasicPage);
488}
489
490const wchar_t kSrcPropertyTestPage[] = L"src_property_host.html";
491
492TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_SrcProperty) {
493  SimpleBrowserTest(IE, kSrcPropertyTestPage);
494}
495
496const wchar_t kCFInstanceBasicTestPage[] = L"CFInstance_basic_host.html";
497
498TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceBasic) {
499  SimpleBrowserTest(IE, kCFInstanceBasicTestPage);
500}
501
502const wchar_t kCFISingletonPage[] = L"CFInstance_singleton_host.html";
503
504TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceSingleton) {
505  SimpleBrowserTest(IE, kCFISingletonPage);
506}
507
508const wchar_t kCFIDelayPage[] = L"CFInstance_delay_host.html";
509
510TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceDelay) {
511  SimpleBrowserTest(IE, kCFIDelayPage);
512}
513
514const wchar_t kCFIFallbackPage[] = L"CFInstance_fallback_host.html";
515
516TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceFallback) {
517  SimpleBrowserTest(IE, kCFIFallbackPage);
518}
519
520const wchar_t kCFINoSrcPage[] = L"CFInstance_no_src_host.html";
521
522// Flaky, crbug.com/160497.
523TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceNoSrc) {
524  SimpleBrowserTest(IE, kCFINoSrcPage);
525}
526
527const wchar_t kCFIIfrOnLoadPage[] = L"CFInstance_iframe_onload_host.html";
528
529// disabled since it's unlikely that we care about this case
530TEST_F(ChromeFrameTestWithWebServer,
531       DISABLED_WidgetModeIE_CFInstanceIfrOnLoad) {
532  SimpleBrowserTest(IE, kCFIIfrOnLoadPage);
533}
534
535const wchar_t kCFIZeroSizePage[] = L"CFInstance_zero_size_host.html";
536
537TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceZeroSize) {
538  SimpleBrowserTest(IE, kCFIZeroSizePage);
539}
540
541const wchar_t kCFIIfrPostPage[] = L"CFInstance_iframe_post_host.html";
542
543TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceIfrPost) {
544  SimpleBrowserTest(IE, kCFIIfrPostPage);
545}
546
547TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceIfrPost) {
548  SimpleBrowserTest(CHROME, kCFIIfrPostPage);
549}
550
551const wchar_t kCFIPostPage[] = L"CFInstance_post_host.html";
552
553TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstancePost) {
554  if (chrome_frame_test::GetInstalledIEVersion() == IE_9) {
555    LOG(INFO) << "Not running test on Vista/Windows 7 with IE9";
556    return;
557  }
558  SimpleBrowserTest(IE, kCFIPostPage);
559}
560
561// This test randomly fails on the ChromeFrame builder.
562TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstancePost) {
563  SimpleBrowserTest(CHROME, kCFIPostPage);
564}
565
566const wchar_t kCFIRPCPage[] = L"CFInstance_rpc_host.html";
567
568TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPC) {
569  if (chrome_frame_test::GetInstalledIEVersion() == IE_9) {
570    LOG(INFO) << "Not running test on Vista/Windows 7 with IE9";
571    return;
572  }
573  SimpleBrowserTest(IE, kCFIRPCPage);
574}
575
576TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPC) {
577  SimpleBrowserTest(CHROME, kCFIRPCPage);
578}
579
580const wchar_t kCFIRPCInternalPage[] =
581    L"CFInstance_rpc_internal_host.html";
582
583TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPCInternal) {
584  if (chrome_frame_test::GetInstalledIEVersion() == IE_9) {
585    LOG(INFO) << "Not running test on Vista/Windows 7 with IE9";
586    return;
587  }
588  SimpleBrowserTest(IE, kCFIRPCInternalPage);
589}
590
591TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPCInternal) {
592  SimpleBrowserTest(CHROME, kCFIRPCInternalPage);
593}
594
595const wchar_t kCFIDefaultCtorPage[] =
596    L"CFInstance_default_ctor_host.html";
597
598TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceDefaultCtor) {
599  SimpleBrowserTest(IE, kCFIDefaultCtorPage);
600}
601
602const wchar_t kCFInstallBasicTestPage[] = L"CFInstall_basic.html";
603
604TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallBasic) {
605  SimpleBrowserTest(IE, kCFInstallBasicTestPage);
606}
607
608const wchar_t kCFInstallPlaceTestPage[] = L"CFInstall_place.html";
609
610TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallPlace) {
611  SimpleBrowserTest(IE, kCFInstallPlaceTestPage);
612}
613
614const wchar_t kCFInstallOverlayTestPage[] = L"CFInstall_overlay.html";
615
616TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallOverlay) {
617  SimpleBrowserTest(IE, kCFInstallOverlayTestPage);
618}
619
620const wchar_t kCFInstallDismissTestPage[] = L"CFInstall_dismiss.html";
621
622TEST_F(ChromeFrameTestWithWebServer, FullTabIE_CFInstallDismiss) {
623  SimpleBrowserTest(IE, kCFInstallDismissTestPage);
624}
625
626const wchar_t kInitializeHiddenPage[] = L"initialize_hidden.html";
627// Times out: http://crbug.com/163728
628TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_InitializeHidden) {
629  SimpleBrowserTest(IE, kInitializeHiddenPage);
630}
631
632const wchar_t kFullTabHttpHeaderPage[] = L"chrome_frame_http_header.html";
633
634TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFHttpHeaderBasic) {
635  SimpleBrowserTest(IE, kFullTabHttpHeaderPage);
636}
637
638const wchar_t kFullTabHttpHeaderPageIFrame[] =
639    L"chrome_frame_http_header_host.html";
640
641TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFHttpHeaderIFrame) {
642  SimpleBrowserTest(IE, kFullTabHttpHeaderPageIFrame);
643}
644
645const wchar_t kFullTabHttpHeaderPageFrameset[] =
646    L"chrome_frame_http_header_frameset.html";
647
648TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFHttpHeaderFrameSet) {
649  SimpleBrowserTest(IE, kFullTabHttpHeaderPageFrameset);
650}
651
652const wchar_t kVersionPage[] = L"version.html";
653
654// Flaky, crbug.com/160497.
655TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_Version) {
656  VersionTest(IE, kVersionPage);
657}
658
659const wchar_t kEventListenerPage[] = L"event_listener.html";
660
661TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_EventListener) {
662  SimpleBrowserTest(IE, kEventListenerPage);
663}
664
665const wchar_t kPrivilegedApisPage[] = L"privileged_apis_host.html";
666
667TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PrivilegedApis) {
668  SimpleBrowserTest(IE, kPrivilegedApisPage);
669}
670
671const wchar_t kMetaTagPage[] = L"meta_tag.html";
672// Flaky, crbug.com/160497.
673TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_MetaTag) {
674  SimpleBrowserTest(IE, kMetaTagPage);
675}
676
677// Times out: http://crbug.com/163728
678const wchar_t kCFProtocolPage[] = L"cf_protocol.html";
679TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_CFProtocol) {
680  // Temporarily enable  gcf: protocol for this test.
681  SetConfigBool(kAllowUnsafeURLs, true);
682  SimpleBrowserTest(IE, kCFProtocolPage);
683  SetConfigBool(kAllowUnsafeURLs, false);
684}
685
686const wchar_t kPersistentCookieTest[] =
687    L"persistent_cookie_test_page.html";
688TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_PersistentCookieTest) {
689  SimpleBrowserTest(IE, kPersistentCookieTest);
690}
691
692const wchar_t kNavigateOutPage[] = L"navigate_out.html";
693TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_NavigateOut) {
694  SimpleBrowserTest(IE, kNavigateOutPage);
695}
696
697const wchar_t kReferrerMainTest[] = L"referrer_main.html";
698
699TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ReferrerTest) {
700  SimpleBrowserTest(IE, kReferrerMainTest);
701}
702
703// Times out: http://crbug.com/163728
704const wchar_t kSubFrameTestPage[] = L"full_tab_sub_frame_main.html";
705TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_SubFrame) {
706  SimpleBrowserTest(IE, kSubFrameTestPage);
707}
708
709const wchar_t kSubIFrameTestPage[] = L"full_tab_sub_iframe_main.html";
710TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_SubIFrame) {
711  SimpleBrowserTest(IE, kSubIFrameTestPage);
712}
713
714const wchar_t kXMLHttpRequestTestUrl[] =
715    L"xmlhttprequest_test.html";
716
717// Flaky, crbug.com/160497.
718TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_XHRTest) {
719  SimpleBrowserTest(IE, kXMLHttpRequestTestUrl);
720}
721
722const wchar_t kInstallFlowTestUrl[] =
723    L"install_flow_test.html";
724
725TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_InstallFlowTest) {
726  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
727    ScopedChromeFrameRegistrar::UnregisterAtPath(
728        GetChromeFrameBuildPath().value(),
729        chrome_frame_test::GetTestBedType());
730
731    ASSERT_TRUE(LaunchBrowser(IE, kInstallFlowTestUrl));
732
733    loop().RunFor(kChromeFrameLongNavigationTimeout);
734
735    ScopedChromeFrameRegistrar::RegisterAtPath(
736        GetChromeFrameBuildPath().value(),
737        chrome_frame_test::GetTestBedType());
738
739    ExpectAndHandlePostedResult();
740    loop().RunFor(kChromeFrameLongNavigationTimeout);
741
742    chrome_frame_test::CloseAllIEWindows();
743    ASSERT_EQ("OK", server_mock().posted_result());
744  }
745}
746
747const wchar_t kMultipleCFInstancesTestUrl[] =
748    L"multiple_cf_instances_main.html";
749
750TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_MultipleCFInstances) {
751  SimpleBrowserTest(IE, kMultipleCFInstancesTestUrl);
752}
753
754const wchar_t kXHRHeaderTestUrl[] =
755    L"xmlhttprequest_header_test.html";
756
757// Marking as flaky since it occasionally times out. crbug.com/127395.
758TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_XHRHeaderTest) {
759  SimpleBrowserTest(IE, kXHRHeaderTestUrl);
760}
761
762const wchar_t kDeleteCookieTest[] =
763    L"fulltab_delete_cookie_test.html";
764
765TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_DeleteCookieTest) {
766  SimpleBrowserTest(IE, kDeleteCookieTest);
767}
768
769const wchar_t kAnchorUrlNavigate[] =
770    L"fulltab_anchor_url_navigate.html#chrome_frame";
771
772TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_AnchorUrlNavigateTest) {
773  SimpleBrowserTest(IE, kAnchorUrlNavigate);
774}
775
776// Test whether POST-ing a form from an mshtml page to a CF page will cause
777// the request to get reissued.  It should not.
778// https://code.google.com/p/chromium/issues/detail?id=143699
779TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_TestPostReissue) {
780  // The order of pages in this array is assumed to be mshtml, cf, script.
781  const wchar_t* kPages[] = {
782    L"full_tab_post_mshtml.html",
783    L"full_tab_post_target_cf.html",
784    L"chrome_frame_tester_helpers.js",
785  };
786
787  SimpleWebServerTest server(local_address_, 46664);
788  server.PopulateStaticFileListT<test_server::FileResponse>(kPages,
789      arraysize(kPages), GetCFTestFilePath());
790
791  ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str()));
792
793  loop().RunFor(kChromeFrameLongNavigationTimeout);
794
795  const test_server::Request* request = NULL;
796  server.FindRequest("/quit?OK", &request);
797  ASSERT_TRUE(request != NULL);
798  EXPECT_EQ("OK", request->arguments());
799
800  if (request->arguments().compare("OK") == 0) {
801    // Check how many requests we got for the cf page.  Also expect it to be
802    // a POST.
803    int requests = server.GetRequestCountForPage(kPages[1], "POST");
804    EXPECT_EQ(1, requests);
805  }
806}
807
808// Test whether following a link from an mshtml page to a CF page will cause
809// multiple network requests.  It should not.
810// Flaky, crbug.com/160497.
811TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_TestMultipleGet) {
812  // The order of pages in this array is assumed to be mshtml, cf, script.
813  const wchar_t* kPages[] = {
814    L"full_tab_get_mshtml.html",
815    L"full_tab_get_target_cf.html",
816    L"chrome_frame_tester_helpers.js",
817  };
818
819  SimpleWebServerTest server(local_address_, 46664);
820
821  server.PopulateStaticFileListT<test_server::FileResponse>(kPages,
822      arraysize(kPages), GetCFTestFilePath());
823
824  ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str()));
825
826  loop().RunFor(kChromeFrameVeryLongNavigationTimeout);
827
828  const test_server::Request* request = NULL;
829  server.FindRequest("/quit?OK", &request);
830  ASSERT_TRUE(request != NULL);
831  EXPECT_EQ("OK", request->arguments());
832
833  if (request->arguments().compare("OK") == 0) {
834    // Check how many requests we got for the cf page and check that it was
835    // a GET.
836    int requests = server.GetRequestCountForPage(kPages[1], "GET");
837    EXPECT_EQ(1, requests);
838  }
839}
840
841const wchar_t kSetCookieTest[] =
842    L"fulltab_set_cookie_test.html";
843
844TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_SetCookieTest) {
845  SimpleBrowserTest(IE, kSetCookieTest);
846}
847
848const wchar_t kXHRConditionalHeaderTestUrl[] =
849    L"xmlhttprequest_conditional_header_test.html";
850
851TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_XHRConditionalHeaderTest) {
852  SimpleBrowserTest(IE, kXHRConditionalHeaderTestUrl);
853}
854
855const wchar_t kWindowCloseTestUrl[] =
856    L"window_close.html";
857
858TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowClose) {
859  SimpleBrowserTest(IE, kWindowCloseTestUrl);
860}
861
862std::string GetHeaderValue(const std::string& headers,
863                           const char* header_name) {
864  net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(),
865                                    "\r\n");
866  while (it.GetNext()) {
867    if (lstrcmpiA(it.name().c_str(), header_name) == 0) {
868      return it.values();
869    }
870  }
871  return "";
872}
873
874// Specialized implementation of test_server::FileResponse that supports
875// adding the request's User-Agent header to the returned document.
876// The class also supports $request_id$ which will be replaced with an
877// id that's incremented each time the response is sent over a socket.
878class UaTemplateFileResponse : public test_server::FileResponse {
879 public:
880  typedef test_server::FileResponse SuperClass;
881
882  UaTemplateFileResponse(const char* request_path,
883                         const base::FilePath& file_path)
884      : test_server::FileResponse(request_path, file_path), request_id_(0) {
885  }
886
887  virtual bool Matches(const test_server::Request& r) const {
888    bool ret = SuperClass::Matches(r);
889    if (ret)
890      ua_ = GetHeaderValue(r.headers(), "User-Agent");
891    return ret;
892  }
893
894  virtual size_t ContentLength() const {
895    const char kRequestIdTemplate[] = "$request_id$";
896    const char kUserAgentTemplate[] = "$UA$";
897
898    size_t length = SuperClass::ContentLength();
899    DCHECK(length);
900    content_.assign(reinterpret_cast<const char*>(file_->data()),
901                    file_->length());
902    size_t i = content_.find(kUserAgentTemplate);
903    if (i != std::string::npos)
904      content_.replace(i, arraysize(kUserAgentTemplate) - 1, ua_);
905    i = content_.find(kRequestIdTemplate);
906    if (i != std::string::npos) {
907      content_.replace(i, arraysize(kRequestIdTemplate) - 1,
908                       base::StringPrintf("%i", request_id_));
909    }
910    return content_.length();
911  }
912
913  virtual void WriteContents(net::StreamListenSocket* socket) const {
914    DCHECK(content_.length());
915    socket->Send(content_.c_str(), content_.length(), false);
916    request_id_++;
917  }
918
919 protected:
920  mutable std::string ua_;
921  mutable std::string content_;
922  mutable int request_id_;
923};
924
925// This test simulates a URL that on first request returns a document
926// that should be rendered in mshtml, then pops up a sign-in page that
927// after signing in, refreshes the original page that should then return
928// a page that needs to be rendered in GCF.
929//
930// This test currently fails because GCF does not add the chromeframe header
931// to requests that mshtml initiates via IInternetSession::CreateBinding.
932TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_RefreshMshtmlTest) {
933  const wchar_t* kPages[] = {
934    L"mshtml_refresh_test.html",
935    L"mshtml_refresh_test_popup.html",
936  };
937
938  SimpleWebServerTest server(local_address_, 46664);
939  server.PopulateStaticFileListT<UaTemplateFileResponse>(kPages,
940      arraysize(kPages), GetCFTestFilePath());
941
942  ASSERT_TRUE(LaunchBrowser(IE, server.FormatHttpPath(kPages[0]).c_str()));
943
944  loop().RunFor(kChromeFrameLongNavigationTimeout);
945
946  test_server::SimpleWebServer* ws = server.web_server();
947  const test_server::ConnectionList& connections = ws->connections();
948  test_server::ConnectionList::const_iterator it = connections.begin();
949  int requests_for_first_page = 0;
950  for (; it != connections.end(); ++it) {
951    test_server::Connection* c = (*it);
952    const test_server::Request& r = c->request();
953    if (!r.path().empty() &&
954        ASCIIToWide(r.path().substr(1)).compare(kPages[0]) == 0) {
955      requests_for_first_page++;
956      std::string ua(GetHeaderValue(r.headers(), "User-Agent"));
957      EXPECT_NE(std::string::npos, ua.find("chromeframe"));
958    }
959  }
960  EXPECT_GT(requests_for_first_page, 1);
961}
962
963// See bug 36694 for details.  http://crbug.com/36694
964TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestDownloadFromForm) {
965  chrome_frame_test::MockWindowObserver win_observer_mock;
966  win_observer_mock.WatchWindow("File Download", "");
967  win_observer_mock.WatchWindow("View Downloads*", "");
968
969  // The content of our HTML test page.  This will be returned whenever
970  // we reply to a GET request.
971  static const char kHtml[] =
972      "<html><head>\n"
973      "<title>ChromeFrame Form Download Test</title>\n"
974      // To see how this test runs with only IE (no CF in the picture), comment
975      // out this meta tag.  The outcome of the test should be identical.
976      "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />\n"
977      "</head>\n"
978      "<script language=\"javascript\">\n"
979      "function SubmitForm() {\n"
980      "  var form = document.forms['myform'];\n"
981      "  form.action = document.location;\n"
982      "  form.submit();\n"
983      "  return true;\n"
984      "}\n"
985      "</script>\n"
986      "<body onload=\"SubmitForm();\">\n"
987      "<form method=\"post\" action=\"foo.html\" id=\"myform\">\n"
988      "  <input type=\"hidden\" name=\"Field1\" value=\"myvalue\" />\n"
989      "  <input type=\"button\" name=\"btn\" value=\"Test Download\" "
990          "onclick=\"return SubmitForm();\" id=\"Button1\"/>\n"
991      "</form></body></html>\n";
992
993  // The content of our HTML test page.  This will be returned whenever
994  // we reply to a POST request.
995  static const char kText[] =
996      "This is a text file (in case you were wondering).";
997
998  // This http response class will return an HTML document that contains
999  // a form whenever it receives a GET request.  Whenever it gets a POST
1000  // request, it will respond with a text file that needs to be downloaded
1001  // (content-disposition is "attachment").
1002  class CustomResponse : public test_server::ResponseForPath {
1003   public:
1004    explicit CustomResponse(const char* path)
1005      : test_server::ResponseForPath(path), is_post_(false),
1006        post_requests_(0), get_requests_(0) {
1007    }
1008
1009    virtual bool GetContentType(std::string* content_type) const {
1010      DCHECK(!is_post_);
1011      return false;
1012    }
1013
1014    virtual size_t ContentLength() const {
1015      DCHECK(!is_post_);
1016      return sizeof(kHtml) - 1;
1017    }
1018
1019    virtual bool GetCustomHeaders(std::string* headers) const {
1020      if (!is_post_)
1021        return false;
1022      *headers = base::StringPrintf(
1023          "HTTP/1.1 200 OK\r\n"
1024          "Content-Disposition: attachment;filename=\"test.txt\"\r\n"
1025          "Content-Type: application/text\r\n"
1026          "Connection: close\r\n"
1027          "Content-Length: %i\r\n\r\n", sizeof(kText) - 1);
1028      return true;
1029    }
1030
1031    virtual bool Matches(const test_server::Request& r) const {
1032      bool match = __super::Matches(r);
1033      if (match) {
1034        is_post_ = LowerCaseEqualsASCII(r.method().c_str(), "post");
1035      }
1036      return match;
1037    }
1038
1039    virtual void WriteContents(net::StreamListenSocket* socket) const {
1040      if (is_post_) {
1041        socket->Send(kText, sizeof(kText) - 1, false);
1042      } else {
1043        socket->Send(kHtml, sizeof(kHtml) - 1, false);
1044      }
1045    }
1046
1047    virtual void IncrementAccessCounter() {
1048      __super::IncrementAccessCounter();
1049      if (is_post_) {
1050        post_requests_++;
1051      } else {
1052        get_requests_++;
1053      }
1054    }
1055
1056    size_t get_request_count() const {
1057      return get_requests_;
1058    }
1059
1060    size_t post_request_count() const {
1061      return get_requests_;
1062    }
1063
1064   protected:
1065    mutable bool is_post_;
1066    size_t post_requests_;
1067    size_t get_requests_;
1068  };
1069
1070  EXPECT_CALL(win_observer_mock, OnWindowOpen(_))
1071      .Times(testing::AtMost(1))
1072      .WillOnce(chrome_frame_test::DoCloseWindow());
1073
1074  EXPECT_CALL(win_observer_mock, OnWindowClose(_))
1075      .Times(testing::AtMost(1))
1076      .WillOnce(QUIT_LOOP(loop()));
1077
1078  SimpleWebServerTest server(local_address_, 46664);
1079  CustomResponse* response = new CustomResponse("/form.html");
1080  server.web_server()->AddResponse(response);
1081
1082  std::wstring url(server.FormatHttpPath(L"form.html"));
1083
1084  ASSERT_TRUE(LaunchBrowser(IE, url.c_str()));
1085  loop().RunFor(kChromeFrameLongNavigationTimeout);
1086
1087  EXPECT_EQ(1, response->get_request_count());
1088  EXPECT_EQ(1, response->post_request_count());
1089}
1090
1091// This test loads a large page and ensures that the full page contents are
1092// actually loaded via a self-validating HTML page. This is done due to a bug
1093// whereby the middle of the response stream would sometimes be truncated when
1094// loading a CF document. See http://crbug.com/178421 for details.
1095TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_LargePageLoad) {
1096  const wchar_t kLargePageLoadPage[] =
1097      L"chrome_frame_large_page.html";
1098
1099  SimpleBrowserTest(IE, kLargePageLoadPage);
1100}
1101