Roll leveldb to r76.
[chromium-blink-merge.git] / chrome_frame / test / html_util_unittests.cc
blob5431f1e747d1d5ea9e94c99b0b77de4102af7709
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/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "net/base/net_util.h"
20 #include "chrome/browser/automation/url_request_automation_job.h"
21 #include "chrome/common/chrome_version_info.h"
22 #include "chrome_frame/chrome_frame_automation.h"
23 #include "chrome_frame/chrome_frame_delegate.h"
24 #include "chrome_frame/html_utils.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "webkit/common/user_agent/user_agent_util.h"
28 const char kChromeFrameUserAgent[] = "chromeframe";
30 class HtmlUtilUnittest : public testing::Test {
31 protected:
32 // Constructor
33 HtmlUtilUnittest() {}
35 // Returns the test path given a test case.
36 virtual bool GetTestPath(const std::string& test_case, base::FilePath* path) {
37 if (!path) {
38 NOTREACHED();
39 return false;
42 base::FilePath test_path;
43 if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_path)) {
44 NOTREACHED();
45 return false;
48 test_path = test_path.AppendASCII("chrome_frame");
49 test_path = test_path.AppendASCII("test");
50 test_path = test_path.AppendASCII("html_util_test_data");
51 test_path = test_path.AppendASCII(test_case);
53 *path = test_path;
54 return true;
57 virtual bool GetTestData(const std::string& test_case, std::wstring* data) {
58 if (!data) {
59 NOTREACHED();
60 return false;
63 base::FilePath path;
64 if (!GetTestPath(test_case, &path)) {
65 NOTREACHED();
66 return false;
69 std::string raw_data;
70 file_util::ReadFileToString(path, &raw_data);
72 // Convert to wide using the "best effort" assurance described in
73 // string_util.h
74 data->assign(UTF8ToWide(raw_data));
75 return true;
79 TEST_F(HtmlUtilUnittest, BasicTest) {
80 std::wstring test_data;
81 GetTestData("basic_test.html", &test_data);
83 HTMLScanner scanner(test_data.c_str());
85 // Grab the meta tag from the document and ensure that we get exactly one.
86 HTMLScanner::StringRangeList tag_list;
87 scanner.GetTagsByName(L"meta", &tag_list, L"body");
88 ASSERT_EQ(1, tag_list.size());
90 // Pull out the http-equiv attribute and check its value:
91 HTMLScanner::StringRange attribute_value;
92 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
93 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
95 // Pull out the content attribute and check its value:
96 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
97 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
100 TEST_F(HtmlUtilUnittest, QuotesTest) {
101 std::wstring test_data;
102 GetTestData("quotes_test.html", &test_data);
104 HTMLScanner scanner(test_data.c_str());
106 // Grab the meta tag from the document and ensure that we get exactly one.
107 HTMLScanner::StringRangeList tag_list;
108 scanner.GetTagsByName(L"meta", &tag_list, L"body");
109 ASSERT_EQ(1, tag_list.size());
111 // Pull out the http-equiv attribute and check its value:
112 HTMLScanner::StringRange attribute_value;
113 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
114 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
116 // Pull out the content attribute and check its value:
117 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
118 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
121 TEST_F(HtmlUtilUnittest, DegenerateCasesTest) {
122 std::wstring test_data;
123 GetTestData("degenerate_cases_test.html", &test_data);
125 HTMLScanner scanner(test_data.c_str());
127 // Scan for meta tags in the document. We expect not to pick up the one
128 // that appears to be there since it is technically inside a quote block.
129 HTMLScanner::StringRangeList tag_list;
130 scanner.GetTagsByName(L"meta", &tag_list, L"body");
131 EXPECT_TRUE(tag_list.empty());
134 TEST_F(HtmlUtilUnittest, MultipleTagsTest) {
135 std::wstring test_data;
136 GetTestData("multiple_tags.html", &test_data);
138 HTMLScanner scanner(test_data.c_str());
140 // Grab the meta tag from the document and ensure that we get exactly three.
141 HTMLScanner::StringRangeList tag_list;
142 scanner.GetTagsByName(L"meta", &tag_list, L"body");
143 EXPECT_EQ(7, tag_list.size());
145 // Pull out the content attribute for each tag and check its value:
146 HTMLScanner::StringRange attribute_value;
147 HTMLScanner::StringRangeList::const_iterator tag_list_iter(
148 tag_list.begin());
149 int valid_tag_count = 0;
150 for (; tag_list_iter != tag_list.end(); tag_list_iter++) {
151 HTMLScanner::StringRange attribute_value;
152 if (tag_list_iter->GetTagAttribute(L"http-equiv", &attribute_value) &&
153 attribute_value.Equals(L"X-UA-Compatible")) {
154 EXPECT_TRUE(tag_list_iter->GetTagAttribute(L"content", &attribute_value));
155 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
156 valid_tag_count++;
159 EXPECT_EQ(3, valid_tag_count);
162 TEST_F(HtmlUtilUnittest, ShortDegenerateTest1) {
163 std::wstring test_data(
164 L"<foo><META http-equiv=X-UA-Compatible content='chrome=1'");
166 HTMLScanner scanner(test_data.c_str());
168 // Scan for meta tags in the document. We expect not to pick up the one
169 // that is there since it is not properly closed.
170 HTMLScanner::StringRangeList tag_list;
171 scanner.GetTagsByName(L"meta", &tag_list, L"body");
172 EXPECT_TRUE(tag_list.empty());
175 TEST_F(HtmlUtilUnittest, ShortDegenerateTest2) {
176 std::wstring test_data(
177 L"<foo <META http-equiv=X-UA-Compatible content='chrome=1'/>");
179 HTMLScanner scanner(test_data.c_str());
181 // Scan for meta tags in the document. We expect not to pick up the one
182 // that appears to be there since it is inside a non-closed tag.
183 HTMLScanner::StringRangeList tag_list;
184 scanner.GetTagsByName(L"meta", &tag_list, L"body");
185 EXPECT_TRUE(tag_list.empty());
188 TEST_F(HtmlUtilUnittest, QuoteInsideHTMLCommentTest) {
189 std::wstring test_data(
190 L"<!-- comment' --><META http-equiv=X-UA-Compatible content='chrome=1'/>");
192 HTMLScanner scanner(test_data.c_str());
194 // Grab the meta tag from the document and ensure that we get exactly one.
195 HTMLScanner::StringRangeList tag_list;
196 scanner.GetTagsByName(L"meta", &tag_list, L"body");
197 ASSERT_EQ(1, tag_list.size());
199 // Pull out the http-equiv attribute and check its value:
200 HTMLScanner::StringRange attribute_value;
201 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"http-equiv", &attribute_value));
202 EXPECT_TRUE(attribute_value.Equals(L"X-UA-Compatible"));
204 // Pull out the content attribute and check its value:
205 EXPECT_TRUE(tag_list[0].GetTagAttribute(L"content", &attribute_value));
206 EXPECT_TRUE(attribute_value.Equals(L"chrome=1"));
209 TEST_F(HtmlUtilUnittest, CloseTagInsideHTMLCommentTest) {
210 std::wstring test_data(
211 L"<!-- comment> <META http-equiv=X-UA-Compatible content='chrome=1'/>-->");
213 HTMLScanner scanner(test_data.c_str());
215 // Ensure that the the meta tag is NOT detected.
216 HTMLScanner::StringRangeList tag_list;
217 scanner.GetTagsByName(L"meta", &tag_list, L"body");
218 ASSERT_TRUE(tag_list.empty());
221 TEST_F(HtmlUtilUnittest, IEConditionalCommentTest) {
222 std::wstring test_data(
223 L"<!--[if lte IE 8]><META http-equiv=X-UA-Compatible content='chrome=1'/>"
224 L"<![endif]-->");
226 HTMLScanner scanner(test_data.c_str());
228 // Ensure that the the meta tag IS detected.
229 HTMLScanner::StringRangeList tag_list;
230 scanner.GetTagsByName(L"meta", &tag_list, L"body");
231 ASSERT_EQ(1, tag_list.size());
234 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithNestedCommentTest) {
235 std::wstring test_data(
236 L"<!--[if IE]><!--<META http-equiv=X-UA-Compatible content='chrome=1'/>"
237 L"--><![endif]-->");
239 HTMLScanner scanner(test_data.c_str());
241 // Ensure that the the meta tag IS NOT detected.
242 HTMLScanner::StringRangeList tag_list;
243 scanner.GetTagsByName(L"meta", &tag_list, L"body");
244 ASSERT_TRUE(tag_list.empty());
247 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithMultipleNestedTagsTest) {
248 std::wstring test_data(
249 L"<!--[if lte IE 8]> <META http-equiv=X-UA-Compatible "
250 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]-->"
251 L"<boo hoo><boo hah>");
253 HTMLScanner scanner(test_data.c_str());
255 // Ensure that the the meta tag IS detected.
256 HTMLScanner::StringRangeList meta_tag_list;
257 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
258 ASSERT_EQ(1, meta_tag_list.size());
260 // Ensure that the foo tags are also detected.
261 HTMLScanner::StringRangeList foo_tag_list;
262 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
263 ASSERT_EQ(2, foo_tag_list.size());
265 // Ensure that the boo tags are also detected.
266 HTMLScanner::StringRangeList boo_tag_list;
267 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
268 ASSERT_EQ(2, boo_tag_list.size());
271 TEST_F(HtmlUtilUnittest, IEConditionalCommentWithAlternateEndingTest) {
272 std::wstring test_data(
273 L"<!--[if lte IE 8]> <META http-equiv=X-UA-Compatible "
274 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]>"
275 L"<boo hoo><!--><boo hah>");
277 HTMLScanner scanner(test_data.c_str());
279 // Ensure that the the meta tag IS detected.
280 HTMLScanner::StringRangeList meta_tag_list;
281 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
282 ASSERT_EQ(1, meta_tag_list.size());
284 // Ensure that the foo tags are also detected.
285 HTMLScanner::StringRangeList foo_tag_list;
286 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
287 ASSERT_EQ(2, foo_tag_list.size());
289 // Ensure that the boo tags are also detected.
290 HTMLScanner::StringRangeList boo_tag_list;
291 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
292 ASSERT_EQ(2, boo_tag_list.size());
295 TEST_F(HtmlUtilUnittest, IEConditionalCommentNonTerminatedTest) {
296 // This test shouldn't detect any tags up until the end of the conditional
297 // comment tag.
298 std::wstring test_data(
299 L"<!--[if lte IE 8> <META http-equiv=X-UA-Compatible "
300 L"content='chrome=1'/><foo bar></foo><foo baz/><![endif]>"
301 L"<boo hoo><!--><boo hah>");
303 HTMLScanner scanner(test_data.c_str());
305 // Ensure that the the meta tag IS NOT detected.
306 HTMLScanner::StringRangeList meta_tag_list;
307 scanner.GetTagsByName(L"meta", &meta_tag_list, L"body");
308 ASSERT_TRUE(meta_tag_list.empty());
310 // Ensure that the foo tags are NOT detected.
311 HTMLScanner::StringRangeList foo_tag_list;
312 scanner.GetTagsByName(L"foo", &foo_tag_list, L"body");
313 ASSERT_TRUE(foo_tag_list.empty());
315 // Ensure that the boo tags are detected.
316 HTMLScanner::StringRangeList boo_tag_list;
317 scanner.GetTagsByName(L"boo", &boo_tag_list, L"body");
318 ASSERT_EQ(2, boo_tag_list.size());
321 struct UserAgentTestCase {
322 std::string input_;
323 std::string expected_;
324 } user_agent_test_cases[] = {
326 "", ""
327 }, {
328 "Mozilla/4.7 [en] (WinNT; U)",
329 "Mozilla/4.7 [en] (WinNT; U; chromeframe/0.0.0.0)"
330 }, {
331 "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)",
332 "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; chromeframe/0.0.0.0)"
333 }, {
334 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; "
335 ".NET CLR 1.1.4322)",
336 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; "
337 ".NET CLR 1.1.4322; chromeframe/0.0.0.0)"
338 }, {
339 "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 5.11 [en]",
340 "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0; chromeframe/0.0.0.0) "
341 "Opera 5.11 [en]"
342 }, {
343 "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
344 "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; "
345 "chromeframe/0.0.0.0)"
346 }, {
347 "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) "
348 "Gecko/20030208 Netscape/7.02",
349 "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2; "
350 "chromeframe/0.0.0.0) Gecko/20030208 Netscape/7.02"
351 }, {
352 "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040612 "
353 "Firefox/0.8",
354 "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6; chromeframe/0.0.0.0) "
355 "Gecko/20040612 Firefox/0.8"
356 }, {
357 "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)",
358 "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; chromeframe/0.0.0.0) "
359 "(KHTML, like Gecko)"
360 }, {
361 "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6h",
362 "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 "
363 "OpenSSL/0.9.6h chromeframe/0.0.0.0",
364 }, {
365 "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.7.10) "
366 "Gecko/20050716 Firefox/1.0.6",
367 "Mozilla/5.0 (X11; U; Linux i686 (x86_64; chromeframe/0.0.0.0); en-US; "
368 "rv:1.7.10) Gecko/20050716 Firefox/1.0.6"
369 }, {
370 "Invalid/1.1 ((((((",
371 "Invalid/1.1 (((((( chromeframe/0.0.0.0",
372 }, {
373 "Invalid/1.1 ()))))",
374 "Invalid/1.1 ( chromeframe/0.0.0.0)))))",
375 }, {
376 "Strange/1.1 ()",
377 "Strange/1.1 ( chromeframe/0.0.0.0)",
381 TEST_F(HtmlUtilUnittest, AddChromeFrameToUserAgentValue) {
382 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
383 std::string new_ua(
384 http_utils::AddChromeFrameToUserAgentValue(
385 user_agent_test_cases[i].input_));
386 EXPECT_EQ(user_agent_test_cases[i].expected_, new_ua);
389 // Now do the same test again, but test that we don't add the chromeframe
390 // tag if we've already added it.
391 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
392 std::string ua(user_agent_test_cases[i].expected_);
393 std::string new_ua(http_utils::AddChromeFrameToUserAgentValue(ua));
394 EXPECT_EQ(user_agent_test_cases[i].expected_, new_ua);
398 TEST_F(HtmlUtilUnittest, RemoveChromeFrameFromUserAgentValue) {
399 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
400 std::string new_ua(
401 http_utils::RemoveChromeFrameFromUserAgentValue(
402 user_agent_test_cases[i].expected_));
403 EXPECT_EQ(user_agent_test_cases[i].input_, new_ua);
406 // Also test that we don't modify the UA if chromeframe is not present.
407 for (int i = 0; i < arraysize(user_agent_test_cases); ++i) {
408 std::string ua(user_agent_test_cases[i].input_);
409 std::string new_ua(http_utils::RemoveChromeFrameFromUserAgentValue(ua));
410 EXPECT_EQ(user_agent_test_cases[i].input_, new_ua);
414 TEST_F(HtmlUtilUnittest, GetDefaultUserAgentHeaderWithCFTag) {
415 std::string ua(http_utils::GetDefaultUserAgentHeaderWithCFTag());
416 EXPECT_NE(0u, ua.length());
417 EXPECT_NE(std::string::npos, ua.find("Mozilla"));
418 EXPECT_NE(std::string::npos, ua.find(kChromeFrameUserAgent));
421 TEST_F(HtmlUtilUnittest, GetChromeUserAgent) {
422 // This code is duplicated from chrome_content_client.cc to avoid
423 // introducing a link-time dependency on chrome_common.
424 chrome::VersionInfo version_info;
425 std::string product("Chrome/");
426 product += version_info.is_valid() ? version_info.Version() : "0.0.0.0";
427 std::string chrome_ua(webkit_glue::BuildUserAgentFromProduct(product));
429 const char* ua = http_utils::GetChromeUserAgent();
430 EXPECT_EQ(ua, chrome_ua);
433 TEST_F(HtmlUtilUnittest, GetDefaultUserAgent) {
434 std::string ua(http_utils::GetDefaultUserAgent());
435 EXPECT_NE(0u, ua.length());
436 EXPECT_NE(std::string::npos, ua.find("Mozilla"));
439 TEST_F(HtmlUtilUnittest, GetChromeFrameUserAgent) {
440 const char* call1 = http_utils::GetChromeFrameUserAgent();
441 const char* call2 = http_utils::GetChromeFrameUserAgent();
442 // Expect static buffer since caller does no cleanup.
443 EXPECT_EQ(call1, call2);
444 std::string ua(call1);
445 EXPECT_EQ("chromeframe/0.0.0.0", ua);
448 TEST(HttpUtils, HasFrameBustingHeader) {
449 // Simple negative cases.
450 EXPECT_FALSE(http_utils::HasFrameBustingHeader(""));
451 EXPECT_FALSE(http_utils::HasFrameBustingHeader("Content-Type: text/plain"));
452 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Optionss: ALLOWALL"));
453 // Explicit negative cases, test that we ignore case.
454 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: ALLOWALL"));
455 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: allowall"));
456 EXPECT_FALSE(http_utils::HasFrameBustingHeader("X-Frame-Options: ALLowalL"));
457 // Added space, ensure stripped out
458 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
459 "X-Frame-Options: ALLOWALL "));
460 // Added space with linefeed, ensure still stripped out
461 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
462 "X-Frame-Options: ALLOWALL \r\n"));
463 // Multiple identical headers, all of them allowing framing.
464 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
465 "X-Frame-Options: ALLOWALL\r\n"
466 "X-Frame-Options: ALLOWALL\r\n"
467 "X-Frame-Options: ALLOWALL"));
468 // Interleave with other headers.
469 EXPECT_FALSE(http_utils::HasFrameBustingHeader(
470 "Content-Type: text/plain\r\n"
471 "X-Frame-Options: ALLOWALL\r\n"
472 "Content-Length: 42"));
474 // Simple positive cases.
475 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-Frame-Options: deny"));
476 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
477 "X-Frame-Options: SAMEorigin"));
479 // Verify that we pick up case changes in the header name too:
480 EXPECT_TRUE(http_utils::HasFrameBustingHeader("X-FRAME-OPTIONS: deny"));
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"));
485 // Allowall entries do not override the denying entries, are
486 // order-independent, and the deny entries can interleave with
487 // other headers.
488 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
489 "Content-Length: 42\r\n"
490 "X-Frame-Options: ALLOWall\r\n"
491 "X-Frame-Options: deny\r\n"));
492 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
493 "X-Frame-Options: ALLOWall\r\n"
494 "Content-Length: 42\r\n"
495 "X-Frame-Options: SAMEORIGIN\r\n"));
496 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
497 "X-Frame-Options: deny\r\n"
498 "X-Frame-Options: ALLOWall\r\n"
499 "Content-Length: 42\r\n"));
500 EXPECT_TRUE(http_utils::HasFrameBustingHeader(
501 "X-Frame-Options: SAMEORIGIN\r\n"
502 "X-Frame-Options: ALLOWall\r\n"));