Audio indicator in each tab
[chromium-blink-merge.git] / chrome_frame / test / html_util_unittests.cc
blob66b05465a46add25ef5c3c884a7b0bd92808011f
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.
5 #include <windows.h>
6 #include <atlsecurity.h>
7 #include <shellapi.h>
8 #include <string>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/file_util.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_handle.h"
15 #include "base/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/process_util.h"
18 #include "base/utf_string_conversions.h"
19 #include "net/base/net_util.h"
21 #include "chrome/browser/automation/url_request_automation_job.h"
22 #include "chrome/common/chrome_version_info.h"
23 #include "chrome_frame/chrome_frame_automation.h"
24 #include "chrome_frame/chrome_frame_delegate.h"
25 #include "chrome_frame/html_utils.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "webkit/user_agent/user_agent_util.h"
29 const char kChromeFrameUserAgent[] = "chromeframe";
31 class HtmlUtilUnittest : public testing::Test {
32 protected:
33 // Constructor
34 HtmlUtilUnittest() {}
36 // Returns the test path given a test case.
37 virtual bool GetTestPath(const std::string& test_case, base::FilePath* path) {
38 if (!path) {
39 NOTREACHED();
40 return false;
43 base::FilePath test_path;
44 if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_path)) {
45 NOTREACHED();
46 return false;
49 test_path = test_path.AppendASCII("chrome_frame");
50 test_path = test_path.AppendASCII("test");
51 test_path = test_path.AppendASCII("html_util_test_data");
52 test_path = test_path.AppendASCII(test_case);
54 *path = test_path;
55 return true;
58 virtual bool GetTestData(const std::string& test_case, std::wstring* data) {
59 if (!data) {
60 NOTREACHED();
61 return false;
64 base::FilePath path;
65 if (!GetTestPath(test_case, &path)) {
66 NOTREACHED();
67 return false;
70 std::string raw_data;
71 file_util::ReadFileToString(path, &raw_data);
73 // Convert to wide using the "best effort" assurance described in
74 // string_util.h
75 data->assign(UTF8ToWide(raw_data));
76 return true;
80 TEST_F(HtmlUtilUnittest, BasicTest) {
81 std::wstring test_data;
82 GetTestData("basic_test.html", &test_data);
84 HTMLScanner scanner(test_data.c_str());
86 // Grab the meta tag from the document and ensure that we get exactly one.
87 HTMLScanner::StringRangeList tag_list;
88 scanner.GetTagsByName(L"meta", &tag_list, L"body");
89 ASSERT_EQ(1, tag_list.size());
91 // Pull out the http-equiv attribute and check its value:
92 HTMLScanner::StringRange attribute_value;
93 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
94 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
96 // Pull out the content attribute and check its value:
97 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
98 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
101 TEST_F(HtmlUtilUnittest, QuotesTest) {
102 std::wstring test_data;
103 GetTestData("quotes_test.html", &test_data);
105 HTMLScanner scanner(test_data.c_str());
107 // Grab the meta tag from the document and ensure that we get exactly one.
108 HTMLScanner::StringRangeList tag_list;
109 scanner.GetTagsByName(L"meta", &tag_list, L"body");
110 ASSERT_EQ(1, tag_list.size());
112 // Pull out the http-equiv attribute and check its value:
113 HTMLScanner::StringRange attribute_value;
114 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
115 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
117 // Pull out the content attribute and check its value:
118 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
119 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
122 TEST_F(HtmlUtilUnittest, DegenerateCasesTest) {
123 std::wstring test_data;
124 GetTestData("degenerate_cases_test.html", &test_data);
126 HTMLScanner scanner(test_data.c_str());
128 // Scan for meta tags in the document. We expect not to pick up the one
129 // that appears to be there since it is technically inside a quote block.
130 HTMLScanner::StringRangeList tag_list;
131 scanner.GetTagsByName(L"meta", &tag_list, L"body");
132 EXPECT_TRUE(tag_list.empty());
135 TEST_F(HtmlUtilUnittest, MultipleTagsTest) {
136 std::wstring test_data;
137 GetTestData("multiple_tags.html", &test_data);
139 HTMLScanner scanner(test_data.c_str());
141 // Grab the meta tag from the document and ensure that we get exactly three.
142 HTMLScanner::StringRangeList tag_list;
143 scanner.GetTagsByName(L"meta", &tag_list, L"body");
144 EXPECT_EQ(7, tag_list.size());
146 // Pull out the content attribute for each tag and check its value:
147 HTMLScanner::StringRange attribute_value;
148 HTMLScanner::StringRangeList::const_iterator tag_list_iter(
149 tag_list.begin());
150 int valid_tag_count = 0;
151 for (; tag_list_iter != tag_list.end(); tag_list_iter++) {
152 HTMLScanner::StringRange attribute_value;
153 if (tag_list_iter->GetTagAttribute(L"http-equiv", &attribute_value) &&
154 attribute_value.Equals(L"X-UA-Compatible")) {
155 EXPECT_TRUE(tag_list_iter->GetTagAttribute(L"content", &attribute_value));
156 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
157 valid_tag_count++;
160 EXPECT_EQ(3, valid_tag_count);
163 TEST_F(HtmlUtilUnittest, ShortDegenerateTest1) {
164 std::wstring test_data(
165 L"<foo><META http-equiv=X-UA-Compatible content='chrome=1'");
167 HTMLScanner scanner(test_data.c_str());
169 // Scan for meta tags in the document. We expect not to pick up the one
170 // that is there since it is not properly closed.
171 HTMLScanner::StringRangeList tag_list;
172 scanner.GetTagsByName(L"meta", &tag_list, L"body");
173 EXPECT_TRUE(tag_list.empty());
176 TEST_F(HtmlUtilUnittest, ShortDegenerateTest2) {
177 std::wstring test_data(
178 L"<foo <META http-equiv=X-UA-Compatible content='chrome=1'/>");
180 HTMLScanner scanner(test_data.c_str());
182 // Scan for meta tags in the document. We expect not to pick up the one
183 // that appears to be there since it is inside a non-closed tag.
184 HTMLScanner::StringRangeList tag_list;
185 scanner.GetTagsByName(L"meta", &tag_list, L"body");
186 EXPECT_TRUE(tag_list.empty());
189 TEST_F(HtmlUtilUnittest, QuoteInsideHTMLCommentTest) {
190 std::wstring test_data(
191 L"<!-- comment' --><META http-equiv=X-UA-Compatible content='chrome=1'/>");
193 HTMLScanner scanner(test_data.c_str());
195 // Grab the meta tag from the document and ensure that we get exactly one.
196 HTMLScanner::StringRangeList tag_list;
197 scanner.GetTagsByName(L"meta", &tag_list, L"body");
198 ASSERT_EQ(1, tag_list.size());
200 // Pull out the http-equiv attribute and check its value:
201 HTMLScanner::StringRange attribute_value;
202 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
203 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
205 // Pull out the content attribute and check its value:
206 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
207 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
210 TEST_F(HtmlUtilUnittest, CloseTagInsideHTMLCommentTest) {
211 std::wstring test_data(
212 L"<!-- comment> <META http-equiv=X-UA-Compatible content='chrome=1'/>-->");
214 HTMLScanner scanner(test_data.c_str());
216 // Ensure that the the meta tag is NOT detected.
217 HTMLScanner::StringRangeList tag_list;
218 scanner.GetTagsByName(L"meta", &tag_list, L"body");
219 ASSERT_TRUE(tag_list.empty());
222 TEST_F(HtmlUtilUnittest, IEConditionalCommentTest) {
223 std::wstring test_data(
224 L"<!--[if lte IE 8]><META http-equiv=X-UA-Compatible content='chrome=1'/>"
225 L"<![endif]-->");
227 HTMLScanner scanner(test_data.c_str());
229 // Ensure that the the meta tag IS detected.
230 HTMLScanner::StringRangeList tag_list;
231 scanner.GetTagsByName(L"meta", &tag_list, L"body");
232 ASSERT_EQ(1, tag_list.size());
235 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithNestedCommentTest) {
236 std::wstring test_data(
237 L"<!--[if IE]><!--<META http-equiv=X-UA-Compatible content='chrome=1'/>"
238 L"--><![endif]-->");
240 HTMLScanner scanner(test_data.c_str());
242 // Ensure that the the meta tag IS NOT detected.
243 HTMLScanner::StringRangeList tag_list;
244 scanner.GetTagsByName(L"meta", &tag_list, L"body");
245 ASSERT_TRUE(tag_list.empty());
248 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithMultipleNestedTagsTest) {
249 std::wstring test_data(
250 L"<!--[if lte IE 8]> <META http-equiv=X-UA-Compatible "
251 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]-->"
252 L"<boo hoo><boo hah>");
254 HTMLScanner scanner(test_data.c_str());
256 // Ensure that the the meta tag IS detected.
257 HTMLScanner::StringRangeList meta_tag_list;
258 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
259 ASSERT_EQ(1, meta_tag_list.size());
261 // Ensure that the foo tags are also detected.
262 HTMLScanner::StringRangeList foo_tag_list;
263 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
264 ASSERT_EQ(2, foo_tag_list.size());
266 // Ensure that the boo tags are also detected.
267 HTMLScanner::StringRangeList boo_tag_list;
268 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
269 ASSERT_EQ(2, boo_tag_list.size());
272 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithAlternateEndingTest) {
273 std::wstring test_data(
274 L"<!--[if lte IE 8]> <META http-equiv=X-UA-Compatible "
275 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]>"
276 L"<boo hoo><!--><boo hah>");
278 HTMLScanner scanner(test_data.c_str());
280 // Ensure that the the meta tag IS detected.
281 HTMLScanner::StringRangeList meta_tag_list;
282 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
283 ASSERT_EQ(1, meta_tag_list.size());
285 // Ensure that the foo tags are also detected.
286 HTMLScanner::StringRangeList foo_tag_list;
287 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
288 ASSERT_EQ(2, foo_tag_list.size());
290 // Ensure that the boo tags are also detected.
291 HTMLScanner::StringRangeList boo_tag_list;
292 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
293 ASSERT_EQ(2, boo_tag_list.size());
296 TEST_F(HtmlUtilUnittest, IEConditionalCommentNonTerminatedTest) {
297 // This test shouldn't detect any tags up until the end of the conditional
298 // comment tag.
299 std::wstring test_data(
300 L"<!--[if lte IE 8> <META http-equiv=X-UA-Compatible "
301 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]>"
302 L"<boo hoo><!--><boo hah>");
304 HTMLScanner scanner(test_data.c_str());
306 // Ensure that the the meta tag IS NOT detected.
307 HTMLScanner::StringRangeList meta_tag_list;
308 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
309 ASSERT_TRUE(meta_tag_list.empty());
311 // Ensure that the foo tags are NOT detected.
312 HTMLScanner::StringRangeList foo_tag_list;
313 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
314 ASSERT_TRUE(foo_tag_list.empty());
316 // Ensure that the boo tags are detected.
317 HTMLScanner::StringRangeList boo_tag_list;
318 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
319 ASSERT_EQ(2, boo_tag_list.size());
322 struct UserAgentTestCase {
323 std::string input_;
324 std::string expected_;
325 } user_agent_test_cases[] = {
327 "", ""
328 }, {
329 "Mozilla/4.7 [en] (WinNT; U)",
330 "Mozilla/4.7 [en] (WinNT; U; chromeframe/0.0.0.0)"
331 }, {
332 "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)",
333 "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; chromeframe/0.0.0.0)"
334 }, {
335 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; "
336 ".NET CLR 1.1.4322)",
337 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; "
338 ".NET CLR 1.1.4322; chromeframe/0.0.0.0)"
339 }, {
340 "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 5.11 [en]",
341 "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0; chromeframe/0.0.0.0) "
342 "Opera 5.11 [en]"
343 }, {
344 "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
345 "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; "
346 "chromeframe/0.0.0.0)"
347 }, {
348 "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) "
349 "Gecko/20030208 Netscape/7.02",
350 "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2; "
351 "chromeframe/0.0.0.0) Gecko/20030208 Netscape/7.02"
352 }, {
353 "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040612 "
354 "Firefox/0.8",
355 "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6; chromeframe/0.0.0.0) "
356 "Gecko/20040612 Firefox/0.8"
357 }, {
358 "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)",
359 "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; chromeframe/0.0.0.0) "
360 "(KHTML, like Gecko)"
361 }, {
362 "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6h",
363 "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 "
364 "OpenSSL/0.9.6h chromeframe/0.0.0.0",
365 }, {
366 "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.7.10) "
367 "Gecko/20050716 Firefox/1.0.6",
368 "Mozilla/5.0 (X11; U; Linux i686 (x86_64; chromeframe/0.0.0.0); en-US; "
369 "rv:1.7.10) Gecko/20050716 Firefox/1.0.6"
370 }, {
371 "Invalid/1.1 ((((((",
372 "Invalid/1.1 (((((( chromeframe/0.0.0.0",
373 }, {
374 "Invalid/1.1 ()))))",
375 "Invalid/1.1 ( chromeframe/0.0.0.0)))))",
376 }, {
377 "Strange/1.1 ()",
378 "Strange/1.1 ( chromeframe/0.0.0.0)",
382 TEST_F(HtmlUtilUnittest, AddChromeFrameToUserAgentValue) {
383 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
384 std::string new_ua(
385 http_utils::AddChromeFrameToUserAgentValue(
386 user_agent_test_cases[i].input_));
387 EXPECT_EQ(user_agent_test_cases[i].expected_, new_ua);
390 // Now do the same test again, but test that we don't add the chromeframe
391 // tag if we've already added it.
392 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
393 std::string ua(user_agent_test_cases[i].expected_);
394 std::string new_ua(http_utils::AddChromeFrameToUserAgentValue(ua));
395 EXPECT_EQ(user_agent_test_cases[i].expected_, new_ua);
399 TEST_F(HtmlUtilUnittest, RemoveChromeFrameFromUserAgentValue) {
400 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
401 std::string new_ua(
402 http_utils::RemoveChromeFrameFromUserAgentValue(
403 user_agent_test_cases[i].expected_));
404 EXPECT_EQ(user_agent_test_cases[i].input_, new_ua);
407 // Also test that we don't modify the UA if chromeframe is not present.
408 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
409 std::string ua(user_agent_test_cases[i].input_);
410 std::string new_ua(http_utils::RemoveChromeFrameFromUserAgentValue(ua));
411 EXPECT_EQ(user_agent_test_cases[i].input_, new_ua);
415 TEST_F(HtmlUtilUnittest, GetDefaultUserAgentHeaderWithCFTag) {
416 std::string ua(http_utils::GetDefaultUserAgentHeaderWithCFTag());
417 EXPECT_NE(0u, ua.length());
418 EXPECT_NE(std::string::npos, ua.find("Mozilla"));
419 EXPECT_NE(std::string::npos, ua.find(kChromeFrameUserAgent));
422 TEST_F(HtmlUtilUnittest, GetChromeUserAgent) {
423 // This code is duplicated from chrome_content_client.cc to avoid
424 // introducing a link-time dependency on chrome_common.
425 chrome::VersionInfo version_info;
426 std::string product("Chrome/");
427 product += version_info.is_valid() ? version_info.Version() : "0.0.0.0";
428 std::string chrome_ua(webkit_glue::BuildUserAgentFromProduct(product));
430 const char* ua = http_utils::GetChromeUserAgent();
431 EXPECT_EQ(ua, chrome_ua);
434 TEST_F(HtmlUtilUnittest, GetDefaultUserAgent) {
435 std::string ua(http_utils::GetDefaultUserAgent());
436 EXPECT_NE(0u, ua.length());
437 EXPECT_NE(std::string::npos, ua.find("Mozilla"));
440 TEST_F(HtmlUtilUnittest, GetChromeFrameUserAgent) {
441 const char* call1 = http_utils::GetChromeFrameUserAgent();
442 const char* call2 = http_utils::GetChromeFrameUserAgent();
443 // Expect static buffer since caller does no cleanup.
444 EXPECT_EQ(call1, call2);
445 std::string ua(call1);
446 EXPECT_EQ("chromeframe/0.0.0.0", ua);
449 TEST(HttpUtils, HasFrameBustingHeader) {
450 // Simple negative cases.
451 EXPECT_FALSE(http_utils::HasFrameBustingHeader(""));
452 EXPECT_FALSE(http_utils::HasFrameBustingHeader("Content-Type: text/plain"));
453 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Optionss: ALLOWALL"));
454 // Explicit negative cases, test that we ignore case.
455 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: ALLOWALL"));
456 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: allowall"));
457 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: ALLowalL"));
458 // Added space, ensure stripped out
459 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
460 "X-Frame-Options: ALLOWALL "));
461 // Added space with linefeed, ensure still stripped out
462 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
463 "X-Frame-Options: ALLOWALL \r\n"));
464 // Multiple identical headers, all of them allowing framing.
465 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
466 "X-Frame-Options: ALLOWALL\r\n"
467 "X-Frame-Options: ALLOWALL\r\n"
468 "X-Frame-Options: ALLOWALL"));
469 // Interleave with other headers.
470 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
471 "Content-Type: text/plain\r\n"
472 "X-Frame-Options: ALLOWALL\r\n"
473 "Content-Length: 42"));
475 // Simple positive cases.
476 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-Frame-Options: deny"));
477 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
478 "X-Frame-Options: SAMEorigin"));
480 // Verify that we pick up case changes in the header name too:
481 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-FRAME-OPTIONS: deny"));
482 EXPECT_TRUE(http_utils::HasFrameBustingHeader("x-frame-options: deny"));
483 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-frame-optionS: deny"));
484 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-Frame-optionS: deny"));
486 // Allowall entries do not override the denying entries, are
487 // order-independent, and the deny entries can interleave with
488 // other headers.
489 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
490 "Content-Length: 42\r\n"
491 "X-Frame-Options: ALLOWall\r\n"
492 "X-Frame-Options: deny\r\n"));
493 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
494 "X-Frame-Options: ALLOWall\r\n"
495 "Content-Length: 42\r\n"
496 "X-Frame-Options: SAMEORIGIN\r\n"));
497 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
498 "X-Frame-Options: deny\r\n"
499 "X-Frame-Options: ALLOWall\r\n"
500 "Content-Length: 42\r\n"));
501 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
502 "X-Frame-Options: SAMEORIGIN\r\n"
503 "X-Frame-Options: ALLOWall\r\n"));