Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: content/browser/browsing_data/clear_site_data_throttle_unittest.cc

Issue 2368923003: Support the Clear-Site-Data header on resource requests (Closed)
Patch Set: Addressed comments, formatted. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/browsing_data/clear_site_data_throttle.h" 5 #include "content/browser/browsing_data/clear_site_data_throttle.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/command_line.h" 9 #include "base/memory/ptr_util.h"
10 #include "content/public/common/content_switches.h" 10 #include "base/memory/ref_counted.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/test/scoped_command_line.h"
14 #include "base/test/scoped_task_environment.h"
15 #include "content/public/browser/resource_request_info.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "net/base/load_flags.h"
19 #include "net/http/http_util.h"
20 #include "net/url_request/redirect_info.h"
21 #include "net/url_request/url_request_job.h"
22 #include "net/url_request/url_request_test_util.h"
11 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
13 25
26 using ::testing::_;
27
14 namespace content { 28 namespace content {
15 29
30 using ConsoleMessagesDelegate = ClearSiteDataThrottle::ConsoleMessagesDelegate;
31
32 namespace {
33
34 const char kClearSiteDataHeaderPrefix[] = "Clear-Site-Data: ";
35
36 const char kClearCookiesHeader[] =
37 "Clear-Site-Data: { \"types\": [ \"cookies\" ] }";
38
39 void WaitForUIThread() {
40 base::RunLoop run_loop;
41 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, run_loop.QuitClosure());
42 run_loop.Run();
43 }
44
45 // Used to verify that resource throttle delegate calls are made.
46 class MockResourceThrottleDelegate : public ResourceThrottle::Delegate {
47 public:
48 MOCK_METHOD0(Cancel, void());
49 MOCK_METHOD0(CancelAndIgnore, void());
50 MOCK_METHOD1(CancelWithError, void(int));
51 MOCK_METHOD0(Resume, void());
52 };
53
54 // A slightly modified ClearSiteDataThrottle for testing with unconditional
55 // construction, injectable response headers, and dummy clearing functionality.
56 class TestThrottle : public ClearSiteDataThrottle {
57 public:
58 TestThrottle(net::URLRequest* request,
59 std::unique_ptr<ConsoleMessagesDelegate> delegate)
60 : ClearSiteDataThrottle(request, std::move(delegate)) {}
61 ~TestThrottle() override {}
62
63 void SetResponseHeaders(const std::string& headers) {
64 std::string headers_with_status_code = "HTTP/1.1 200\n" + headers;
65 headers_ = new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
66 headers_with_status_code.c_str(), headers_with_status_code.size()));
67 }
68
69 MOCK_METHOD4(ClearSiteData,
70 void(const url::Origin& origin,
71 bool clear_cookies,
72 bool clear_storage,
73 bool clear_cache));
74
75 protected:
76 const net::HttpResponseHeaders* GetResponseHeaders() const override {
77 return headers_.get();
78 }
79
80 void ExecuteClearingTask(const url::Origin& origin,
81 bool clear_cookies,
82 bool clear_storage,
83 bool clear_cache,
84 base::OnceClosure callback) override {
85 ClearSiteData(origin, clear_cookies, clear_storage, clear_cache);
86
87 // NOTE: ResourceThrottle expects Resume() to be called asynchronously.
88 // For the purposes of this test, synchronous call works correctly, and
89 // is preferable for simplicity, so that we don't have to synchronize
90 // between triggering Clear-Site-Data and verifying test expectations.
91 std::move(callback).Run();
92 }
93
94 private:
95 scoped_refptr<net::HttpResponseHeaders> headers_;
96 };
97
98 // A TestThrottle with modifiable current url.
99 class RedirectableTestThrottle : public TestThrottle {
100 public:
101 RedirectableTestThrottle(net::URLRequest* request,
102 std::unique_ptr<ConsoleMessagesDelegate> delegate)
103 : TestThrottle(request, std::move(delegate)) {}
104
105 const GURL& GetCurrentURL() const override {
106 return current_url_.is_valid() ? current_url_
107 : TestThrottle::GetCurrentURL();
108 }
109
110 void SetCurrentURLForTesting(const GURL& url) { current_url_ = url; }
111
112 private:
113 GURL current_url_;
114 };
115
116 // A ConsoleDelegate that outputs messages to a string |output_buffer| owned
117 // by the caller instead of to the console (losing the level information).
118 class StringConsoleMessagesDelegate : public ConsoleMessagesDelegate {
119 public:
120 StringConsoleMessagesDelegate(std::string* output_buffer) {
121 SetOutputFormattedMessageFunctionForTesting(
122 base::Bind(&StringConsoleMessagesDelegate::OutputFormattedMessage,
123 base::Unretained(output_buffer)));
124 }
125
126 ~StringConsoleMessagesDelegate() override {}
127
128 private:
129 static void OutputFormattedMessage(std::string* output_buffer,
130 WebContents* web_contents,
131 ConsoleMessageLevel level,
132 const std::string& formatted_text) {
133 *output_buffer += formatted_text + "\n";
134 }
135 };
136
137 } // namespace
138
16 class ClearSiteDataThrottleTest : public testing::Test { 139 class ClearSiteDataThrottleTest : public testing::Test {
17 public: 140 public:
18 void SetUp() override { 141 ClearSiteDataThrottleTest()
19 base::CommandLine::ForCurrentProcess()->AppendSwitch( 142 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
20 switches::kEnableExperimentalWebPlatformFeatures);
21 throttle_ = ClearSiteDataThrottle::CreateThrottleForNavigation(nullptr);
22 }
23
24 ClearSiteDataThrottle* GetThrottle() {
25 return static_cast<ClearSiteDataThrottle*>(throttle_.get());
26 }
27 143
28 private: 144 private:
29 std::unique_ptr<NavigationThrottle> throttle_; 145 TestBrowserThreadBundle thread_bundle_;
146
147 DISALLOW_COPY_AND_ASSIGN(ClearSiteDataThrottleTest);
30 }; 148 };
31 149
32 TEST_F(ClearSiteDataThrottleTest, ParseHeader) { 150 TEST_F(ClearSiteDataThrottleTest, MaybeCreateThrottleForRequest) {
151 // Create a URL request.
152 GURL url("https://www.example.com");
153 net::TestURLRequestContext context;
154 std::unique_ptr<net::URLRequest> request(
155 context.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr));
156
157 // We will not create the throttle for an empty ResourceRequestInfo.
158 EXPECT_FALSE(
159 ClearSiteDataThrottle::MaybeCreateThrottleForRequest(request.get()));
160
161 // We can create the throttle for a valid ResourceRequestInfo.
162 ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_IMAGE,
163 nullptr, 0, 0, 0, false, true, true,
164 true, false);
165 EXPECT_TRUE(
166 ClearSiteDataThrottle::MaybeCreateThrottleForRequest(request.get()));
167 }
168
169 TEST_F(ClearSiteDataThrottleTest, ParseHeaderAndExecuteClearingTask) {
33 struct TestCase { 170 struct TestCase {
34 const char* header; 171 const char* header;
35 bool cookies; 172 bool cookies;
36 bool storage; 173 bool storage;
37 bool cache; 174 bool cache;
38 } test_cases[] = { 175 } test_cases[] = {
39 // One data type. 176 // One data type.
40 {"{ \"types\": [\"cookies\"] }", true, false, false}, 177 {"{ \"types\": [\"cookies\"] }", true, false, false},
41 {"{ \"types\": [\"storage\"] }", false, true, false}, 178 {"{ \"types\": [\"storage\"] }", false, true, false},
42 {"{ \"types\": [\"cache\"] }", false, false, true}, 179 {"{ \"types\": [\"cache\"] }", false, false, true},
(...skipping 22 matching lines...) Expand all
65 false}, 202 false},
66 203
67 // Unknown types are ignored, but we still proceed with the deletion for 204 // Unknown types are ignored, but we still proceed with the deletion for
68 // those that we recognize. 205 // those that we recognize.
69 {"{ \"types\": [\"cache\", \"foo\"] }", false, false, true}, 206 {"{ \"types\": [\"cache\", \"foo\"] }", false, false, true},
70 }; 207 };
71 208
72 for (const TestCase& test_case : test_cases) { 209 for (const TestCase& test_case : test_cases) {
73 SCOPED_TRACE(test_case.header); 210 SCOPED_TRACE(test_case.header);
74 211
212 // Test that ParseHeader works correctly.
75 bool actual_cookies; 213 bool actual_cookies;
76 bool actual_storage; 214 bool actual_storage;
77 bool actual_cache; 215 bool actual_cache;
78 216
79 std::vector<ClearSiteDataThrottle::ConsoleMessage> messages; 217 GURL url("https://example.com");
218 ConsoleMessagesDelegate console_delegate;
80 219
81 EXPECT_TRUE(GetThrottle()->ParseHeader(test_case.header, &actual_cookies, 220 EXPECT_TRUE(ClearSiteDataThrottle::ParseHeaderForTesting(
82 &actual_storage, &actual_cache, 221 test_case.header, &actual_cookies, &actual_storage, &actual_cache,
83 &messages)); 222 &console_delegate, url));
84 223
85 EXPECT_EQ(test_case.cookies, actual_cookies); 224 EXPECT_EQ(test_case.cookies, actual_cookies);
86 EXPECT_EQ(test_case.storage, actual_storage); 225 EXPECT_EQ(test_case.storage, actual_storage);
87 EXPECT_EQ(test_case.cache, actual_cache); 226 EXPECT_EQ(test_case.cache, actual_cache);
227
228 // Test that a call with the above parameters actually reaches
229 // ExecuteClearingTask().
230 net::TestURLRequestContext context;
231 std::unique_ptr<net::URLRequest> request(
232 context.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr));
233 TestThrottle throttle(request.get(),
234 base::MakeUnique<ConsoleMessagesDelegate>());
235 MockResourceThrottleDelegate delegate;
236 throttle.set_delegate_for_testing(&delegate);
237 throttle.SetResponseHeaders(std::string(kClearSiteDataHeaderPrefix) +
238 test_case.header);
239
240 EXPECT_CALL(throttle, ClearSiteData(url::Origin(url), test_case.cookies,
241 test_case.storage, test_case.cache));
242 bool defer;
243 throttle.WillProcessResponse(&defer);
244 EXPECT_TRUE(defer);
245
246 testing::Mock::VerifyAndClearExpectations(&throttle);
88 } 247 }
89 } 248 }
90 249
91 TEST_F(ClearSiteDataThrottleTest, InvalidHeader) { 250 TEST_F(ClearSiteDataThrottleTest, InvalidHeader) {
92 struct TestCase { 251 struct TestCase {
93 const char* header; 252 const char* header;
94 const char* console_message; 253 const char* console_message;
95 } test_cases[] = { 254 } test_cases[] = {
96 {"", "Not a valid JSON.\n"}, 255 {"", "Expected valid JSON.\n"},
97 {"\"unclosed quote", "Not a valid JSON.\n"}, 256 {"\"unclosed quote", "Expected valid JSON.\n"},
98 {"\"some text\"", "Expecting a JSON dictionary with a 'types' field.\n"}, 257 {"\"some text\"", "Expected a JSON dictionary with a 'types' field.\n"},
99 {"{ \"field\" : {} }", 258 {"{ \"field\" : {} }",
100 "Expecting a JSON dictionary with a 'types' field.\n"}, 259 "Expected a JSON dictionary with a 'types' field.\n"},
101 {"{ \"types\" : [ \"passwords\" ] }", 260 {"{ \"types\" : [ \"passwords\" ] }",
102 "Invalid type: \"passwords\".\n" 261 "Unrecognized type: \"passwords\".\n"
103 "No valid types specified in the 'types' field.\n"}, 262 "No recognized types specified in the 'types' field.\n"},
104 {"{ \"types\" : [ [ \"list in a list\" ] ] }", 263 {"{ \"types\" : [ [ \"list in a list\" ] ] }",
105 "Invalid type: [\"list in a list\"].\n" 264 "Unrecognized type: [\"list in a list\"].\n"
106 "No valid types specified in the 'types' field.\n"}, 265 "No recognized types specified in the 'types' field.\n"},
107 {"{ \"types\" : [ \"кукис\", \"сторидж\", \"кэш\" ]", 266 {"{ \"types\" : [ \"кукис\", \"сторидж\", \"кэш\" ]",
108 "Must only contain ASCII characters.\n"}}; 267 "Must only contain ASCII characters.\n"}};
109 268
110 for (const TestCase& test_case : test_cases) { 269 for (const TestCase& test_case : test_cases) {
111 SCOPED_TRACE(test_case.header); 270 SCOPED_TRACE(test_case.header);
112 271
113 bool actual_cookies; 272 bool actual_cookies;
114 bool actual_storage; 273 bool actual_storage;
115 bool actual_cache; 274 bool actual_cache;
116 275
117 std::vector<ClearSiteDataThrottle::ConsoleMessage> messages; 276 ConsoleMessagesDelegate console_delegate;
118 277
119 EXPECT_FALSE(GetThrottle()->ParseHeader(test_case.header, &actual_cookies, 278 EXPECT_FALSE(ClearSiteDataThrottle::ParseHeaderForTesting(
120 &actual_storage, &actual_cache, 279 test_case.header, &actual_cookies, &actual_storage, &actual_cache,
121 &messages)); 280 &console_delegate, GURL()));
122 281
123 std::string multiline_message; 282 std::string multiline_message;
124 for (const auto& message : messages) { 283 for (const auto& message : console_delegate.messages()) {
125 EXPECT_EQ(CONSOLE_MESSAGE_LEVEL_ERROR, message.level); 284 EXPECT_EQ(CONSOLE_MESSAGE_LEVEL_ERROR, message.level);
126 multiline_message += message.text + "\n"; 285 multiline_message += message.text + "\n";
127 } 286 }
128 287
129 EXPECT_EQ(test_case.console_message, multiline_message); 288 EXPECT_EQ(test_case.console_message, multiline_message);
130 } 289 }
131 } 290 }
132 291
292 TEST_F(ClearSiteDataThrottleTest, LoadDoNotSaveCookies) {
293 net::TestURLRequestContext context;
294 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
295 GURL("https://www.example.com"), net::DEFAULT_PRIORITY, nullptr));
296 std::unique_ptr<ConsoleMessagesDelegate> scoped_console_delegate(
297 new ConsoleMessagesDelegate());
298 const ConsoleMessagesDelegate* console_delegate =
299 scoped_console_delegate.get();
300 TestThrottle throttle(request.get(), std::move(scoped_console_delegate));
301 MockResourceThrottleDelegate delegate;
302 throttle.set_delegate_for_testing(&delegate);
303 throttle.SetResponseHeaders(kClearCookiesHeader);
304
305 EXPECT_CALL(throttle, ClearSiteData(_, _, _, _));
306 bool defer;
307 throttle.WillProcessResponse(&defer);
308 EXPECT_TRUE(defer);
309 EXPECT_EQ(1u, console_delegate->messages().size());
310 EXPECT_EQ("Cleared data types: cookies.",
311 console_delegate->messages().front().text);
312 EXPECT_EQ(console_delegate->messages().front().level,
313 CONSOLE_MESSAGE_LEVEL_INFO);
314 testing::Mock::VerifyAndClearExpectations(&throttle);
315
316 request->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
317 EXPECT_CALL(throttle, ClearSiteData(_, _, _, _)).Times(0);
318 throttle.WillProcessResponse(&defer);
319 EXPECT_FALSE(defer);
320 EXPECT_EQ(2u, console_delegate->messages().size());
321 EXPECT_EQ(
322 "The request's credentials mode prohibits modifying cookies "
323 "and other local data.",
324 console_delegate->messages().rbegin()->text);
325 EXPECT_EQ(CONSOLE_MESSAGE_LEVEL_ERROR,
326 console_delegate->messages().rbegin()->level);
327 testing::Mock::VerifyAndClearExpectations(&throttle);
328 }
329
330 TEST_F(ClearSiteDataThrottleTest, InvalidOrigin) {
331 struct TestCase {
332 const char* origin;
333 bool expect_success;
334 std::string error_message; // Tested only if |expect_success| = false.
335 } kTestCases[] = {
336 // The throttle only works on secure origins.
337 {"https://secure-origin.com", true, ""},
338 {"filesystem:https://secure-origin.com/temporary/", true, ""},
339
340 // That includes localhost.
341 {"http://localhost", true, ""},
342
343 // Not on insecure origins.
344 {"http://insecure-origin.com", false,
345 "Not supported for insecure origins."},
346 {"filesystem:http://insecure-origin.com/temporary/", false,
347 "Not supported for insecure origins."},
348
349 // Not on unique origins.
350 {"data:unique-origin;", false, "Not supported for unique origins."},
351 };
352
353 net::TestURLRequestContext context;
354
355 for (const TestCase& test_case : kTestCases) {
356 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
357 GURL(test_case.origin), net::DEFAULT_PRIORITY, nullptr));
358 std::unique_ptr<ConsoleMessagesDelegate> scoped_console_delegate(
359 new ConsoleMessagesDelegate());
360 const ConsoleMessagesDelegate* console_delegate =
361 scoped_console_delegate.get();
362 TestThrottle throttle(request.get(), std::move(scoped_console_delegate));
363 MockResourceThrottleDelegate delegate;
364 throttle.set_delegate_for_testing(&delegate);
365 throttle.SetResponseHeaders(kClearCookiesHeader);
366
367 EXPECT_CALL(throttle, ClearSiteData(_, _, _, _))
368 .Times(test_case.expect_success ? 1 : 0);
369
370 bool defer;
371 throttle.WillProcessResponse(&defer);
372
373 EXPECT_EQ(defer, test_case.expect_success);
374 EXPECT_EQ(console_delegate->messages().size(), 1u);
375 EXPECT_EQ(test_case.expect_success ? CONSOLE_MESSAGE_LEVEL_INFO
376 : CONSOLE_MESSAGE_LEVEL_ERROR,
377 console_delegate->messages().front().level);
378 if (!test_case.expect_success) {
379 EXPECT_EQ(test_case.error_message,
380 console_delegate->messages().front().text);
381 }
382 testing::Mock::VerifyAndClearExpectations(&throttle);
383 }
384 }
385
386 TEST_F(ClearSiteDataThrottleTest, DeferAndResume) {
387 enum Stage { START, REDIRECT, RESPONSE };
388
389 struct TestCase {
390 Stage stage;
391 std::string response_headers;
392 bool should_defer;
393 } kTestCases[] = {
394 // The throttle never interferes while the request is starting. Response
395 // headers are ignored, because URLRequest is not supposed to have any
396 // at this stage in the first place.
397 {START, "", false},
398 {START, kClearCookiesHeader, false},
399
400 // The throttle does not defer redirects if there are no interesting
401 // response headers.
402 {REDIRECT, "", false},
403 {REDIRECT, "Set-Cookie: abc=123;", false},
404 {REDIRECT, "Content-Type: image/png;", false},
405
406 // That includes malformed Clear-Site-Data headers or header values
407 // that do not lead to deletion.
408 {REDIRECT, "Clear-Site-Data: { types: cookies } ", false},
409 {REDIRECT, "Clear-Site-Data: { \"types\": [ \"unknown type\" ] }", false},
410
411 // However, redirects are deferred for valid Clear-Site-Data headers.
412 {REDIRECT,
413 "Clear-Site-Data: { \"types\": [ \"cookies\", \"unknown type\" ] }",
414 true},
415 {REDIRECT,
416 base::StringPrintf("Content-Type: image/png;\n%s", kClearCookiesHeader),
417 true},
418 {REDIRECT,
419 base::StringPrintf("%s\nContent-Type: image/png;", kClearCookiesHeader),
420 true},
421
422 // We expect at most one instance of the header. Multiple instances
423 // will not be parsed currently. This is not an inherent property of
424 // Clear-Site-Data, just a documentation of the current behavior.
425 {REDIRECT,
426 base::StringPrintf("%s\n%s", kClearCookiesHeader, kClearCookiesHeader),
427 false},
428
429 // Final response headers are treated the same way as in the case
430 // of redirect.
431 {REDIRECT, "Set-Cookie: abc=123;", false},
432 {REDIRECT, "Clear-Site-Data: { types: cookies } ", false},
433 {REDIRECT, kClearCookiesHeader, true},
434 };
435
436 struct TestOrigin {
437 const char* origin;
438 bool valid;
439 } kTestOrigins[] = {
440 // The throttle only works on secure origins.
441 {"https://secure-origin.com", true},
442 {"filesystem:https://secure-origin.com/temporary/", true},
443
444 // That includes localhost.
445 {"http://localhost", true},
446
447 // Not on insecure origins.
448 {"http://insecure-origin.com", false},
449 {"filesystem:http://insecure-origin.com/temporary/", false},
450
451 // Not on unique origins.
452 {"data:unique-origin;", false},
453 };
454
455 net::TestURLRequestContext context;
456
457 for (const TestOrigin& test_origin : kTestOrigins) {
458 for (const TestCase& test_case : kTestCases) {
459 SCOPED_TRACE(base::StringPrintf("Origin=%s\nStage=%d\nHeaders:\n%s",
460 test_origin.origin, test_case.stage,
461 test_case.response_headers.c_str()));
462
463 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
464 GURL(test_origin.origin), net::DEFAULT_PRIORITY, nullptr));
465 TestThrottle throttle(request.get(),
466 base::MakeUnique<ConsoleMessagesDelegate>());
467 throttle.SetResponseHeaders(test_case.response_headers);
468
469 MockResourceThrottleDelegate delegate;
470 throttle.set_delegate_for_testing(&delegate);
471
472 // Whether we should defer is always conditional on the origin
473 // being valid.
474 bool expected_defer = test_case.should_defer && test_origin.valid;
475
476 // If we expect loading to be deferred, then we also expect data to be
477 // cleared and the load to eventually resume.
478 if (expected_defer) {
479 testing::Expectation expectation = EXPECT_CALL(
480 throttle,
481 ClearSiteData(url::Origin(GURL(test_origin.origin)), _, _, _));
482 EXPECT_CALL(delegate, Resume()).After(expectation);
483 } else {
484 EXPECT_CALL(throttle, ClearSiteData(_, _, _, _)).Times(0);
485 EXPECT_CALL(delegate, Resume()).Times(0);
486 }
487
488 bool actual_defer = false;
489
490 switch (test_case.stage) {
491 case START: {
492 throttle.WillStartRequest(&actual_defer);
493 break;
494 }
495 case REDIRECT: {
496 net::RedirectInfo redirect_info;
497 throttle.WillRedirectRequest(redirect_info, &actual_defer);
498 break;
499 }
500 case RESPONSE: {
501 throttle.WillProcessResponse(&actual_defer);
502 break;
503 }
504 }
505
506 EXPECT_EQ(expected_defer, actual_defer);
507 testing::Mock::VerifyAndClearExpectations(&delegate);
508 }
509 }
510 }
511
512 // Verifies that console outputs from various actions on different URLs
513 // are correctly pretty-printed to the console.
514 TEST_F(ClearSiteDataThrottleTest, FormattedConsoleOutput) {
515 struct TestCase {
516 const char* header;
517 const char* url;
518 const char* output;
519 } kTestCases[] = {
520 // Successful deletion outputs one line.
521 {"{ \"types\": [ \"cookies\" ] }", "https://origin1.com/foo",
522 "Clear-Site-Data header on 'https://origin1.com/foo': "
523 "Cleared data types: cookies.\n"},
524
525 // Another successful deletion.
526 {"{ \"types\": [ \"storage\" ] }", "https://origin2.com/foo",
527 "Clear-Site-Data header on 'https://origin2.com/foo': "
528 "Cleared data types: storage.\n"},
529
530 // Redirect to the same URL. Unsuccessful deletion outputs two lines.
531 {"{ \"foo\": \"bar\" }", "https://origin2.com/foo",
532 "Clear-Site-Data header on 'https://origin2.com/foo': "
533 "Expected a JSON dictionary with a 'types' field.\n"},
534
535 // Redirect to another URL. Another unsuccessful deletion.
536 {"\"some text\"", "https://origin3.com/bar",
537 "Clear-Site-Data header on 'https://origin3.com/bar': "
538 "Expected a JSON dictionary with a 'types' field.\n"},
539
540 // Yet another on the same URL.
541 {"{ \"types\" : [ \"passwords\" ] }", "https://origin3.com/bar",
542 "Clear-Site-Data header on 'https://origin3.com/bar': "
543 "Unrecognized type: \"passwords\".\n"
544 "Clear-Site-Data header on 'https://origin3.com/bar': "
545 "No recognized types specified in the 'types' field.\n"},
546
547 // Successful deletion on the same URL.
548 {"{ \"types\": [ \"cache\" ] }", "https://origin3.com/bar",
549 "Clear-Site-Data header on 'https://origin3.com/bar': "
550 "Cleared data types: cache.\n"},
551
552 // Redirect to the original URL.
553 // Successful deletion outputs one line.
554 {"", "https://origin1.com/foo",
555 "Clear-Site-Data header on 'https://origin1.com/foo': "
556 "Expected valid JSON.\n"}};
557
558 bool kThrottleTypeIsNavigation[] = {true, false};
559
560 for (bool navigation : kThrottleTypeIsNavigation) {
561 SCOPED_TRACE(navigation ? "Navigation test." : "Subresource test.");
562
563 net::TestURLRequestContext context;
564 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
565 GURL(kTestCases[0].url), net::DEFAULT_PRIORITY, nullptr));
566 ResourceRequestInfo::AllocateForTesting(
567 request.get(),
568 navigation ? RESOURCE_TYPE_SUB_FRAME : RESOURCE_TYPE_IMAGE, nullptr, 0,
569 0, 0, false, true, true, true, false);
570
571 std::string output_buffer;
572 std::unique_ptr<RedirectableTestThrottle> throttle =
573 base::MakeUnique<RedirectableTestThrottle>(
574 request.get(),
575 base::MakeUnique<StringConsoleMessagesDelegate>(&output_buffer));
576
577 MockResourceThrottleDelegate delegate;
578 throttle->set_delegate_for_testing(&delegate);
579
580 std::string last_seen_console_output;
581
582 // Simulate redirecting the throttle through the above origins with the
583 // corresponding response headers.
584 bool defer;
585 throttle->WillStartRequest(&defer);
586
587 for (size_t i = 0; i < arraysize(kTestCases); i++) {
588 throttle->SetResponseHeaders(std::string(kClearSiteDataHeaderPrefix) +
589 kTestCases[i].header);
590
591 // TODO(msramek): There is probably a better way to do this inside
592 // URLRequest.
593 throttle->SetCurrentURLForTesting(GURL(kTestCases[i].url));
594
595 net::RedirectInfo redirect_info;
596 if (i < arraysize(kTestCases) - 1)
597 throttle->WillRedirectRequest(redirect_info, &defer);
598 else
599 throttle->WillProcessResponse(&defer);
600
601 // Wait for any messages to be output.
602 WaitForUIThread();
603
604 // For navigations, the console should be still empty. For subresource
605 // requests, messages should be added progressively.
606 if (navigation) {
607 EXPECT_TRUE(output_buffer.empty());
608 } else {
609 EXPECT_EQ(last_seen_console_output + kTestCases[i].output,
610 output_buffer);
611 }
612
613 last_seen_console_output = output_buffer;
614 }
615
616 throttle.reset();
617 WaitForUIThread();
618
619 // At the end, the console must contain all messages regardless of whether
620 // it was a navigation or a subresource request.
621 std::string expected_output;
622 for (struct TestCase& test_case : kTestCases)
623 expected_output += test_case.output;
624 EXPECT_EQ(expected_output, output_buffer);
625 }
626 }
627
133 } // namespace content 628 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698