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

Side by Side Diff: chrome/browser/net/predictor_browsertest.cc

Issue 1857383002: Refactor net predictor to use ResourceThrottles (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase on #396550 Created 4 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
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/browser/profiles/profile_impl_io_data.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 <stddef.h> 5 #include <stddef.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include <algorithm> 8 #include <algorithm>
9 #include <memory> 9 #include <memory>
10 #include <set> 10 #include <set>
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 net::NetworkDelegate* delegate) { 62 net::NetworkDelegate* delegate) {
63 const char kPlainTextHeaders[] = 63 const char kPlainTextHeaders[] =
64 "HTTP/1.1 200 OK\n" 64 "HTTP/1.1 200 OK\n"
65 "Content-Type: text/plain\n" 65 "Content-Type: text/plain\n"
66 "Access-Control-Allow-Origin: *\n" 66 "Access-Control-Allow-Origin: *\n"
67 "\n"; 67 "\n";
68 return new net::URLRequestTestJob(request, delegate, kPlainTextHeaders, "", 68 return new net::URLRequestTestJob(request, delegate, kPlainTextHeaders, "",
69 true); 69 true);
70 } 70 }
71 71
72 net::URLRequestJob* CreateRedirectRequestJob(std::string location,
73 net::URLRequest* request,
74 net::NetworkDelegate* delegate) {
75 char kPlainTextHeaders[] =
76 "HTTP/1.1 302 \n"
77 "Location: %s\n"
78 "Access-Control-Allow-Origin: *\n"
79 "\n";
80 return new net::URLRequestTestJob(
81 request, delegate,
82 base::StringPrintf(kPlainTextHeaders, location.c_str()), "", true);
83 }
84
72 // Override the test server to redirect requests matching some path. This is 85 // Override the test server to redirect requests matching some path. This is
73 // used because the predictor only learns simple redirects with a path of "/" 86 // used because the predictor only learns simple redirects with a path of "/"
74 std::unique_ptr<net::test_server::HttpResponse> RedirectForPathHandler( 87 std::unique_ptr<net::test_server::HttpResponse> RedirectForPathHandler(
75 const std::string& path, 88 const std::string& path,
76 const GURL& redirect_url, 89 const GURL& redirect_url,
77 const net::test_server::HttpRequest& request) { 90 const net::test_server::HttpRequest& request) {
78 if (request.GetURL().path() != path) 91 if (request.GetURL().path() != path)
79 return nullptr; 92 return nullptr;
80 std::unique_ptr<net::test_server::BasicHttpResponse> response( 93 std::unique_ptr<net::test_server::BasicHttpResponse> response(
81 new net::test_server::BasicHttpResponse); 94 new net::test_server::BasicHttpResponse);
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 class CrossSitePredictorObserver 301 class CrossSitePredictorObserver
289 : public chrome_browser_net::PredictorObserver { 302 : public chrome_browser_net::PredictorObserver {
290 public: 303 public:
291 CrossSitePredictorObserver(const GURL& source_host, 304 CrossSitePredictorObserver(const GURL& source_host,
292 const GURL& cross_site_host) 305 const GURL& cross_site_host)
293 : source_host_(source_host), 306 : source_host_(source_host),
294 cross_site_host_(cross_site_host), 307 cross_site_host_(cross_site_host),
295 cross_site_learned_(0), 308 cross_site_learned_(0),
296 cross_site_preconnected_(0), 309 cross_site_preconnected_(0),
297 same_site_preconnected_(0), 310 same_site_preconnected_(0),
298 dns_run_loop_(nullptr) {} 311 dns_run_loop_(nullptr),
312 strict_(true) {}
299 313
300 void OnPreconnectUrl( 314 void OnPreconnectUrl(
301 const GURL& original_url, 315 const GURL& original_url,
302 const GURL& first_party_for_cookies, 316 const GURL& first_party_for_cookies,
303 chrome_browser_net::UrlInfo::ResolutionMotivation motivation, 317 chrome_browser_net::UrlInfo::ResolutionMotivation motivation,
304 int count) override { 318 int count) override {
305 base::AutoLock lock(lock_); 319 base::AutoLock lock(lock_);
306 if (original_url == cross_site_host_) { 320 if (original_url == cross_site_host_) {
307 cross_site_preconnected_ = std::max(cross_site_preconnected_, count); 321 cross_site_preconnected_ = std::max(cross_site_preconnected_, count);
308 } else if (original_url == source_host_) { 322 } else if (original_url == source_host_) {
309 same_site_preconnected_ = std::max(same_site_preconnected_, count); 323 same_site_preconnected_ = std::max(same_site_preconnected_, count);
310 } else { 324 } else if (strict_) {
311 ADD_FAILURE() << "Preconnected " << original_url 325 ADD_FAILURE() << "Preconnected " << original_url
312 << " when should only be preconnecting the source host: " 326 << " when should only be preconnecting the source host: "
313 << source_host_ 327 << source_host_
314 << " or the cross site host: " << cross_site_host_; 328 << " or the cross site host: " << cross_site_host_;
315 } 329 }
316 } 330 }
317 331
318 void OnLearnFromNavigation(const GURL& referring_url, 332 void OnLearnFromNavigation(const GURL& referring_url,
319 const GURL& target_url) override { 333 const GURL& target_url) override {
320 base::AutoLock lock(lock_); 334 base::AutoLock lock(lock_);
321 // There are three possibilities: 335 // There are three possibilities:
322 // source => target 336 // source => target
323 // source => source 337 // source => source
324 // target => target 338 // target => target
325 if (referring_url == source_host_ && target_url == cross_site_host_) { 339 if (referring_url == source_host_ && target_url == cross_site_host_) {
326 cross_site_learned_++; 340 cross_site_learned_++;
327 } else if (referring_url == source_host_ && target_url == source_host_) { 341 } else if (referring_url == source_host_ && target_url == source_host_) {
328 // Same site learned. Branch retained for clarity. 342 // Same site learned. Branch retained for clarity.
329 } else if (!(referring_url == cross_site_host_ && 343 } else if (strict_ &&
344 !(referring_url == cross_site_host_ &&
330 target_url == cross_site_host_)) { 345 target_url == cross_site_host_)) {
331 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url 346 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url
332 << " when should only be learning the source host: " 347 << " when should only be learning the source host: "
333 << source_host_ 348 << source_host_
334 << " or the cross site host: " << cross_site_host_; 349 << " or the cross site host: " << cross_site_host_;
335 } 350 }
336 } 351 }
337 352
338 void OnDnsLookupFinished(const GURL& url, bool found) override { 353 void OnDnsLookupFinished(const GURL& url, bool found) override {
339 base::AutoLock lock(lock_); 354 base::AutoLock lock(lock_);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 EXPECT_TRUE(HasHostBeenLookedUpLocked(url)) << "Expected to have looked up " 432 EXPECT_TRUE(HasHostBeenLookedUpLocked(url)) << "Expected to have looked up "
418 << url.spec(); 433 << url.spec();
419 return ContainsKey(successful_dns_lookups_, url); 434 return ContainsKey(successful_dns_lookups_, url);
420 } 435 }
421 436
422 void set_task_runner( 437 void set_task_runner(
423 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 438 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
424 task_runner_.swap(task_runner); 439 task_runner_.swap(task_runner);
425 } 440 }
426 441
442 // Optionally allows the object to observe preconnects / learning from other
443 // hosts.
444 void SetStrict(bool strict) {
445 base::AutoLock lock(lock_);
446 strict_ = strict;
447 }
448
427 private: 449 private:
428 const GURL source_host_; 450 const GURL source_host_;
429 const GURL cross_site_host_; 451 const GURL cross_site_host_;
430 452
431 GURL waiting_on_dns_; 453 GURL waiting_on_dns_;
432 454
433 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 455 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
434 456
435 // Protects all following members. They are read and updated from different 457 // Protects all following members. They are read and updated from different
436 // threads. 458 // threads.
437 base::Lock lock_; 459 base::Lock lock_;
438 460
439 int cross_site_learned_; 461 int cross_site_learned_;
440 int cross_site_preconnected_; 462 int cross_site_preconnected_;
441 int same_site_preconnected_; 463 int same_site_preconnected_;
442 464
443 std::set<GURL> successful_dns_lookups_; 465 std::set<GURL> successful_dns_lookups_;
444 std::set<GURL> unsuccessful_dns_lookups_; 466 std::set<GURL> unsuccessful_dns_lookups_;
445 base::RunLoop* dns_run_loop_; 467 base::RunLoop* dns_run_loop_;
446 468
469 // This member can be set to optionally allow url learning other than from
470 // source => source, source => target, or target => target. It will also allow
471 // preconnects to other hosts.
472 bool strict_;
473
447 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver); 474 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver);
448 }; 475 };
449 476
450 } // namespace 477 } // namespace
451 478
452 namespace chrome_browser_net { 479 namespace chrome_browser_net {
453 480
454 class PredictorBrowserTest : public InProcessBrowserTest { 481 class PredictorBrowserTest : public InProcessBrowserTest {
455 public: 482 public:
456 PredictorBrowserTest() 483 PredictorBrowserTest()
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 base::Bind(&RedirectForPathHandler, "/", 533 base::Bind(&RedirectForPathHandler, "/",
507 cross_site_test_server()->GetURL("/title1.html"))); 534 cross_site_test_server()->GetURL("/title1.html")));
508 535
509 predictor()->SetPreconnectEnabledForTest(true); 536 predictor()->SetPreconnectEnabledForTest(true);
510 InstallPredictorObserver(embedded_test_server()->base_url(), 537 InstallPredictorObserver(embedded_test_server()->base_url(),
511 cross_site_test_server()->base_url()); 538 cross_site_test_server()->base_url());
512 observer()->set_task_runner(task_runner_); 539 observer()->set_task_runner(task_runner_);
513 StartInterceptingCrossSiteOnUI(); 540 StartInterceptingCrossSiteOnUI();
514 } 541 }
515 542
516 // Intercepts all requests to the specified host and returns a response with 543 static void StartInterceptingHostWithCreateJobCallback(
517 // an empty body. Needed to prevent requests from actually going to the test 544 const GURL& url,
518 // server, to avoid any races related to socket accounting. Note, the 545 const MatchingPortRequestInterceptor::CreateJobCallback& callback) {
519 // interceptor also looks at the port, to differentiate between the
520 // two test servers.
521 static void StartInterceptingHost(const GURL& url) {
522 DCHECK_CURRENTLY_ON(BrowserThread::IO); 546 DCHECK_CURRENTLY_ON(BrowserThread::IO);
523 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( 547 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
524 url.scheme(), url.host(), 548 url.scheme(), url.host(),
525 base::WrapUnique(new MatchingPortRequestInterceptor( 549 base::WrapUnique(new MatchingPortRequestInterceptor(
526 url.EffectiveIntPort(), base::Bind(&CreateEmptyBodyRequestJob)))); 550 url.EffectiveIntPort(), callback)));
527 } 551 }
528 552
529 static void StopInterceptingHost(const GURL& url) { 553 static void StopInterceptingHost(const GURL& url) {
530 DCHECK_CURRENTLY_ON(BrowserThread::IO); 554 DCHECK_CURRENTLY_ON(BrowserThread::IO);
531 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(), 555 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(),
532 url.host()); 556 url.host());
533 } 557 }
534 558
559 // Intercepts all requests to the specified host and returns a response with
560 // an empty body. Needed to prevent requests from actually going to the test
561 // server, to avoid any races related to socket accounting. Note, the
562 // interceptor also looks at the port, to differentiate between the
563 // two test servers.
535 void StartInterceptingCrossSiteOnUI() { 564 void StartInterceptingCrossSiteOnUI() {
536 DCHECK_CURRENTLY_ON(BrowserThread::UI); 565 DCHECK_CURRENTLY_ON(BrowserThread::UI);
537 content::BrowserThread::PostTask( 566 content::BrowserThread::PostTask(
538 content::BrowserThread::IO, FROM_HERE, 567 content::BrowserThread::IO, FROM_HERE,
539 base::Bind(&PredictorBrowserTest::StartInterceptingHost, 568 base::Bind(
540 cross_site_test_server()->base_url())); 569 &PredictorBrowserTest::StartInterceptingHostWithCreateJobCallback,
570 cross_site_test_server()->base_url(),
571 base::Bind(&CreateEmptyBodyRequestJob)));
541 } 572 }
542 573
543 void StopInterceptingCrossSiteOnUI() { 574 void StopInterceptingCrossSiteOnUI() {
544 DCHECK_CURRENTLY_ON(BrowserThread::UI); 575 DCHECK_CURRENTLY_ON(BrowserThread::UI);
545 content::BrowserThread::PostTask( 576 content::BrowserThread::PostTask(
546 content::BrowserThread::IO, FROM_HERE, 577 content::BrowserThread::IO, FROM_HERE,
547 base::Bind(&PredictorBrowserTest::StopInterceptingHost, 578 base::Bind(&PredictorBrowserTest::StopInterceptingHost,
548 cross_site_test_server()->base_url())); 579 cross_site_test_server()->base_url()));
549 } 580 }
550 581
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 // embedded test servers have the same host_piece, an extra preconnect is 940 // embedded test servers have the same host_piece, an extra preconnect is
910 // issued. This results in ceil(2.33) + 1 = 4 preconnects. 941 // issued. This results in ceil(2.33) + 1 = 4 preconnects.
911 ui_test_utils::NavigateToURL(browser(), 942 ui_test_utils::NavigateToURL(browser(),
912 embedded_test_server()->GetURL("/title1.html")); 943 embedded_test_server()->GetURL("/title1.html"));
913 // Just check that predictor has initiated preconnects to the cross site test 944 // Just check that predictor has initiated preconnects to the cross site test
914 // server. It's tricky to reset the connections to the test server, and 945 // server. It's tricky to reset the connections to the test server, and
915 // sockets can be reused. 946 // sockets can be reused.
916 EXPECT_EQ(4, observer()->CrossSitePreconnected()); 947 EXPECT_EQ(4, observer()->CrossSitePreconnected());
917 } 948 }
918 949
950 // 1. Navigate to A.com learning B.com
951 // 2. Navigate to B.com with subresource from C.com redirecting to A.com.
952 // 3. Assert that the redirect does not cause us to preconnect to B.com (via
953 // A.com).
954 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, DontPredictBasedOnSubresources) {
955 GURL redirector_url = GURL("http://redirector.com");
956
957 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
958 EXPECT_EQ(1, observer()->CrossSiteLearned());
959 EXPECT_EQ(0, observer()->CrossSitePreconnected());
960
961 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
962
963 // Stop intercepting so that the test can actually navigate to the cross site
964 // server.
965 StopInterceptingCrossSiteOnUI();
966
967 // All requests with the redirector url as base url should redirect to the
968 // embedded_test_server_.
969 content::BrowserThread::PostTask(
970 content::BrowserThread::IO, FROM_HERE,
971 base::Bind(
972 &PredictorBrowserTest::StartInterceptingHostWithCreateJobCallback,
973 redirector_url,
974 base::Bind(
975 &CreateRedirectRequestJob,
976 embedded_test_server()->GetURL("/predictor/empty.js").spec())));
977
978 // Reduce the strictness, because the below logic causes the predictor to
979 // learn cross_site_test_server_ => redirector, as well as
980 // cross_site_test_server_ => embedded_test_server_ (via referrer header).
981 observer()->SetStrict(false);
982
983 GURL redirect_requesting_url =
984 cross_site_test_server()->GetURL(base::StringPrintf(
985 "/predictor/"
986 "predictor_cross_site.html?subresourceHost=%s&numCORSResources=1",
987 redirector_url.spec().c_str()));
988 ui_test_utils::NavigateToURL(browser(), redirect_requesting_url);
989 bool result = false;
990
991 int navigation_preconnects = observer()->CrossSitePreconnected();
992 EXPECT_EQ(2, navigation_preconnects);
993
994 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
995 browser()->tab_strip_model()->GetActiveWebContents(),
996 "startFetchesAndWaitForReply()", &result));
997 EXPECT_TRUE(result);
998
999 // The number of preconnects should not increase. Note that the predictor
1000 // would preconnect 4 sockets if it were doing so based on learning.
1001 EXPECT_EQ(navigation_preconnects, observer()->CrossSitePreconnected());
1002 }
1003
1004 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PredictBasedOnSubframeRedirect) {
1005 // A test server is needed here because data url navigations with redirect
1006 // interceptors don't interact well with the ResourceTiming API.
1007 // TODO(csharrison): Possibly this is a bug in either net or Blink, and it
1008 // might be worthwhile to investigate.
1009 std::unique_ptr<net::EmbeddedTestServer> redirector =
1010 base::WrapUnique(new net::EmbeddedTestServer());
1011 ASSERT_TRUE(redirector->Start());
1012
1013 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
1014 EXPECT_EQ(1, observer()->CrossSiteLearned());
1015 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
1016
1017 redirector->RegisterRequestHandler(
1018 base::Bind(&RedirectForPathHandler, "/",
1019 embedded_test_server()->GetURL("/title1.html")));
1020
1021 // Note that the observer will see preconnects to the redirector, and the
1022 // predictor will learn redirector->embedded_test_server.
1023 observer()->SetStrict(false);
1024
1025 NavigateToDataURLWithContent(base::StringPrintf(
1026 "<iframe src='%s'></iframe>", redirector->base_url().spec().c_str()));
1027
1028 EXPECT_EQ(4, observer()->CrossSitePreconnected());
1029 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
1030 }
1031
919 // Expect that the predictor correctly predicts subframe navigations. 1032 // Expect that the predictor correctly predicts subframe navigations.
920 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeCrossSitePrediction) { 1033 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeCrossSitePrediction) {
921 ui_test_utils::NavigateToURL( 1034 ui_test_utils::NavigateToURL(
922 browser(), embedded_test_server()->GetURL( 1035 browser(), embedded_test_server()->GetURL(
923 "/predictor/predictor_cross_site_subframe_nav.html")); 1036 "/predictor/predictor_cross_site_subframe_nav.html"));
924 bool result = false; 1037 bool result = false;
925 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( 1038 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
926 browser()->tab_strip_model()->GetActiveWebContents(), 1039 browser()->tab_strip_model()->GetActiveWebContents(),
927 base::StringPrintf( 1040 base::StringPrintf(
928 "navigateSubframe('%s')", 1041 "navigateSubframe('%s')",
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1392 // Second navigation to content with an img. 1505 // Second navigation to content with an img.
1393 std::string img_content = 1506 std::string img_content =
1394 "<img src=\"" + preconnect_url.spec() + "test.gif\">"; 1507 "<img src=\"" + preconnect_url.spec() + "test.gif\">";
1395 NavigateToDataURLWithContent(img_content); 1508 NavigateToDataURLWithContent(img_content);
1396 connection_listener_->WaitUntilFirstConnectionRead(); 1509 connection_listener_->WaitUntilFirstConnectionRead();
1397 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount()); 1510 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount());
1398 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount()); 1511 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount());
1399 } 1512 }
1400 1513
1401 } // namespace chrome_browser_net 1514 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/browser/profiles/profile_impl_io_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698