Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / content / child / site_isolation_stats_gatherer_browsertest.cc
blobef22f384e3cccfe899f93673947cd5e3f9073baa
1 // Copyright 2015 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 "base/command_line.h"
6 #include "base/strings/pattern.h"
7 #include "base/strings/string_util.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/test/histogram_tester.h"
10 #include "content/public/common/content_switches.h"
11 #include "content/public/common/resource_type.h"
12 #include "content/public/test/browser_test_utils.h"
13 #include "content/public/test/content_browser_test.h"
14 #include "content/public/test/content_browser_test_utils.h"
15 #include "content/shell/browser/shell.h"
16 #include "net/test/spawned_test_server/spawned_test_server.h"
17 #include "testing/gmock/include/gmock/gmock.h"
19 namespace content {
21 // These tests simulate exploited renderer processes, which can fetch arbitrary
22 // resources from other websites, not constrained by the Same Origin Policy. We
23 // are trying to verify that the renderer cannot fetch any cross-site document
24 // responses even when the Same Origin Policy is turned off inside the renderer.
25 class SiteIsolationStatsGathererBrowserTest : public ContentBrowserTest {
26 public:
27 SiteIsolationStatsGathererBrowserTest() {}
28 ~SiteIsolationStatsGathererBrowserTest() override {}
30 void SetUpCommandLine(base::CommandLine* command_line) override {
31 ASSERT_TRUE(test_server()->Start());
32 // Add a host resolver rule to map all outgoing requests to the test server.
33 // This allows us to use "real" hostnames in URLs, which we can use to
34 // create arbitrary SiteInstances.
35 command_line->AppendSwitchASCII(
36 switches::kHostResolverRules,
37 "MAP * " + test_server()->host_port_pair().ToString() +
38 ",EXCLUDE localhost");
40 // Since we assume exploited renderer process, it can bypass the same origin
41 // policy at will. Simulate that by passing the disable-web-security flag.
42 command_line->AppendSwitch(switches::kDisableWebSecurity);
45 void InspectHistograms(const base::HistogramTester& histograms,
46 bool should_be_blocked,
47 const std::string& resource_name) {
48 std::string bucket;
49 int mime_type = 0; // Hardcoded because histogram enums mustn't change.
50 if (base::MatchPattern(resource_name, "*.html")) {
51 bucket = "HTML";
52 mime_type = 0;
53 } else if (base::MatchPattern(resource_name, "*.xml")) {
54 bucket = "XML";
55 mime_type = 1;
56 } else if (base::MatchPattern(resource_name, "*.json")) {
57 bucket = "JSON";
58 mime_type = 2;
59 } else if (base::MatchPattern(resource_name, "*.txt")) {
60 bucket = "Plain";
61 mime_type = 3;
62 if (base::MatchPattern(resource_name, "json*")) {
63 bucket += ".JSON";
64 } else if (base::MatchPattern(resource_name, "html*")) {
65 bucket += ".HTML";
66 } else if (base::MatchPattern(resource_name, "xml*")) {
67 bucket += ".XML";
69 } else {
70 FAIL();
72 FetchHistogramsFromChildProcesses();
74 // A few histograms are incremented unconditionally.
75 histograms.ExpectUniqueSample("SiteIsolation.AllResponses", 1, 1);
76 base::HistogramTester::CountsMap expected_metrics;
77 expected_metrics["SiteIsolation.XSD.DataLength"] = 1;
78 expected_metrics["SiteIsolation.XSD.MimeType"] = 1;
80 // Determine the appropriate conditionally-incremented histograms.
81 std::string base = "SiteIsolation.XSD." + bucket;
82 if (should_be_blocked) {
83 expected_metrics[base + ".Blocked"] = 1;
84 expected_metrics[base + ".Blocked.RenderableStatusCode"] = 1;
85 } else {
86 expected_metrics[base + ".NotBlocked"] = 1;
87 if (base::MatchPattern(resource_name, "*js.*")) {
88 expected_metrics[base + ".NotBlocked.MaybeJS"] = 1;
92 // Make sure that the expected metrics, and only those metrics, were
93 // incremented.
94 EXPECT_THAT(histograms.GetTotalCountsForPrefix("SiteIsolation.XSD."),
95 testing::ContainerEq(expected_metrics))
96 << "For resource_name=" << resource_name
97 << ", should_be_blocked=" << should_be_blocked;
99 EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.MimeType"),
100 testing::ElementsAre(base::Bucket(mime_type, 1)))
101 << "The wrong mime type bucket was incremented.";
102 if (should_be_blocked) {
103 static_assert(13 == RESOURCE_TYPE_XHR, "Histogram enums mustn't change.");
104 EXPECT_THAT(
105 histograms.GetAllSamples(base + ".Blocked.RenderableStatusCode"),
106 testing::ElementsAre(base::Bucket(RESOURCE_TYPE_XHR, 1)))
107 << "The wrong RenderableStatusCode bucket was incremented.";
111 private:
112 DISALLOW_COPY_AND_ASSIGN(SiteIsolationStatsGathererBrowserTest);
115 // TODO(dsjang): we cannot run these tests on Android since SetUpCommandLine()
116 // is executed before the I/O thread is created on Android. After this bug
117 // (crbug.com/278425) is resolved, we can enable this test case on Android.
118 #if defined(OS_ANDROID)
119 #define MAYBE_CrossSiteDocumentBlockingForMimeType \
120 DISABLED_CrossSiteDocumentBlockingForMimeType
121 #else
122 #define MAYBE_CrossSiteDocumentBlockingForMimeType \
123 CrossSiteDocumentBlockingForMimeType
124 #endif
126 IN_PROC_BROWSER_TEST_F(SiteIsolationStatsGathererBrowserTest,
127 MAYBE_CrossSiteDocumentBlockingForMimeType) {
128 // Load a page that issues illegal cross-site document requests to bar.com.
129 // The page uses XHR to request HTML/XML/JSON documents from bar.com, and
130 // inspects if any of them were successfully received. Currently, on illegal
131 // access, the XHR requests should succeed, but the UMA histograms should
132 // record that they would have been blocked. This test is only possible since
133 // we run the browser without the same origin policy.
134 GURL foo("http://foo.com/files/cross_site_document_request.html");
136 NavigateToURL(shell(), foo);
138 // Flush out existing histogram activity.
139 FetchHistogramsFromChildProcesses();
141 // The following are files under content/test/data/site_isolation. All
142 // should be disallowed for cross site XHR under the document blocking policy.
143 const char* blocked_resources[] = {
144 "comment_valid.html",
145 "html.txt",
146 "html4_dtd.html",
147 "html4_dtd.txt",
148 "html5_dtd.html",
149 "html5_dtd.txt",
150 "json.txt",
151 "valid.html",
152 "valid.json",
153 "valid.xml",
154 "xml.txt",
157 for (const char* resource : blocked_resources) {
158 SCOPED_TRACE(base::StringPrintf("... while testing page: %s", resource));
159 base::HistogramTester histograms;
161 bool was_blocked;
162 ASSERT_TRUE(ExecuteScriptAndExtractBool(
163 shell()->web_contents(),
164 base::StringPrintf("sendRequest(\"%s\");", resource), &was_blocked));
165 ASSERT_FALSE(was_blocked);
167 InspectHistograms(histograms, true, resource);
170 // These files should be allowed for XHR under the document blocking policy.
171 const char* allowed_resources[] = {"js.html",
172 "comment_js.html",
173 "js.xml",
174 "js.json",
175 "js.txt",
176 "img.html",
177 "img.xml",
178 "img.json",
179 "img.txt",
180 "comment_js.html"};
181 for (const char* resource : allowed_resources) {
182 SCOPED_TRACE(base::StringPrintf("... while testing page: %s", resource));
183 base::HistogramTester histograms;
185 bool was_blocked;
186 ASSERT_TRUE(ExecuteScriptAndExtractBool(
187 shell()->web_contents(),
188 base::StringPrintf("sendRequest(\"%s\");", resource), &was_blocked));
189 ASSERT_FALSE(was_blocked);
191 InspectHistograms(histograms, false, resource);
195 // TODO(dsjang): we cannot run these tests on Android since SetUpCommandLine()
196 // is executed before the I/O thread is created on Android. After this bug
197 // (crbug.com/278425) is resolved, we can enable this test case on Android.
198 #if defined(OS_ANDROID)
199 #define MAYBE_CrossSiteDocumentBlockingForDifferentTargets \
200 DISABLED_CrossSiteDocumentBlockingForDifferentTargets
201 #else
202 #define MAYBE_CrossSiteDocumentBlockingForDifferentTargets \
203 CrossSiteDocumentBlockingForDifferentTargets
204 #endif
206 IN_PROC_BROWSER_TEST_F(SiteIsolationStatsGathererBrowserTest,
207 MAYBE_CrossSiteDocumentBlockingForDifferentTargets) {
208 // This webpage loads a cross-site HTML page in different targets such as
209 // <img>,<link>,<embed>, etc. Since the requested document is blocked, and one
210 // character string (' ') is returned instead, this tests that the renderer
211 // does not crash even when it receives a response body which is " ", whose
212 // length is different from what's described in "content-length" for such
213 // different targets.
215 // TODO(nick): Split up these cases, and add positive assertions here about
216 // what actually happens in these various resource-block cases.
217 GURL foo("http://foo.com/files/cross_site_document_request_target.html");
218 NavigateToURL(shell(), foo);
221 } // namespace content