• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <windows.h>
6 #include <atlsecurity.h>
7 #include <shellapi.h>
8 #include <string>
9 #include <vector>
10 
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"
19 
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"
27 
28 const char kChromeFrameUserAgent[] = "chromeframe";
29 
30 class HtmlUtilUnittest : public testing::Test {
31  protected:
32   // Constructor
HtmlUtilUnittest()33   HtmlUtilUnittest() {}
34 
35   // Returns the test path given a test case.
GetTestPath(const std::string & test_case,base::FilePath * path)36   virtual bool GetTestPath(const std::string& test_case, base::FilePath* path) {
37     if (!path) {
38       NOTREACHED();
39       return false;
40     }
41 
42     base::FilePath test_path;
43     if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_path)) {
44       NOTREACHED();
45       return false;
46     }
47 
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);
52 
53     *path = test_path;
54     return true;
55   }
56 
GetTestData(const std::string & test_case,std::wstring * data)57   virtual bool GetTestData(const std::string& test_case, std::wstring* data) {
58     if (!data) {
59       NOTREACHED();
60       return false;
61     }
62 
63     base::FilePath path;
64     if (!GetTestPath(test_case, &path)) {
65       NOTREACHED();
66       return false;
67     }
68 
69     std::string raw_data;
70     base::ReadFileToString(path, &raw_data);
71 
72     // Convert to wide using the "best effort" assurance described in
73     // string_util.h
74     data->assign(UTF8ToWide(raw_data));
75     return true;
76   }
77 };
78 
TEST_F(HtmlUtilUnittest,BasicTest)79 TEST_F(HtmlUtilUnittest, BasicTest) {
80   std::wstring test_data;
81   GetTestData("basic_test.html", &test_data);
82 
83   HTMLScanner scanner(test_data.c_str());
84 
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());
89 
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"));
94 
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"));
98 }
99 
TEST_F(HtmlUtilUnittest,QuotesTest)100 TEST_F(HtmlUtilUnittest, QuotesTest) {
101   std::wstring test_data;
102   GetTestData("quotes_test.html", &test_data);
103 
104   HTMLScanner scanner(test_data.c_str());
105 
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());
110 
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"));
115 
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"));
119 }
120 
TEST_F(HtmlUtilUnittest,DegenerateCasesTest)121 TEST_F(HtmlUtilUnittest, DegenerateCasesTest) {
122   std::wstring test_data;
123   GetTestData("degenerate_cases_test.html", &test_data);
124 
125   HTMLScanner scanner(test_data.c_str());
126 
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());
132 }
133 
TEST_F(HtmlUtilUnittest,MultipleTagsTest)134 TEST_F(HtmlUtilUnittest, MultipleTagsTest) {
135   std::wstring test_data;
136   GetTestData("multiple_tags.html", &test_data);
137 
138   HTMLScanner scanner(test_data.c_str());
139 
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());
144 
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++;
157     }
158   }
159   EXPECT_EQ(3, valid_tag_count);
160 }
161 
TEST_F(HtmlUtilUnittest,ShortDegenerateTest1)162 TEST_F(HtmlUtilUnittest, ShortDegenerateTest1) {
163   std::wstring test_data(
164       L"<foo><META http-equiv=X-UA-Compatible content='chrome=1'");
165 
166   HTMLScanner scanner(test_data.c_str());
167 
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());
173 }
174 
TEST_F(HtmlUtilUnittest,ShortDegenerateTest2)175 TEST_F(HtmlUtilUnittest, ShortDegenerateTest2) {
176   std::wstring test_data(
177     L"<foo <META http-equiv=X-UA-Compatible content='chrome=1'/>");
178 
179   HTMLScanner scanner(test_data.c_str());
180 
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());
186 }
187 
TEST_F(HtmlUtilUnittest,QuoteInsideHTMLCommentTest)188 TEST_F(HtmlUtilUnittest, QuoteInsideHTMLCommentTest) {
189   std::wstring test_data(
190     L"<!-- comment' --><META http-equiv=X-UA-Compatible content='chrome=1'/>");
191 
192   HTMLScanner scanner(test_data.c_str());
193 
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());
198 
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"));
203 
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"));
207 }
208 
TEST_F(HtmlUtilUnittest,CloseTagInsideHTMLCommentTest)209 TEST_F(HtmlUtilUnittest, CloseTagInsideHTMLCommentTest) {
210   std::wstring test_data(
211     L"<!-- comment> <META http-equiv=X-UA-Compatible content='chrome=1'/>-->");
212 
213   HTMLScanner scanner(test_data.c_str());
214 
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());
219 }
220 
TEST_F(HtmlUtilUnittest,IEConditionalCommentTest)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]-->");
225 
226   HTMLScanner scanner(test_data.c_str());
227 
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());
232 }
233 
TEST_F(HtmlUtilUnittest,IEConditionalCommentWithNestedCommentTest)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]-->");
238 
239   HTMLScanner scanner(test_data.c_str());
240 
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());
245 }
246 
TEST_F(HtmlUtilUnittest,IEConditionalCommentWithMultipleNestedTagsTest)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>");
252 
253   HTMLScanner scanner(test_data.c_str());
254 
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());
259 
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());
264 
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());
269 }
270 
TEST_F(HtmlUtilUnittest,IEConditionalCommentWithAlternateEndingTest)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>");
276 
277   HTMLScanner scanner(test_data.c_str());
278 
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());
283 
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());
288 
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());
293 }
294 
TEST_F(HtmlUtilUnittest,IEConditionalCommentNonTerminatedTest)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>");
302 
303   HTMLScanner scanner(test_data.c_str());
304 
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());
309 
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());
314 
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());
319 }
320 
321 struct UserAgentTestCase {
322   std::string input_;
323   std::string expected_;
324 } user_agent_test_cases[] = {
325   {
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)",
378   }
379 };
380 
TEST_F(HtmlUtilUnittest,AddChromeFrameToUserAgentValue)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);
387   }
388 
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);
395   }
396 }
397 
TEST_F(HtmlUtilUnittest,RemoveChromeFrameFromUserAgentValue)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);
404   }
405 
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);
411   }
412 }
413 
TEST_F(HtmlUtilUnittest,GetDefaultUserAgentHeaderWithCFTag)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));
419 }
420 
TEST_F(HtmlUtilUnittest,GetChromeUserAgent)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));
428 
429   const char* ua = http_utils::GetChromeUserAgent();
430   EXPECT_EQ(ua, chrome_ua);
431 }
432 
TEST_F(HtmlUtilUnittest,GetDefaultUserAgent)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"));
437 }
438 
TEST_F(HtmlUtilUnittest,GetChromeFrameUserAgent)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);
446 }
447 
TEST(HttpUtils,HasFrameBustingHeader)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"));
473 
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"));
478 
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"));
484 
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"));
503 }
504