Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 | 11 |
| 11 #include "base/base64.h" | 12 #include "base/base64.h" |
| 12 #include "base/bind.h" | 13 #include "base/bind.h" |
| 13 #include "base/callback.h" | 14 #include "base/callback.h" |
| 14 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 15 #include "base/json/json_string_value_serializer.h" | 16 #include "base/json/json_string_value_serializer.h" |
| 16 #include "base/macros.h" | 17 #include "base/macros.h" |
| 17 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
| 18 #include "base/memory/ref_counted.h" | 19 #include "base/memory/ref_counted.h" |
| 19 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 if (request.GetURL().path() != path) | 77 if (request.GetURL().path() != path) |
| 77 return nullptr; | 78 return nullptr; |
| 78 std::unique_ptr<net::test_server::BasicHttpResponse> response( | 79 std::unique_ptr<net::test_server::BasicHttpResponse> response( |
| 79 new net::test_server::BasicHttpResponse); | 80 new net::test_server::BasicHttpResponse); |
| 80 response->set_code(net::HTTP_MOVED_PERMANENTLY); | 81 response->set_code(net::HTTP_MOVED_PERMANENTLY); |
| 81 response->AddCustomHeader("Location", redirect_url.spec()); | 82 response->AddCustomHeader("Location", redirect_url.spec()); |
| 82 return std::move(response); | 83 return std::move(response); |
| 83 } | 84 } |
| 84 | 85 |
| 85 const char kBlinkPreconnectFeature[] = "LinkPreconnect"; | 86 const char kBlinkPreconnectFeature[] = "LinkPreconnect"; |
| 86 const char kChromiumHostname[] = "chromium.org"; | 87 const char kChromiumHost[] = "http://chromium.org"; |
|
eroman
2016/05/27 00:56:38
nit: Can you call this a "url" or "origin" now?
Charlie Harrison
2016/05/27 11:55:53
Done.
| |
| 87 const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-" | 88 const char kInvalidLongHost[] = |
|
eroman
2016/05/27 00:56:38
same
Charlie Harrison
2016/05/27 11:55:53
Done.
| |
| 88 "characters-should-not-send-an-ipc-message-to-the-browser-" | 89 "http://" |
| 89 "0000000000000000000000000000000000000000000000000000000000000000000000000" | 90 "illegally-long-hostname-over-255-characters-should-not-send-an-ipc-" |
| 90 "0000000000000000000000000000000000000000000000000000000000000000000000000" | 91 "message-to-the-browser-" |
| 91 "000000000000000000000000000000000000000000000000000000.org"; | 92 "00000000000000000000000000000000000000000000000000000000000000000000000000" |
| 93 "00000000000000000000000000000000000000000000000000000000000000000000000000" | |
| 94 "0000000000000000000000000000000000000000000000000000.org"; | |
| 92 | 95 |
| 93 // Gets notified by the EmbeddedTestServer on incoming connections being | 96 // Gets notified by the EmbeddedTestServer on incoming connections being |
| 94 // accepted or read from, keeps track of them and exposes that info to | 97 // accepted or read from, keeps track of them and exposes that info to |
| 95 // the tests. | 98 // the tests. |
| 96 // A port being reused is currently considered an error. If a test | 99 // A port being reused is currently considered an error. If a test |
| 97 // needs to verify multiple connections are opened in sequence, that will need | 100 // needs to verify multiple connections are opened in sequence, that will need |
| 98 // to be changed. | 101 // to be changed. |
| 99 class ConnectionListener | 102 class ConnectionListener |
| 100 : public net::test_server::EmbeddedTestServerConnectionListener { | 103 : public net::test_server::EmbeddedTestServerConnectionListener { |
| 101 public: | 104 public: |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 | 241 |
| 239 // If |num_accepted_connections_needed_| is non zero, then the object is | 242 // If |num_accepted_connections_needed_| is non zero, then the object is |
| 240 // waiting for |num_accepted_connections_needed_| sockets to be accepted | 243 // waiting for |num_accepted_connections_needed_| sockets to be accepted |
| 241 // before quitting the |num_accepted_connections_loop_|. | 244 // before quitting the |num_accepted_connections_loop_|. |
| 242 size_t num_accepted_connections_needed_; | 245 size_t num_accepted_connections_needed_; |
| 243 base::RunLoop* num_accepted_connections_loop_; | 246 base::RunLoop* num_accepted_connections_loop_; |
| 244 | 247 |
| 245 DISALLOW_COPY_AND_ASSIGN(ConnectionListener); | 248 DISALLOW_COPY_AND_ASSIGN(ConnectionListener); |
| 246 }; | 249 }; |
| 247 | 250 |
| 248 // Records a history of all hostnames for which resolving has been requested, | |
| 249 // and immediately fails the resolution requests themselves. | |
| 250 class HostResolutionRequestRecorder : public net::HostResolverProc { | |
| 251 public: | |
| 252 HostResolutionRequestRecorder() | |
| 253 : HostResolverProc(NULL), | |
| 254 is_waiting_for_hostname_(false) { | |
| 255 } | |
| 256 | |
| 257 int Resolve(const std::string& host, | |
| 258 net::AddressFamily address_family, | |
| 259 net::HostResolverFlags host_resolver_flags, | |
| 260 net::AddressList* addrlist, | |
| 261 int* os_error) override { | |
| 262 BrowserThread::PostTask( | |
| 263 BrowserThread::UI, | |
| 264 FROM_HERE, | |
| 265 base::Bind(&HostResolutionRequestRecorder::AddToHistory, | |
| 266 base::Unretained(this), | |
| 267 host)); | |
| 268 return net::ERR_NAME_NOT_RESOLVED; | |
| 269 } | |
| 270 | |
| 271 int RequestedHostnameCount() const { | |
| 272 return requested_hostnames_.size(); | |
| 273 } | |
| 274 | |
| 275 bool HasHostBeenRequested(const std::string& hostname) const { | |
| 276 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 277 return std::find(requested_hostnames_.begin(), | |
| 278 requested_hostnames_.end(), | |
| 279 hostname) != requested_hostnames_.end(); | |
| 280 } | |
| 281 | |
| 282 void WaitUntilHostHasBeenRequested(const std::string& hostname) { | |
| 283 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 284 DCHECK(!is_waiting_for_hostname_); | |
| 285 if (HasHostBeenRequested(hostname)) | |
| 286 return; | |
| 287 waiting_for_hostname_ = hostname; | |
| 288 is_waiting_for_hostname_ = true; | |
| 289 content::RunMessageLoop(); | |
| 290 } | |
| 291 | |
| 292 private: | |
| 293 ~HostResolutionRequestRecorder() override {} | |
| 294 | |
| 295 void AddToHistory(const std::string& hostname) { | |
| 296 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 297 requested_hostnames_.push_back(hostname); | |
| 298 if (is_waiting_for_hostname_ && waiting_for_hostname_ == hostname) { | |
| 299 is_waiting_for_hostname_ = false; | |
| 300 waiting_for_hostname_.clear(); | |
| 301 base::MessageLoop::current()->QuitWhenIdle(); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 // The hostname which WaitUntilHostHasBeenRequested is currently waiting for | |
| 306 // to be requested. | |
| 307 std::string waiting_for_hostname_; | |
| 308 | |
| 309 // Whether WaitUntilHostHasBeenRequested is waiting for a hostname to be | |
| 310 // requested and thus is running a nested message loop. | |
| 311 bool is_waiting_for_hostname_; | |
| 312 | |
| 313 // A list of hostnames for which resolution has already been requested. Only | |
| 314 // to be accessed from the UI thread. | |
| 315 std::vector<std::string> requested_hostnames_; | |
| 316 | |
| 317 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder); | |
| 318 }; | |
| 319 | |
| 320 // This class intercepts URLRequests and responds with the URLRequestJob* | 251 // This class intercepts URLRequests and responds with the URLRequestJob* |
| 321 // callback provided by the constructor. Note that the port of the URL must | 252 // callback provided by the constructor. Note that the port of the URL must |
| 322 // match the port given in the constructor. | 253 // match the port given in the constructor. |
| 323 class MatchingPortRequestInterceptor : public net::URLRequestInterceptor { | 254 class MatchingPortRequestInterceptor : public net::URLRequestInterceptor { |
| 324 public: | 255 public: |
| 325 typedef base::Callback<net::URLRequestJob*(net::URLRequest*, | 256 typedef base::Callback<net::URLRequestJob*(net::URLRequest*, |
| 326 net::NetworkDelegate*)> | 257 net::NetworkDelegate*)> |
| 327 CreateJobCallback; | 258 CreateJobCallback; |
| 328 | 259 |
| 329 MatchingPortRequestInterceptor( | 260 MatchingPortRequestInterceptor( |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 355 // two. | 286 // two. |
| 356 class CrossSitePredictorObserver | 287 class CrossSitePredictorObserver |
| 357 : public chrome_browser_net::PredictorObserver { | 288 : public chrome_browser_net::PredictorObserver { |
| 358 public: | 289 public: |
| 359 CrossSitePredictorObserver(const GURL& source_host, | 290 CrossSitePredictorObserver(const GURL& source_host, |
| 360 const GURL& cross_site_host) | 291 const GURL& cross_site_host) |
| 361 : source_host_(source_host), | 292 : source_host_(source_host), |
| 362 cross_site_host_(cross_site_host), | 293 cross_site_host_(cross_site_host), |
| 363 cross_site_learned_(0), | 294 cross_site_learned_(0), |
| 364 cross_site_preconnected_(0), | 295 cross_site_preconnected_(0), |
| 365 same_site_preconnected_(0) {} | 296 same_site_preconnected_(0), |
| 297 dns_run_loop_(nullptr) {} | |
| 366 | 298 |
| 367 void OnPreconnectUrl( | 299 void OnPreconnectUrl( |
| 368 const GURL& original_url, | 300 const GURL& original_url, |
| 369 const GURL& first_party_for_cookies, | 301 const GURL& first_party_for_cookies, |
| 370 chrome_browser_net::UrlInfo::ResolutionMotivation motivation, | 302 chrome_browser_net::UrlInfo::ResolutionMotivation motivation, |
| 371 int count) override { | 303 int count) override { |
| 372 base::AutoLock lock(lock_); | 304 base::AutoLock lock(lock_); |
| 373 if (original_url == cross_site_host_) { | 305 if (original_url == cross_site_host_) { |
| 374 cross_site_preconnected_ = std::max(cross_site_preconnected_, count); | 306 cross_site_preconnected_ = std::max(cross_site_preconnected_, count); |
| 375 } else if (original_url == source_host_) { | 307 } else if (original_url == source_host_) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 395 // Same site learned. Branch retained for clarity. | 327 // Same site learned. Branch retained for clarity. |
| 396 } else if (!(referring_url == cross_site_host_ && | 328 } else if (!(referring_url == cross_site_host_ && |
| 397 target_url == cross_site_host_)) { | 329 target_url == cross_site_host_)) { |
| 398 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url | 330 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url |
| 399 << " when should only be learning the source host: " | 331 << " when should only be learning the source host: " |
| 400 << source_host_ | 332 << source_host_ |
| 401 << " or the cross site host: " << cross_site_host_; | 333 << " or the cross site host: " << cross_site_host_; |
| 402 } | 334 } |
| 403 } | 335 } |
| 404 | 336 |
| 337 void OnDnsLookupFinished(const GURL& url, bool found) override { | |
| 338 base::AutoLock lock(lock_); | |
| 339 if (found) { | |
| 340 successful_dns_lookups_.insert(url); | |
| 341 } else { | |
| 342 unsuccessful_dns_lookups_.insert(url); | |
| 343 } | |
| 344 CheckForWaitingLoop(); | |
| 345 } | |
| 346 | |
| 405 void ResetCounts() { | 347 void ResetCounts() { |
| 406 base::AutoLock lock(lock_); | 348 base::AutoLock lock(lock_); |
| 407 cross_site_learned_ = 0; | 349 cross_site_learned_ = 0; |
| 408 cross_site_preconnected_ = 0; | 350 cross_site_preconnected_ = 0; |
| 409 same_site_preconnected_ = 0; | 351 same_site_preconnected_ = 0; |
| 410 } | 352 } |
| 411 | 353 |
| 412 int CrossSiteLearned() { | 354 int CrossSiteLearned() { |
| 413 base::AutoLock lock(lock_); | 355 base::AutoLock lock(lock_); |
| 414 return cross_site_learned_; | 356 return cross_site_learned_; |
| 415 } | 357 } |
| 416 | 358 |
| 417 int CrossSitePreconnected() { | 359 int CrossSitePreconnected() { |
| 418 base::AutoLock lock(lock_); | 360 base::AutoLock lock(lock_); |
| 419 return cross_site_preconnected_; | 361 return cross_site_preconnected_; |
| 420 } | 362 } |
| 421 | 363 |
| 422 int SameSitePreconnected() { | 364 int SameSitePreconnected() { |
| 423 base::AutoLock lock(lock_); | 365 base::AutoLock lock(lock_); |
| 424 return same_site_preconnected_; | 366 return same_site_preconnected_; |
| 425 } | 367 } |
| 426 | 368 |
| 369 // Spins a run loop until |url| is added to one of the lookup maps. | |
| 370 void WaitUntilHostLookedUp(const GURL& url) { | |
| 371 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 372 base::RunLoop run_loop; | |
| 373 { | |
| 374 base::AutoLock lock(lock_); | |
| 375 DCHECK(waiting_on_dns_.is_empty()); | |
| 376 DCHECK(!dns_run_loop_); | |
| 377 waiting_on_dns_ = url; | |
| 378 dns_run_loop_ = &run_loop; | |
| 379 CheckForWaitingLoop(); | |
| 380 } | |
| 381 run_loop.Run(); | |
| 382 } | |
| 383 | |
| 384 bool HasHostBeenLookedUpLocked(const GURL& url) { | |
| 385 lock_.AssertAcquired(); | |
| 386 return successful_dns_lookups_.find(url) != successful_dns_lookups_.end() || | |
|
eroman
2016/05/27 00:56:38
optional: can use ContainsKey() to simplify the va
Charlie Harrison
2016/05/27 11:55:52
Done.
| |
| 387 unsuccessful_dns_lookups_.find(url) != | |
| 388 unsuccessful_dns_lookups_.end(); | |
| 389 } | |
| 390 | |
| 391 bool HasHostBeenLookedUp(const GURL& url) { | |
| 392 base::AutoLock lock(lock_); | |
| 393 return HasHostBeenLookedUpLocked(url); | |
| 394 } | |
| 395 | |
| 396 void CheckForWaitingLoop() { | |
| 397 lock_.AssertAcquired(); | |
| 398 if (waiting_on_dns_.is_empty()) | |
| 399 return; | |
| 400 if (!HasHostBeenLookedUpLocked(waiting_on_dns_)) | |
| 401 return; | |
| 402 DCHECK(dns_run_loop_); | |
| 403 DCHECK(task_runner_); | |
| 404 waiting_on_dns_ = GURL(); | |
| 405 task_runner_->PostTask(FROM_HERE, dns_run_loop_->QuitClosure()); | |
| 406 dns_run_loop_ = nullptr; | |
| 407 } | |
| 408 | |
| 409 size_t TotalHostsLookedUp() { | |
| 410 base::AutoLock lock(lock_); | |
| 411 return successful_dns_lookups_.size() + unsuccessful_dns_lookups_.size(); | |
| 412 } | |
| 413 | |
| 414 // Note: this method expects the URL to have been looked up. | |
| 415 bool HostFound(const GURL& url) { | |
| 416 base::AutoLock lock(lock_); | |
| 417 EXPECT_TRUE(HasHostBeenLookedUpLocked(url)) << "Expected to have looked up" | |
|
eroman
2016/05/27 00:56:38
nit: add a space at the end of the string.
Charlie Harrison
2016/05/27 11:55:53
Done.
| |
| 418 << url.spec(); | |
| 419 return successful_dns_lookups_.find(url) != successful_dns_lookups_.end(); | |
| 420 } | |
| 421 | |
| 422 void set_task_runner( | |
| 423 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | |
| 424 task_runner_.swap(task_runner); | |
| 425 } | |
| 426 | |
| 427 private: | 427 private: |
| 428 const GURL source_host_; | 428 const GURL source_host_; |
| 429 const GURL cross_site_host_; | 429 const GURL cross_site_host_; |
| 430 | 430 |
| 431 GURL waiting_on_dns_; | |
| 432 | |
| 433 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
| 434 | |
| 431 // Protects all following members. They are read and updated from different | 435 // Protects all following members. They are read and updated from different |
| 432 // threads. | 436 // threads. |
| 433 base::Lock lock_; | 437 base::Lock lock_; |
| 434 | 438 |
| 435 int cross_site_learned_; | 439 int cross_site_learned_; |
| 436 int cross_site_preconnected_; | 440 int cross_site_preconnected_; |
| 437 int same_site_preconnected_; | 441 int same_site_preconnected_; |
| 438 | 442 |
| 443 std::set<GURL> successful_dns_lookups_; | |
| 444 std::set<GURL> unsuccessful_dns_lookups_; | |
| 445 base::RunLoop* dns_run_loop_; | |
| 446 | |
| 439 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver); | 447 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver); |
| 440 }; | 448 }; |
| 441 | 449 |
| 442 } // namespace | 450 } // namespace |
| 443 | 451 |
| 444 namespace chrome_browser_net { | 452 namespace chrome_browser_net { |
| 445 | 453 |
| 446 class PredictorBrowserTest : public InProcessBrowserTest { | 454 class PredictorBrowserTest : public InProcessBrowserTest { |
| 447 public: | 455 public: |
| 448 PredictorBrowserTest() | 456 PredictorBrowserTest() |
| 449 : startup_url_("http://host1:1"), | 457 : startup_url_("http://host1/"), |
| 450 referring_url_("http://host2:1"), | 458 referring_url_("http://host2/"), |
| 451 target_url_("http://host3:1"), | 459 target_url_("http://host3/"), |
| 452 host_resolution_request_recorder_(new HostResolutionRequestRecorder), | 460 rule_based_resolver_proc_(new net::RuleBasedHostResolverProc(nullptr)), |
| 453 cross_site_test_server_(new net::EmbeddedTestServer()) {} | 461 cross_site_test_server_(new net::EmbeddedTestServer()) { |
| 462 rule_based_resolver_proc_->AddRuleWithLatency("www.example.test", | |
| 463 "127.0.0.1", 50); | |
| 464 rule_based_resolver_proc_->AddRuleWithLatency("gmail.google.com", | |
| 465 "127.0.0.1", 70); | |
| 466 rule_based_resolver_proc_->AddRuleWithLatency("mail.google.com", | |
| 467 "127.0.0.1", 44); | |
| 468 rule_based_resolver_proc_->AddRuleWithLatency("gmail.com", "127.0.0.1", 63); | |
| 469 rule_based_resolver_proc_->AddSimulatedFailure("*.notfound"); | |
| 470 rule_based_resolver_proc_->AddRuleWithLatency("delay.google.com", | |
| 471 "127.0.0.1", 1000 * 60); | |
| 472 } | |
| 454 | 473 |
| 455 protected: | 474 protected: |
| 456 void SetUpInProcessBrowserTestFixture() override { | 475 void SetUpInProcessBrowserTestFixture() override { |
| 457 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc( | 476 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc( |
| 458 host_resolution_request_recorder_.get())); | 477 rule_based_resolver_proc_.get())); |
| 459 InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); | 478 InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); |
| 460 } | 479 } |
| 461 | 480 |
| 462 void SetUpCommandLine(base::CommandLine* command_line) override { | 481 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 463 command_line->AppendSwitch( | 482 command_line->AppendSwitch( |
| 464 switches::kEnableExperimentalWebPlatformFeatures); | 483 switches::kEnableExperimentalWebPlatformFeatures); |
| 465 command_line->AppendSwitchASCII( | 484 command_line->AppendSwitchASCII( |
| 466 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature); | 485 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature); |
| 467 command_line->AppendSwitchASCII(switches::kEnableFeatures, | 486 command_line->AppendSwitchASCII(switches::kEnableFeatures, |
| 468 "PreconnectMore"); | 487 "PreconnectMore"); |
| 488 command_line->AppendSwitchASCII(switches::kEnableFeatures, | |
| 489 "UsePredictorDNSQueue"); | |
| 469 } | 490 } |
| 470 | 491 |
| 471 void SetUpOnMainThread() override { | 492 void SetUpOnMainThread() override { |
| 472 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 493 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 473 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 494 task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 474 cross_site_test_server_->ServeFilesFromSourceDirectory("chrome/test/data/"); | 495 cross_site_test_server_->ServeFilesFromSourceDirectory("chrome/test/data/"); |
| 475 | 496 |
| 476 connection_listener_.reset(new ConnectionListener()); | 497 connection_listener_.reset(new ConnectionListener()); |
| 477 cross_site_connection_listener_.reset(new ConnectionListener()); | 498 cross_site_connection_listener_.reset(new ConnectionListener()); |
| 478 embedded_test_server()->SetConnectionListener(connection_listener_.get()); | 499 embedded_test_server()->SetConnectionListener(connection_listener_.get()); |
| 479 cross_site_test_server_->SetConnectionListener( | 500 cross_site_test_server_->SetConnectionListener( |
| 480 cross_site_connection_listener_.get()); | 501 cross_site_connection_listener_.get()); |
| 481 ASSERT_TRUE(embedded_test_server()->Start()); | 502 ASSERT_TRUE(embedded_test_server()->Start()); |
| 482 ASSERT_TRUE(cross_site_test_server_->Start()); | 503 ASSERT_TRUE(cross_site_test_server_->Start()); |
| 483 | 504 |
| 484 embedded_test_server()->RegisterRequestHandler( | 505 embedded_test_server()->RegisterRequestHandler( |
| 485 base::Bind(&RedirectForPathHandler, "/", | 506 base::Bind(&RedirectForPathHandler, "/", |
| 486 cross_site_test_server()->GetURL("/title1.html"))); | 507 cross_site_test_server()->GetURL("/title1.html"))); |
| 487 | 508 |
| 488 predictor()->SetPreconnectEnabledForTest(true); | 509 predictor()->SetPreconnectEnabledForTest(true); |
| 489 InstallPredictorObserver(embedded_test_server()->base_url(), | 510 InstallPredictorObserver(embedded_test_server()->base_url(), |
| 490 cross_site_test_server()->base_url()); | 511 cross_site_test_server()->base_url()); |
| 512 observer()->set_task_runner(task_runner_); | |
| 491 StartInterceptingCrossSiteOnUI(); | 513 StartInterceptingCrossSiteOnUI(); |
| 492 } | 514 } |
| 493 | 515 |
| 494 // Intercepts all requests to the specified host and returns a response with | 516 // Intercepts all requests to the specified host and returns a response with |
| 495 // an empty body. Needed to prevent requests from actually going to the test | 517 // an empty body. Needed to prevent requests from actually going to the test |
| 496 // server, to avoid any races related to socket accounting. Note, the | 518 // server, to avoid any races related to socket accounting. Note, the |
| 497 // interceptor also looks at the port, to differentiate between the | 519 // interceptor also looks at the port, to differentiate between the |
| 498 // two test servers. | 520 // two test servers. |
| 499 static void StartInterceptingHost(const GURL& url) { | 521 static void StartInterceptingHost(const GURL& url) { |
| 500 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 522 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 } | 588 } |
| 567 | 589 |
| 568 void GetListFromPrefsAsString(const char* list_path, | 590 void GetListFromPrefsAsString(const char* list_path, |
| 569 std::string* value_as_string) const { | 591 std::string* value_as_string) const { |
| 570 PrefService* prefs = browser()->profile()->GetPrefs(); | 592 PrefService* prefs = browser()->profile()->GetPrefs(); |
| 571 const base::ListValue* list_value = prefs->GetList(list_path); | 593 const base::ListValue* list_value = prefs->GetList(list_path); |
| 572 JSONStringValueSerializer serializer(value_as_string); | 594 JSONStringValueSerializer serializer(value_as_string); |
| 573 serializer.Serialize(*list_value); | 595 serializer.Serialize(*list_value); |
| 574 } | 596 } |
| 575 | 597 |
| 576 bool HasHostBeenRequested(const std::string& hostname) const { | 598 void WaitUntilHostsLookedUp(const network_hints::UrlList& names) { |
| 577 return host_resolution_request_recorder_->HasHostBeenRequested(hostname); | 599 for (const GURL& url : names) |
| 600 observer()->WaitUntilHostLookedUp(url); | |
| 578 } | 601 } |
| 579 | 602 |
| 580 void WaitUntilHostHasBeenRequested(const std::string& hostname) { | 603 void FloodResolveRequestsOnUIThread(const network_hints::UrlList& names) { |
| 581 host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname); | 604 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 605 BrowserThread::PostTask( | |
| 606 BrowserThread::IO, FROM_HERE, | |
| 607 base::Bind(&PredictorBrowserTest::FloodResolveRequests, this, names)); | |
| 582 } | 608 } |
| 583 | 609 |
| 584 int RequestedHostnameCount() const { | 610 void FloodResolveRequests(const network_hints::UrlList& names) { |
| 585 return host_resolution_request_recorder_->RequestedHostnameCount(); | 611 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 612 for (int i = 0; i < 10; i++) { | |
| 613 predictor()->DnsPrefetchMotivatedList(names, | |
| 614 UrlInfo::PAGE_SCAN_MOTIVATED); | |
| 615 } | |
| 586 } | 616 } |
| 587 | 617 |
| 588 net::EmbeddedTestServer* cross_site_test_server() { | 618 net::EmbeddedTestServer* cross_site_test_server() { |
| 589 return cross_site_test_server_.get(); | 619 return cross_site_test_server_.get(); |
| 590 } | 620 } |
| 591 | 621 |
| 592 Predictor* predictor() { return browser()->profile()->GetNetworkPredictor(); } | 622 Predictor* predictor() { return browser()->profile()->GetNetworkPredictor(); } |
| 593 | 623 |
| 594 void InstallPredictorObserver(const GURL& source_host, | 624 void InstallPredictorObserver(const GURL& source_host, |
| 595 const GURL& cross_site_host) { | 625 const GURL& cross_site_host) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 632 base::Unretained(this)), | 662 base::Unretained(this)), |
| 633 run_loop.QuitClosure()); | 663 run_loop.QuitClosure()); |
| 634 run_loop.Run(); | 664 run_loop.Run(); |
| 635 } | 665 } |
| 636 | 666 |
| 637 void FlushServerSocketsOnUIThread(net::EmbeddedTestServer* test_server) { | 667 void FlushServerSocketsOnUIThread(net::EmbeddedTestServer* test_server) { |
| 638 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 668 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 639 EXPECT_TRUE(test_server->FlushAllSocketsAndConnectionsOnUIThread()); | 669 EXPECT_TRUE(test_server->FlushAllSocketsAndConnectionsOnUIThread()); |
| 640 } | 670 } |
| 641 | 671 |
| 672 // Note this method also expects that all the urls (found or not) were looked | |
| 673 // up. | |
| 674 void ExpectFoundUrls( | |
| 675 const network_hints::UrlList& found_names, | |
| 676 const network_hints::UrlList& not_found_names) { | |
| 677 for (const auto& name : found_names) { | |
| 678 EXPECT_TRUE(observer()->HostFound(name)) << "Expected to have found " | |
| 679 << name.spec(); | |
| 680 } | |
| 681 for (const auto& name : not_found_names) { | |
| 682 EXPECT_FALSE(observer()->HostFound(name)) << "Did not expect to find " | |
| 683 << name.spec(); | |
| 684 } | |
| 685 } | |
| 686 | |
| 687 // This method verifies that |url| is in the predictors |results_| map. This | |
|
eroman
2016/05/27 00:56:38
nit: predictors --> predictor's
Charlie Harrison
2016/05/27 11:55:52
Done.
| |
| 688 // is used for pending lookups, and lookups performed before the observer is | |
| 689 // attached. | |
| 690 void ExpectUrlRequestedFromPredictorOnUIThread(const GURL& url) { | |
| 691 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 692 BrowserThread::PostTask( | |
| 693 BrowserThread::IO, FROM_HERE, | |
| 694 base::Bind(&PredictorBrowserTest::ExpectUrlRequestedFromPredictor, | |
| 695 base::Unretained(this), url)); | |
| 696 } | |
| 697 | |
| 698 void ExpectUrlRequestedFromPredictor(const GURL& url) { | |
| 699 EXPECT_NE(predictor()->results_.find(url), predictor()->results_.end()); | |
| 700 } | |
| 701 | |
| 702 void DiscardAllResultsOnUIThread() { | |
| 703 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 704 base::Bind(&Predictor::DiscardAllResults, | |
| 705 base::Unretained(predictor()))); | |
| 706 } | |
| 707 | |
| 708 void ExpectValidPeakPendingLookupsOnUI(size_t num_names_requested) { | |
| 709 BrowserThread::PostTask( | |
| 710 BrowserThread::IO, FROM_HERE, | |
| 711 base::Bind(&PredictorBrowserTest::ExpectValidPeakPendingLookups, | |
| 712 base::Unretained(this), num_names_requested)); | |
| 713 } | |
| 714 | |
| 715 void ExpectValidPeakPendingLookups(size_t num_names_requested) { | |
| 716 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 717 EXPECT_LE(predictor()->peak_pending_lookups_, num_names_requested); | |
| 718 EXPECT_LE(predictor()->peak_pending_lookups_, | |
| 719 predictor()->max_concurrent_dns_lookups()); | |
| 720 } | |
| 721 | |
| 642 CrossSitePredictorObserver* observer() { return observer_.get(); } | 722 CrossSitePredictorObserver* observer() { return observer_.get(); } |
| 643 | 723 |
| 644 // Navigate to an html file on embedded_test_server and tell it to request | 724 // Navigate to an html file on embedded_test_server and tell it to request |
| 645 // |num_cors| resources from the cross_site_test_server. It then waits for | 725 // |num_cors| resources from the cross_site_test_server. It then waits for |
| 646 // those requests to complete. Note that "cors" here means using cors-mode in | 726 // those requests to complete. Note that "cors" here means using cors-mode in |
| 647 // correspondence with the fetch spec. | 727 // correspondence with the fetch spec. |
| 648 void NavigateToCrossSiteHtmlUrl(int num_cors, const char* file_suffix) { | 728 void NavigateToCrossSiteHtmlUrl(int num_cors, const char* file_suffix) { |
| 649 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 729 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 650 const GURL& base_url = cross_site_test_server()->base_url(); | 730 const GURL& base_url = cross_site_test_server()->base_url(); |
| 651 std::string path = base::StringPrintf( | 731 std::string path = base::StringPrintf( |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 662 EXPECT_TRUE(result); | 742 EXPECT_TRUE(result); |
| 663 } | 743 } |
| 664 | 744 |
| 665 const GURL startup_url_; | 745 const GURL startup_url_; |
| 666 const GURL referring_url_; | 746 const GURL referring_url_; |
| 667 const GURL target_url_; | 747 const GURL target_url_; |
| 668 std::unique_ptr<ConnectionListener> connection_listener_; | 748 std::unique_ptr<ConnectionListener> connection_listener_; |
| 669 std::unique_ptr<ConnectionListener> cross_site_connection_listener_; | 749 std::unique_ptr<ConnectionListener> cross_site_connection_listener_; |
| 670 | 750 |
| 671 private: | 751 private: |
| 672 scoped_refptr<HostResolutionRequestRecorder> | 752 scoped_refptr<net::RuleBasedHostResolverProc> rule_based_resolver_proc_; |
| 673 host_resolution_request_recorder_; | |
| 674 std::unique_ptr<net::ScopedDefaultHostResolverProc> | 753 std::unique_ptr<net::ScopedDefaultHostResolverProc> |
| 675 scoped_host_resolver_proc_; | 754 scoped_host_resolver_proc_; |
| 676 std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_; | 755 std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_; |
| 677 std::unique_ptr<CrossSitePredictorObserver> observer_; | 756 std::unique_ptr<CrossSitePredictorObserver> observer_; |
| 678 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 757 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 679 }; | 758 }; |
| 680 | 759 |
| 760 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SingleLookupTest) { | |
| 761 DiscardAllResultsOnUIThread(); | |
| 762 GURL goog("http://www.example.test/"); | |
|
eroman
2016/05/27 00:56:38
probably better to call this "url" -- not actually
Charlie Harrison
2016/05/27 11:55:53
Done.
| |
| 763 | |
| 764 // Try to flood the predictor with many concurrent requests. | |
| 765 network_hints::UrlList names{goog}; | |
| 766 FloodResolveRequestsOnUIThread(names); | |
| 767 observer()->WaitUntilHostLookedUp(goog); | |
| 768 EXPECT_TRUE(observer()->HostFound(goog)); | |
| 769 ExpectValidPeakPendingLookupsOnUI(1u); | |
| 770 } | |
| 771 | |
| 772 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ConcurrentLookupTest) { | |
| 773 DiscardAllResultsOnUIThread(); | |
| 774 GURL goog("http://www.example.test"), goog2("http://gmail.google.com"), | |
|
eroman
2016/05/27 00:56:38
same here -- at least for one of them.
Charlie Harrison
2016/05/27 11:55:53
Done.
| |
| 775 goog3("http://mail.google.com"), goog4("http://gmail.com"); | |
| 776 GURL bad1("http://bad1.notfound"), bad2("http://bad2.notfound"); | |
| 777 | |
| 778 UrlList found_names{goog, goog3, goog2, goog4, goog}; | |
| 779 UrlList not_found_names{bad1, bad2}; | |
| 780 FloodResolveRequestsOnUIThread(found_names); | |
| 781 FloodResolveRequestsOnUIThread(not_found_names); | |
| 782 | |
| 783 WaitUntilHostsLookedUp(found_names); | |
| 784 WaitUntilHostsLookedUp(not_found_names); | |
| 785 ExpectFoundUrls(found_names, not_found_names); | |
| 786 ExpectValidPeakPendingLookupsOnUI(found_names.size() + | |
| 787 not_found_names.size()); | |
| 788 } | |
| 789 | |
| 790 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, MassiveConcurrentLookupTest) { | |
| 791 DiscardAllResultsOnUIThread(); | |
| 792 UrlList not_found_names; | |
| 793 for (int i = 0; i < 100; i++) { | |
| 794 not_found_names.push_back( | |
| 795 GURL(base::StringPrintf("http://host%d.notfound:80", i))); | |
| 796 } | |
| 797 FloodResolveRequestsOnUIThread(not_found_names); | |
| 798 | |
| 799 WaitUntilHostsLookedUp(not_found_names); | |
| 800 ExpectFoundUrls(network_hints::UrlList(), not_found_names); | |
| 801 ExpectValidPeakPendingLookupsOnUI(not_found_names.size()); | |
| 802 } | |
| 803 | |
| 804 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, | |
| 805 ShutdownWhenResolutionIsPendingTest) { | |
| 806 GURL delayed_url("http://delay.google.com:80"); | |
| 807 UrlList names{delayed_url}; | |
| 808 | |
| 809 // Flood with delayed requests, then wait. | |
| 810 FloodResolveRequestsOnUIThread(names); | |
| 811 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 812 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), | |
| 813 base::TimeDelta::FromMilliseconds(500)); | |
| 814 base::MessageLoop::current()->Run(); | |
| 815 | |
| 816 ExpectUrlRequestedFromPredictor(delayed_url); | |
| 817 EXPECT_FALSE(observer()->HasHostBeenLookedUp(delayed_url)); | |
| 818 } | |
| 819 | |
| 681 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectOne) { | 820 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectOne) { |
| 682 predictor()->PreconnectUrl( | 821 predictor()->PreconnectUrl( |
| 683 embedded_test_server()->base_url(), GURL(), | 822 embedded_test_server()->base_url(), GURL(), |
| 684 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED, | 823 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED, |
| 685 false /* allow credentials */, 1); | 824 false /* allow credentials */, 1); |
| 686 connection_listener_->WaitForAcceptedConnectionsOnUI(1u); | 825 connection_listener_->WaitForAcceptedConnectionsOnUI(1u); |
| 687 } | 826 } |
| 688 | 827 |
| 689 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectTwo) { | 828 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectTwo) { |
| 690 predictor()->PreconnectUrl( | 829 predictor()->PreconnectUrl( |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1121 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList, | 1260 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList, |
| 1122 &cleared_referral_list); | 1261 &cleared_referral_list); |
| 1123 | 1262 |
| 1124 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host()))); | 1263 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host()))); |
| 1125 EXPECT_THAT(cleared_referral_list, Not(HasSubstr(referring_url_.host()))); | 1264 EXPECT_THAT(cleared_referral_list, Not(HasSubstr(referring_url_.host()))); |
| 1126 EXPECT_THAT(cleared_referral_list, Not(HasSubstr(target_url_.host()))); | 1265 EXPECT_THAT(cleared_referral_list, Not(HasSubstr(target_url_.host()))); |
| 1127 | 1266 |
| 1128 // But also make sure this data has been first loaded into the Predictor, by | 1267 // But also make sure this data has been first loaded into the Predictor, by |
| 1129 // inspecting that the Predictor starts making the expected hostname requests. | 1268 // inspecting that the Predictor starts making the expected hostname requests. |
| 1130 PrepareFrameSubresources(referring_url_); | 1269 PrepareFrameSubresources(referring_url_); |
| 1131 WaitUntilHostHasBeenRequested(startup_url_.host()); | 1270 observer()->WaitUntilHostLookedUp(target_url_); |
| 1132 WaitUntilHostHasBeenRequested(target_url_.host()); | 1271 |
| 1272 // Verify that both urls were requested by the predictor. Note that the | |
| 1273 // startup URL may be requested before the observer attaches itself. | |
| 1274 ExpectUrlRequestedFromPredictor(startup_url_); | |
| 1275 EXPECT_FALSE(observer()->HostFound(target_url_)); | |
| 1133 } | 1276 } |
| 1134 | 1277 |
| 1135 // Flaky on Windows: http://crbug.com/469120 | 1278 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, DnsPrefetch) { |
| 1136 #if defined(OS_WIN) | 1279 // Navigate once to make sure all initial hostnames are requested. |
| 1137 #define MAYBE_DnsPrefetch DISABLED_DnsPrefetch | 1280 ui_test_utils::NavigateToURL(browser(), |
| 1138 #else | 1281 embedded_test_server()->GetURL("/title1.html")); |
| 1139 #define MAYBE_DnsPrefetch DnsPrefetch | 1282 |
| 1140 #endif | 1283 size_t hosts_looked_up_before_load = observer()->TotalHostsLookedUp(); |
| 1141 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, MAYBE_DnsPrefetch) { | 1284 |
| 1142 int hostnames_requested_before_load = RequestedHostnameCount(); | 1285 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL( |
| 1143 ui_test_utils::NavigateToURL( | 1286 "/predictor/dns_prefetch.html")); |
| 1144 browser(), | 1287 observer()->WaitUntilHostLookedUp(GURL(kChromiumHost)); |
| 1145 GURL(embedded_test_server()->GetURL("/predictor/dns_prefetch.html"))); | 1288 ASSERT_FALSE(observer()->HasHostBeenLookedUp(GURL(kInvalidLongHost))); |
| 1146 WaitUntilHostHasBeenRequested(kChromiumHostname); | 1289 |
| 1147 ASSERT_FALSE(HasHostBeenRequested(kInvalidLongHostname)); | 1290 EXPECT_FALSE(observer()->HostFound(GURL(kChromiumHost))); |
| 1148 ASSERT_EQ(hostnames_requested_before_load + 1, RequestedHostnameCount()); | 1291 ASSERT_EQ(hosts_looked_up_before_load + 1, observer()->TotalHostsLookedUp()); |
| 1149 } | 1292 } |
| 1150 | 1293 |
| 1151 // Tests that preconnect warms up a socket connection to a test server. | 1294 // Tests that preconnect warms up a socket connection to a test server. |
| 1152 // Note: This test uses a data URI to serve the preconnect hint, to make sure | 1295 // Note: This test uses a data URI to serve the preconnect hint, to make sure |
| 1153 // that the network stack doesn't just re-use its connection to the test server. | 1296 // that the network stack doesn't just re-use its connection to the test server. |
| 1154 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PreconnectNonCORS) { | 1297 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PreconnectNonCORS) { |
| 1155 GURL preconnect_url = embedded_test_server()->base_url(); | 1298 GURL preconnect_url = embedded_test_server()->base_url(); |
| 1156 std::string preconnect_content = | 1299 std::string preconnect_content = |
| 1157 "<link rel=\"preconnect\" href=\"" + preconnect_url.spec() + "\">"; | 1300 "<link rel=\"preconnect\" href=\"" + preconnect_url.spec() + "\">"; |
| 1158 NavigateToDataURLWithContent(preconnect_content); | 1301 NavigateToDataURLWithContent(preconnect_content); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1249 // Second navigation to content with an img. | 1392 // Second navigation to content with an img. |
| 1250 std::string img_content = | 1393 std::string img_content = |
| 1251 "<img src=\"" + preconnect_url.spec() + "test.gif\">"; | 1394 "<img src=\"" + preconnect_url.spec() + "test.gif\">"; |
| 1252 NavigateToDataURLWithContent(img_content); | 1395 NavigateToDataURLWithContent(img_content); |
| 1253 connection_listener_->WaitUntilFirstConnectionRead(); | 1396 connection_listener_->WaitUntilFirstConnectionRead(); |
| 1254 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount()); | 1397 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount()); |
| 1255 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount()); | 1398 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount()); |
| 1256 } | 1399 } |
| 1257 | 1400 |
| 1258 } // namespace chrome_browser_net | 1401 } // namespace chrome_browser_net |
| OLD | NEW |