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

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

Issue 1881463003: Add a browsertest suite for net predictor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: EXPECT that we get the right number of accepted connections after waiting Created 4 years, 7 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/test/data/predictor/empty.js » ('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>
9 #include <memory>
10
8 #include "base/base64.h" 11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/callback.h"
9 #include "base/command_line.h" 14 #include "base/command_line.h"
10 #include "base/json/json_string_value_serializer.h" 15 #include "base/json/json_string_value_serializer.h"
11 #include "base/macros.h" 16 #include "base/macros.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/memory/ref_counted.h"
12 #include "base/synchronization/lock.h" 19 #include "base/synchronization/lock.h"
13 #include "base/threading/thread_task_runner_handle.h" 20 #include "base/threading/thread_task_runner_handle.h"
14 #include "build/build_config.h" 21 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/net/predictor.h" 23 #include "chrome/browser/net/predictor.h"
17 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h" 25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/pref_names.h" 27 #include "chrome/common/pref_names.h"
20 #include "chrome/test/base/in_process_browser_test.h" 28 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h" 29 #include "chrome/test/base/ui_test_utils.h"
22 #include "components/prefs/pref_service.h" 30 #include "components/prefs/pref_service.h"
23 #include "content/public/common/content_switches.h" 31 #include "content/public/common/content_switches.h"
32 #include "content/public/test/browser_test_utils.h"
24 #include "content/public/test/test_utils.h" 33 #include "content/public/test/test_utils.h"
25 #include "net/base/host_port_pair.h" 34 #include "net/base/host_port_pair.h"
26 #include "net/base/ip_endpoint.h" 35 #include "net/base/ip_endpoint.h"
27 #include "net/base/net_errors.h" 36 #include "net/base/net_errors.h"
28 #include "net/dns/host_resolver_proc.h" 37 #include "net/dns/host_resolver_proc.h"
29 #include "net/dns/mock_host_resolver.h" 38 #include "net/dns/mock_host_resolver.h"
39 #include "net/http/http_transaction_factory.h"
30 #include "net/socket/stream_socket.h" 40 #include "net/socket/stream_socket.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h" 41 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h" 42 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h"
43 #include "net/test/embedded_test_server/http_request.h"
44 #include "net/test/embedded_test_server/http_response.h"
45 #include "net/test/url_request/url_request_failed_job.h"
46 #include "net/url_request/url_request_context.h"
47 #include "net/url_request/url_request_context_getter.h"
48 #include "net/url_request/url_request_filter.h"
49 #include "net/url_request/url_request_interceptor.h"
50 #include "net/url_request/url_request_test_job.h"
33 #include "testing/gmock/include/gmock/gmock.h" 51 #include "testing/gmock/include/gmock/gmock.h"
52 #include "url/gurl.h"
34 53
35 using content::BrowserThread; 54 using content::BrowserThread;
36 using testing::HasSubstr; 55 using testing::HasSubstr;
37 56
38 namespace { 57 namespace {
39 58
59 net::URLRequestJob* CreateEmptyBodyRequestJob(net::URLRequest* request,
60 net::NetworkDelegate* delegate) {
61 const char kPlainTextHeaders[] =
62 "HTTP/1.1 200 OK\n"
63 "Content-Type: text/plain\n"
64 "Access-Control-Allow-Origin: *\n"
65 "\n";
66 return new net::URLRequestTestJob(request, delegate, kPlainTextHeaders, "",
67 true);
68 }
69
70 // Override the test server to redirect requests matching some path. This is
71 // used because the predictor only learns simple redirects with a path of "/"
72 std::unique_ptr<net::test_server::HttpResponse> RedirectForPathHandler(
73 const std::string& path,
74 const GURL& redirect_url,
75 const net::test_server::HttpRequest& request) {
76 if (request.GetURL().path() != path)
77 return nullptr;
78 std::unique_ptr<net::test_server::BasicHttpResponse> response(
79 new net::test_server::BasicHttpResponse);
80 response->set_code(net::HTTP_MOVED_PERMANENTLY);
81 response->AddCustomHeader("Location", redirect_url.spec());
82 return std::move(response);
83 }
84
40 const char kBlinkPreconnectFeature[] = "LinkPreconnect"; 85 const char kBlinkPreconnectFeature[] = "LinkPreconnect";
41 const char kChromiumHostname[] = "chromium.org"; 86 const char kChromiumHostname[] = "chromium.org";
42 const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-" 87 const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-"
43 "characters-should-not-send-an-ipc-message-to-the-browser-" 88 "characters-should-not-send-an-ipc-message-to-the-browser-"
44 "0000000000000000000000000000000000000000000000000000000000000000000000000" 89 "0000000000000000000000000000000000000000000000000000000000000000000000000"
45 "0000000000000000000000000000000000000000000000000000000000000000000000000" 90 "0000000000000000000000000000000000000000000000000000000000000000000000000"
46 "000000000000000000000000000000000000000000000000000000.org"; 91 "000000000000000000000000000000000000000000000000000000.org";
47 92
48 // Gets notified by the EmbeddedTestServer on incoming connections being 93 // Gets notified by the EmbeddedTestServer on incoming connections being
49 // accepted or read from, keeps track of them and exposes that info to 94 // accepted or read from, keeps track of them and exposes that info to
50 // the tests. 95 // the tests.
51 // A port being reused is currently considered an error. If a test 96 // A port being reused is currently considered an error. If a test
52 // needs to verify multiple connections are opened in sequence, that will need 97 // needs to verify multiple connections are opened in sequence, that will need
53 // to be changed. 98 // to be changed.
54 class ConnectionListener 99 class ConnectionListener
55 : public net::test_server::EmbeddedTestServerConnectionListener { 100 : public net::test_server::EmbeddedTestServerConnectionListener {
56 public: 101 public:
57 ConnectionListener() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} 102 ConnectionListener()
103 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
104 num_accepted_connections_needed_(0),
105 num_accepted_connections_loop_(nullptr) {}
58 106
59 ~ConnectionListener() override {} 107 ~ConnectionListener() override {}
60 108
61 // Get called from the EmbeddedTestServer thread to be notified that 109 // Get called from the EmbeddedTestServer thread to be notified that
62 // a connection was accepted. 110 // a connection was accepted.
63 void AcceptedSocket(const net::StreamSocket& connection) override { 111 void AcceptedSocket(const net::StreamSocket& connection) override {
64 base::AutoLock lock(lock_); 112 base::AutoLock lock(lock_);
65 uint16_t socket = GetPort(connection); 113 uint16_t socket = GetPort(connection);
66 EXPECT_TRUE(sockets_.find(socket) == sockets_.end()); 114 EXPECT_TRUE(sockets_.find(socket) == sockets_.end());
67 115
68 sockets_[socket] = SOCKET_ACCEPTED; 116 sockets_[socket] = SOCKET_ACCEPTED;
69 task_runner_->PostTask(FROM_HERE, accept_loop_.QuitClosure()); 117 task_runner_->PostTask(FROM_HERE, accept_loop_.QuitClosure());
118 CheckAccepted();
70 } 119 }
71 120
72 // Get called from the EmbeddedTestServer thread to be notified that 121 // Get called from the EmbeddedTestServer thread to be notified that
73 // a connection was read from. 122 // a connection was read from.
74 void ReadFromSocket(const net::StreamSocket& connection) override { 123 void ReadFromSocket(const net::StreamSocket& connection, int rv) override {
124 // Don't log a read if no data was transferred. This case often happens if
125 // the sockets of the test server are being flushed and disconnected.
126 if (rv <= 0)
127 return;
75 base::AutoLock lock(lock_); 128 base::AutoLock lock(lock_);
76 uint16_t socket = GetPort(connection); 129 uint16_t socket = GetPort(connection);
77 EXPECT_FALSE(sockets_.find(socket) == sockets_.end()); 130 EXPECT_FALSE(sockets_.find(socket) == sockets_.end());
78 131
79 sockets_[socket] = SOCKET_READ_FROM; 132 sockets_[socket] = SOCKET_READ_FROM;
80 task_runner_->PostTask(FROM_HERE, read_loop_.QuitClosure()); 133 task_runner_->PostTask(FROM_HERE, read_loop_.QuitClosure());
81 } 134 }
82 135
83 // Returns the number of sockets that were accepted by the server. 136 // Returns the number of sockets that were accepted by the server.
84 size_t GetAcceptedSocketCount() const { 137 size_t GetAcceptedSocketCount() const {
85 base::AutoLock lock(lock_); 138 base::AutoLock lock(lock_);
86 return sockets_.size(); 139 return sockets_.size();
87 } 140 }
88 141
89 // Returns the number of sockets that were read from by the server. 142 // Returns the number of sockets that were read from by the server.
90 size_t GetReadSocketCount() const { 143 size_t GetReadSocketCount() const {
91 base::AutoLock lock(lock_); 144 base::AutoLock lock(lock_);
92 size_t read_sockets = 0; 145 size_t read_sockets = 0;
93 for (const auto& socket : sockets_) { 146 for (const auto& socket : sockets_) {
94 if (socket.second == SOCKET_READ_FROM) 147 if (socket.second == SOCKET_READ_FROM)
95 ++read_sockets; 148 ++read_sockets;
96 } 149 }
97 return read_sockets; 150 return read_sockets;
98 } 151 }
99 152
100 void WaitUntilFirstConnectionAccepted() { accept_loop_.Run(); } 153 void WaitUntilFirstConnectionAccepted() { accept_loop_.Run(); }
154 void WaitUntilFirstConnectionRead() { read_loop_.Run(); }
101 155
102 void WaitUntilFirstConnectionRead() { read_loop_.Run(); } 156 // The UI thread will wait for exactly |n| items in |sockets_|. |n| must be
157 // greater than 0.
158 void WaitForAcceptedConnectionsOnUI(size_t num_connections) {
159 DCHECK_CURRENTLY_ON(BrowserThread::UI);
160 DCHECK(!num_accepted_connections_loop_);
161 DCHECK_GT(num_connections, 0u);
162 base::RunLoop run_loop;
163 {
164 base::AutoLock lock(lock_);
165 EXPECT_GE(num_connections, sockets_.size());
166 num_accepted_connections_loop_ = &run_loop;
167 num_accepted_connections_needed_ = num_connections;
168 CheckAccepted();
169 }
170 // Note that the previous call to CheckAccepted can quit this run loop
171 // before this call, which will make this call a no-op.
172 run_loop.Run();
173
174 // Grab the mutex again and make sure that the number of accepted sockets is
175 // indeed |num_connections|.
176 base::AutoLock lock(lock_);
177 EXPECT_EQ(num_connections, sockets_.size());
178 }
179
180 void CheckAcceptedLocked() {
181 base::AutoLock lock(lock_);
182 CheckAccepted();
183 }
184
185 // Helper function to stop the waiting for sockets to be accepted for
186 // WaitForAcceptedConnectionsOnUI. |num_accepted_connections_loop_| spins
187 // until |num_accepted_connections_needed_| sockets are accepted by the test
188 // server. The values will be null/0 if the loop is not running.
189 void CheckAccepted() {
190 lock_.AssertAcquired();
191 // |num_accepted_connections_loop_| null implies
192 // |num_accepted_connections_needed_| == 0.
193 DCHECK(num_accepted_connections_loop_ ||
194 num_accepted_connections_needed_ == 0);
195 if (!num_accepted_connections_loop_ ||
196 num_accepted_connections_needed_ != sockets_.size()) {
197 return;
198 }
199
200 task_runner_->PostTask(FROM_HERE,
201 num_accepted_connections_loop_->QuitClosure());
202 num_accepted_connections_needed_ = 0;
203 num_accepted_connections_loop_ = nullptr;
204 }
205
206 void ResetCounts() {
207 base::AutoLock lock(lock_);
208 sockets_.clear();
209 }
103 210
104 private: 211 private:
105 static uint16_t GetPort(const net::StreamSocket& connection) { 212 static uint16_t GetPort(const net::StreamSocket& connection) {
106 // Get the remote port of the peer, since the local port will always be the 213 // Get the remote port of the peer, since the local port will always be the
107 // port the test server is listening on. This isn't strictly correct - it's 214 // port the test server is listening on. This isn't strictly correct - it's
108 // possible for multiple peers to connect with the same remote port but 215 // possible for multiple peers to connect with the same remote port but
109 // different remote IPs - but the tests here assume that connections to the 216 // different remote IPs - but the tests here assume that connections to the
110 // test server (running on localhost) will always come from localhost, and 217 // test server (running on localhost) will always come from localhost, and
111 // thus the peer port is all thats needed to distinguish two connections. 218 // thus the peer port is all thats needed to distinguish two connections.
112 // This also would be problematic if the OS reused ports, but that's not 219 // This also would be problematic if the OS reused ports, but that's not
113 // something to worry about for these tests. 220 // something to worry about for these tests.
114 net::IPEndPoint address; 221 net::IPEndPoint address;
115 EXPECT_EQ(net::OK, connection.GetPeerAddress(&address)); 222 EXPECT_EQ(net::OK, connection.GetPeerAddress(&address));
116 return address.port(); 223 return address.port();
117 } 224 }
118 225
119 enum SocketStatus { SOCKET_ACCEPTED, SOCKET_READ_FROM }; 226 enum SocketStatus { SOCKET_ACCEPTED, SOCKET_READ_FROM };
120 227
228 base::RunLoop accept_loop_;
229 base::RunLoop read_loop_;
230
231 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
232
233 // This lock protects all the members below, which each are used on both the
234 // IO and UI thread. Members declared after the lock are protected by it.
235 mutable base::Lock lock_;
121 typedef base::hash_map<uint16_t, SocketStatus> SocketContainer; 236 typedef base::hash_map<uint16_t, SocketStatus> SocketContainer;
122 SocketContainer sockets_; 237 SocketContainer sockets_;
123 238
124 base::RunLoop accept_loop_; 239 // If |num_accepted_connections_needed_| is non zero, then the object is
125 base::RunLoop read_loop_; 240 // waiting for |num_accepted_connections_needed_| sockets to be accepted
126 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 241 // before quitting the |num_accepted_connections_loop_|.
127 242 size_t num_accepted_connections_needed_;
128 mutable base::Lock lock_; 243 base::RunLoop* num_accepted_connections_loop_;
129 244
130 DISALLOW_COPY_AND_ASSIGN(ConnectionListener); 245 DISALLOW_COPY_AND_ASSIGN(ConnectionListener);
131 }; 246 };
132 247
133 // Records a history of all hostnames for which resolving has been requested, 248 // Records a history of all hostnames for which resolving has been requested,
134 // and immediately fails the resolution requests themselves. 249 // and immediately fails the resolution requests themselves.
135 class HostResolutionRequestRecorder : public net::HostResolverProc { 250 class HostResolutionRequestRecorder : public net::HostResolverProc {
136 public: 251 public:
137 HostResolutionRequestRecorder() 252 HostResolutionRequestRecorder()
138 : HostResolverProc(NULL), 253 : HostResolverProc(NULL),
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 // requested and thus is running a nested message loop. 310 // requested and thus is running a nested message loop.
196 bool is_waiting_for_hostname_; 311 bool is_waiting_for_hostname_;
197 312
198 // A list of hostnames for which resolution has already been requested. Only 313 // A list of hostnames for which resolution has already been requested. Only
199 // to be accessed from the UI thread. 314 // to be accessed from the UI thread.
200 std::vector<std::string> requested_hostnames_; 315 std::vector<std::string> requested_hostnames_;
201 316
202 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder); 317 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder);
203 }; 318 };
204 319
320 // This class intercepts URLRequests and responds with the URLRequestJob*
321 // callback provided by the constructor. Note that the port of the URL must
322 // match the port given in the constructor.
323 class MatchingPortRequestInterceptor : public net::URLRequestInterceptor {
324 public:
325 typedef base::Callback<net::URLRequestJob*(net::URLRequest*,
326 net::NetworkDelegate*)>
327 CreateJobCallback;
328
329 MatchingPortRequestInterceptor(
330 int port,
331 base::Callback<net::URLRequestJob*(net::URLRequest*,
332 net::NetworkDelegate*)>
333 create_job_callback)
334 : create_job_callback_(create_job_callback), port_(port) {}
335 ~MatchingPortRequestInterceptor() override {}
336
337 private:
338 net::URLRequestJob* MaybeInterceptRequest(
339 net::URLRequest* request,
340 net::NetworkDelegate* network_delegate) const override {
341 if (request->url().EffectiveIntPort() != port_)
342 return nullptr;
343 return create_job_callback_.Run(request, network_delegate);
344 }
345
346 const CreateJobCallback create_job_callback_;
347 const int port_;
348
349 DISALLOW_COPY_AND_ASSIGN(MatchingPortRequestInterceptor);
350 };
351
352 // This class is owned by the test harness, and listens to Predictor events. It
353 // takes as input the source host and cross site host used by the test harness,
354 // and asserts that only valid preconnects and learning can occur between the
355 // two.
356 class CrossSitePredictorObserver
357 : public chrome_browser_net::PredictorObserver {
358 public:
359 CrossSitePredictorObserver(const GURL& source_host,
360 const GURL& cross_site_host)
361 : source_host_(source_host),
362 cross_site_host_(cross_site_host),
363 cross_site_learned_(0),
364 cross_site_preconnected_(0),
365 same_site_preconnected_(0) {}
366
367 void OnPreconnectUrl(
368 const GURL& original_url,
369 const GURL& first_party_for_cookies,
370 chrome_browser_net::UrlInfo::ResolutionMotivation motivation,
371 int count) override {
372 base::AutoLock lock(lock_);
373 if (original_url == cross_site_host_) {
374 cross_site_preconnected_ = std::max(cross_site_preconnected_, count);
375 } else if (original_url == source_host_) {
376 same_site_preconnected_ = std::max(same_site_preconnected_, count);
377 } else {
378 ADD_FAILURE() << "Preconnected " << original_url
379 << " when should only be preconnecting the source host: "
380 << source_host_
381 << " or the cross site host: " << cross_site_host_;
382 }
383 }
384
385 void OnLearnFromNavigation(const GURL& referring_url,
386 const GURL& target_url) override {
387 base::AutoLock lock(lock_);
388 // There are three possibilities:
389 // source => target
390 // source => source
391 // target => target
392 if (referring_url == source_host_ && target_url == cross_site_host_) {
393 cross_site_learned_++;
394 } else if (referring_url == source_host_ && target_url == source_host_) {
395 // Same site learned. Branch retained for clarity.
396 } else if (!(referring_url == cross_site_host_ &&
397 target_url == cross_site_host_)) {
398 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url
399 << " when should only be learning the source host: "
400 << source_host_
401 << " or the cross site host: " << cross_site_host_;
402 }
403 }
404
405 void ResetCounts() {
406 base::AutoLock lock(lock_);
407 cross_site_learned_ = 0;
408 cross_site_preconnected_ = 0;
409 same_site_preconnected_ = 0;
410 }
411
412 int CrossSiteLearned() {
413 base::AutoLock lock(lock_);
414 return cross_site_learned_;
415 }
416
417 int CrossSitePreconnected() {
418 base::AutoLock lock(lock_);
419 return cross_site_preconnected_;
420 }
421
422 int SameSitePreconnected() {
423 base::AutoLock lock(lock_);
424 return same_site_preconnected_;
425 }
426
427 private:
428 const GURL source_host_;
429 const GURL cross_site_host_;
430
431 // Protects all following members. They are read and updated from different
432 // threads.
433 base::Lock lock_;
434
435 int cross_site_learned_;
436 int cross_site_preconnected_;
437 int same_site_preconnected_;
438
439 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver);
440 };
441
205 } // namespace 442 } // namespace
206 443
207 namespace chrome_browser_net { 444 namespace chrome_browser_net {
208 445
209 class PredictorBrowserTest : public InProcessBrowserTest { 446 class PredictorBrowserTest : public InProcessBrowserTest {
210 public: 447 public:
211 PredictorBrowserTest() 448 PredictorBrowserTest()
212 : startup_url_("http://host1:1"), 449 : startup_url_("http://host1:1"),
213 referring_url_("http://host2:1"), 450 referring_url_("http://host2:1"),
214 target_url_("http://host3:1"), 451 target_url_("http://host3:1"),
215 host_resolution_request_recorder_(new HostResolutionRequestRecorder) { 452 host_resolution_request_recorder_(new HostResolutionRequestRecorder),
216 } 453 cross_site_test_server_(new net::EmbeddedTestServer()) {}
217 454
218 protected: 455 protected:
219 void SetUpInProcessBrowserTestFixture() override { 456 void SetUpInProcessBrowserTestFixture() override {
220 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc( 457 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc(
221 host_resolution_request_recorder_.get())); 458 host_resolution_request_recorder_.get()));
222 InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); 459 InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
223 } 460 }
224 461
225 void SetUpCommandLine(base::CommandLine* command_line) override { 462 void SetUpCommandLine(base::CommandLine* command_line) override {
226 command_line->AppendSwitch( 463 command_line->AppendSwitch(
227 switches::kEnableExperimentalWebPlatformFeatures); 464 switches::kEnableExperimentalWebPlatformFeatures);
228 command_line->AppendSwitchASCII( 465 command_line->AppendSwitchASCII(
229 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature); 466 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature);
230 } 467 }
231 468
232 void SetUpOnMainThread() override { 469 void SetUpOnMainThread() override {
470 DCHECK_CURRENTLY_ON(BrowserThread::UI);
471 task_runner_ = base::ThreadTaskRunnerHandle::Get();
472 cross_site_test_server_->ServeFilesFromSourceDirectory("chrome/test/data/");
473
233 connection_listener_.reset(new ConnectionListener()); 474 connection_listener_.reset(new ConnectionListener());
475 cross_site_connection_listener_.reset(new ConnectionListener());
234 embedded_test_server()->SetConnectionListener(connection_listener_.get()); 476 embedded_test_server()->SetConnectionListener(connection_listener_.get());
477 cross_site_test_server_->SetConnectionListener(
478 cross_site_connection_listener_.get());
235 ASSERT_TRUE(embedded_test_server()->Start()); 479 ASSERT_TRUE(embedded_test_server()->Start());
480 ASSERT_TRUE(cross_site_test_server_->Start());
481
482 embedded_test_server()->RegisterRequestHandler(
483 base::Bind(&RedirectForPathHandler, "/",
484 cross_site_test_server()->GetURL("/title1.html")));
485
486 predictor()->SetPreconnectEnabledForTest(true);
487 InstallPredictorObserver(embedded_test_server()->base_url(),
488 cross_site_test_server()->base_url());
489 StartInterceptingCrossSiteOnUI();
490 }
491
492 // Intercepts all requests to the specified host and returns a response with
493 // an empty body. Needed to prevent requests from actually going to the test
494 // server, to avoid any races related to socket accounting. Note, the
495 // interceptor also looks at the port, to differentiate between the
496 // two test servers.
497 static void StartInterceptingHost(const GURL& url) {
498 DCHECK_CURRENTLY_ON(BrowserThread::IO);
499 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
500 url.scheme(), url.host(),
501 base::WrapUnique(new MatchingPortRequestInterceptor(
502 url.EffectiveIntPort(), base::Bind(&CreateEmptyBodyRequestJob))));
503 }
504
505 static void StopInterceptingHost(const GURL& url) {
506 DCHECK_CURRENTLY_ON(BrowserThread::IO);
507 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(),
508 url.host());
509 }
510
511 void StartInterceptingCrossSiteOnUI() {
512 DCHECK_CURRENTLY_ON(BrowserThread::UI);
513 content::BrowserThread::PostTask(
514 content::BrowserThread::IO, FROM_HERE,
515 base::Bind(&PredictorBrowserTest::StartInterceptingHost,
516 cross_site_test_server()->base_url()));
517 }
518
519 void StopInterceptingCrossSiteOnUI() {
520 DCHECK_CURRENTLY_ON(BrowserThread::UI);
521 content::BrowserThread::PostTask(
522 content::BrowserThread::IO, FROM_HERE,
523 base::Bind(&PredictorBrowserTest::StopInterceptingHost,
524 cross_site_test_server()->base_url()));
236 } 525 }
237 526
238 void TearDownOnMainThread() override { 527 void TearDownOnMainThread() override {
528 DCHECK_CURRENTLY_ON(BrowserThread::UI);
239 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); 529 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
240 } 530 }
241 531
242 // Navigates to a data URL containing the given content, with a MIME type of 532 // Navigates to a data URL containing the given content, with a MIME type of
243 // text/html. 533 // text/html.
244 void NavigateToDataURLWithContent(const std::string& content) { 534 void NavigateToDataURLWithContent(const std::string& content) {
535 DCHECK_CURRENTLY_ON(BrowserThread::UI);
245 std::string encoded_content; 536 std::string encoded_content;
246 base::Base64Encode(content, &encoded_content); 537 base::Base64Encode(content, &encoded_content);
247 std::string data_uri_content = "data:text/html;base64," + encoded_content; 538 std::string data_uri_content = "data:text/html;base64," + encoded_content;
248 ui_test_utils::NavigateToURL(browser(), GURL(data_uri_content)); 539 ui_test_utils::NavigateToURL(browser(), GURL(data_uri_content));
249 } 540 }
250 541
251 void TearDownInProcessBrowserTestFixture() override { 542 void TearDownInProcessBrowserTestFixture() override {
252 InProcessBrowserTest::TearDownInProcessBrowserTestFixture(); 543 InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
253 scoped_host_resolver_proc_.reset(); 544 scoped_host_resolver_proc_.reset();
254 } 545 }
255 546
256 void LearnAboutInitialNavigation(const GURL& url) { 547 void LearnAboutInitialNavigation(const GURL& url) {
257 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 548 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
258 BrowserThread::PostTask(BrowserThread::IO,
259 FROM_HERE,
260 base::Bind(&Predictor::LearnAboutInitialNavigation, 549 base::Bind(&Predictor::LearnAboutInitialNavigation,
261 base::Unretained(predictor), 550 base::Unretained(predictor()), url));
262 url));
263 content::RunAllPendingInMessageLoop(BrowserThread::IO); 551 content::RunAllPendingInMessageLoop(BrowserThread::IO);
264 } 552 }
265 553
266 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) { 554 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
267 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 555 BrowserThread::PostTask(
268 BrowserThread::PostTask(BrowserThread::IO, 556 BrowserThread::IO, FROM_HERE,
269 FROM_HERE, 557 base::Bind(&Predictor::LearnFromNavigation,
270 base::Bind(&Predictor::LearnFromNavigation, 558 base::Unretained(predictor()), referring_url, target_url));
271 base::Unretained(predictor),
272 referring_url,
273 target_url));
274 content::RunAllPendingInMessageLoop(BrowserThread::IO); 559 content::RunAllPendingInMessageLoop(BrowserThread::IO);
275 } 560 }
276 561
277 void PrepareFrameSubresources(const GURL& url) { 562 void PrepareFrameSubresources(const GURL& url) {
278 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 563 predictor()->PredictFrameSubresources(url, GURL());
279 predictor->PredictFrameSubresources(url, GURL());
280 } 564 }
281 565
282 void GetListFromPrefsAsString(const char* list_path, 566 void GetListFromPrefsAsString(const char* list_path,
283 std::string* value_as_string) const { 567 std::string* value_as_string) const {
284 PrefService* prefs = browser()->profile()->GetPrefs(); 568 PrefService* prefs = browser()->profile()->GetPrefs();
285 const base::ListValue* list_value = prefs->GetList(list_path); 569 const base::ListValue* list_value = prefs->GetList(list_path);
286 JSONStringValueSerializer serializer(value_as_string); 570 JSONStringValueSerializer serializer(value_as_string);
287 serializer.Serialize(*list_value); 571 serializer.Serialize(*list_value);
288 } 572 }
289 573
290 bool HasHostBeenRequested(const std::string& hostname) const { 574 bool HasHostBeenRequested(const std::string& hostname) const {
291 return host_resolution_request_recorder_->HasHostBeenRequested(hostname); 575 return host_resolution_request_recorder_->HasHostBeenRequested(hostname);
292 } 576 }
293 577
294 void WaitUntilHostHasBeenRequested(const std::string& hostname) { 578 void WaitUntilHostHasBeenRequested(const std::string& hostname) {
295 host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname); 579 host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname);
296 } 580 }
297 581
298 int RequestedHostnameCount() const { 582 int RequestedHostnameCount() const {
299 return host_resolution_request_recorder_->RequestedHostnameCount(); 583 return host_resolution_request_recorder_->RequestedHostnameCount();
300 } 584 }
301 585
586 net::EmbeddedTestServer* cross_site_test_server() {
587 return cross_site_test_server_.get();
588 }
589
590 Predictor* predictor() { return browser()->profile()->GetNetworkPredictor(); }
591
592 void InstallPredictorObserver(const GURL& source_host,
593 const GURL& cross_site_host) {
594 DCHECK_CURRENTLY_ON(BrowserThread::UI);
595 observer_.reset(
596 new CrossSitePredictorObserver(source_host, cross_site_host));
597 BrowserThread::PostTask(
598 BrowserThread::IO, FROM_HERE,
599 base::Bind(&PredictorBrowserTest::InstallPredictorObserverOnIOThread,
600 base::Unretained(this), base::Unretained(predictor())));
601 }
602
603 void InstallPredictorObserverOnIOThread(
604 chrome_browser_net::Predictor* predictor) {
605 DCHECK_CURRENTLY_ON(BrowserThread::IO);
606 predictor->SetObserver(observer_.get());
607 }
608
609 // Note: For many of the tests to get to a "clean slate" mid run, they must
610 // flush sockets on both the client and server.
611 void FlushClientSockets() {
612 DCHECK_CURRENTLY_ON(BrowserThread::IO);
613 predictor()
614 ->url_request_context_getter_for_test()
615 ->GetURLRequestContext()
616 ->http_transaction_factory()
617 ->GetSession()
618 ->CloseAllConnections();
619 }
620
621 void FlushClientSocketsOnUIThread() {
622 DCHECK_CURRENTLY_ON(BrowserThread::UI);
623 base::RunLoop run_loop;
624 BrowserThread::PostTaskAndReply(
625 BrowserThread::IO, FROM_HERE,
626 base::Bind(&PredictorBrowserTest::FlushClientSockets,
627 base::Unretained(this)),
628 run_loop.QuitClosure());
629 run_loop.Run();
630 }
631
632 void FlushServerSocketsOnUIThread(net::EmbeddedTestServer* test_server) {
633 DCHECK_CURRENTLY_ON(BrowserThread::UI);
634 EXPECT_TRUE(test_server->FlushAllSocketsAndConnectionsOnUIThread());
635 }
636
637 CrossSitePredictorObserver* observer() { return observer_.get(); }
638
639 // Navigate to an html file on embedded_test_server and tell it to request
640 // |num_cors| resources from the cross_site_test_server. It then waits for
641 // those requests to complete. Note that "cors" here means using cors-mode in
642 // correspondence with the fetch spec.
643 void NavigateToCrossSiteHtmlUrl(int num_cors, const char* file_suffix) {
644 DCHECK_CURRENTLY_ON(BrowserThread::UI);
645 const GURL& base_url = cross_site_test_server()->base_url();
646 std::string path = base::StringPrintf(
647 "/predictor/"
648 "predictor_cross_site%s.html?subresourceHost=%s&"
649 "numCORSResources=%d",
650 file_suffix, base_url.spec().c_str(), num_cors);
651 ui_test_utils::NavigateToURL(browser(),
652 embedded_test_server()->GetURL(path));
653 bool result = false;
654 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
655 browser()->tab_strip_model()->GetActiveWebContents(),
656 "startFetchesAndWaitForReply()", &result));
657 EXPECT_TRUE(result);
658 }
659
302 const GURL startup_url_; 660 const GURL startup_url_;
303 const GURL referring_url_; 661 const GURL referring_url_;
304 const GURL target_url_; 662 const GURL target_url_;
305 std::unique_ptr<ConnectionListener> connection_listener_; 663 std::unique_ptr<ConnectionListener> connection_listener_;
664 std::unique_ptr<ConnectionListener> cross_site_connection_listener_;
306 665
307 private: 666 private:
308 scoped_refptr<HostResolutionRequestRecorder> 667 scoped_refptr<HostResolutionRequestRecorder>
309 host_resolution_request_recorder_; 668 host_resolution_request_recorder_;
310 std::unique_ptr<net::ScopedDefaultHostResolverProc> 669 std::unique_ptr<net::ScopedDefaultHostResolverProc>
311 scoped_host_resolver_proc_; 670 scoped_host_resolver_proc_;
671 std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_;
672 std::unique_ptr<CrossSitePredictorObserver> observer_;
673 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
312 }; 674 };
313 675
314 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PRE_ShutdownStartupCycle) { 676 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectOne) {
677 predictor()->PreconnectUrl(
678 embedded_test_server()->base_url(), GURL(),
679 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
680 false /* allow credentials */, 1);
681 connection_listener_->WaitForAcceptedConnectionsOnUI(1u);
682 }
683
684 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectTwo) {
685 predictor()->PreconnectUrl(
686 embedded_test_server()->base_url(), GURL(),
687 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
688 false /* allow credentials */, 2);
689 connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
690 }
691
692 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectFour) {
693 predictor()->PreconnectUrl(
694 embedded_test_server()->base_url(), GURL(),
695 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
696 false /* allow credentials */, 4);
697 connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
698 }
699
700 // Test the html test harness used to initiate cross site fetches. These
701 // initiate cross site subresource requests to the cross site test server.
702 // Inspect the predictor's internal state to make sure that they are properly
703 // logged.
704 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteUseOneSocket) {
705 StopInterceptingCrossSiteOnUI();
706 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
707 EXPECT_EQ(1u, cross_site_connection_listener_->GetAcceptedSocketCount());
708 EXPECT_EQ(1, observer()->CrossSiteLearned());
709 EXPECT_EQ(2, observer()->SameSitePreconnected());
710 }
711
712 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteUseThreeSockets) {
713 StopInterceptingCrossSiteOnUI();
714 NavigateToCrossSiteHtmlUrl(3 /* num_cors */, "" /* file_suffix */);
715 EXPECT_EQ(3u, cross_site_connection_listener_->GetAcceptedSocketCount());
716 EXPECT_EQ(3, observer()->CrossSiteLearned());
717 EXPECT_EQ(2, observer()->SameSitePreconnected());
718 }
719
720 // The following tests confirm that Chrome accurately predicts preconnects after
721 // learning from navigations. Note that every "learned" connection adds ~.33 to
722 // the expected connection number, which starts at 2. Every preconnect Chrome
723 // performs multiplies the expected connections by .66.
724 //
725 // In order to simplify things, many of the following tests intercept requests
726 // to the cross site test server. This allows the test server to maintain a
727 // "clean slate" with no connected sockets, so that when the tests need to check
728 // that predictor initiated preconnects occur, there are no races and the
729 // connections are deterministic.
730 //
731 // One additional complexity is that if a preconnect from A to B is learned, an
732 // extra preconnect will be issued if the host part of A and B match (ignoring
733 // port). TODO(csharrison): This logic could probably be removed from the
734 // predictor.
735 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
736 CrossSiteSimplePredictionAfterOneNavigation) {
737 NavigateToCrossSiteHtmlUrl(2 /* num_cors */, "" /* file_suffix */);
738 EXPECT_EQ(2, observer()->CrossSiteLearned());
739
740 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
741
742 // Navigate again and confirm a preconnect. Note that because the two
743 // embedded test servers have the same host name, an extra preconnect is
744 // issued. This results in ceil(2.66) + 1 = 4 preconnects.
745 ui_test_utils::NavigateToURL(browser(),
746 embedded_test_server()->GetURL("/title1.html"));
747 EXPECT_EQ(4, observer()->CrossSitePreconnected());
748 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
749 }
750
751 // This test does not intercept initial requests / preconnects to the cross site
752 // test server. This is a sanity check to make sure that the interceptor doesn't
753 // change the logic in the predictor. Note that the test does not have the
754 // ability to inspect at the socket layer, but verifies that the predictor is at
755 // least making preconnect requests.
756 IN_PROC_BROWSER_TEST_F(
757 PredictorBrowserTest,
758 CrossSiteSimplePredictionAfterOneNavigationNoInterceptor) {
759 StopInterceptingCrossSiteOnUI();
760 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
761 EXPECT_EQ(1, observer()->CrossSiteLearned());
762 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(1u);
763
764 // Navigate again and confirm a preconnect. Note that because the two
765 // embedded test servers have the same host_piece, an extra preconnect is
766 // issued. This results in ceil(2.33) + 1 = 4 preconnects.
767 ui_test_utils::NavigateToURL(browser(),
768 embedded_test_server()->GetURL("/title1.html"));
769 // Just check that predictor has initiated preconnects to the cross site test
770 // server. It's tricky to reset the connections to the test server, and
771 // sockets can be reused.
772 EXPECT_EQ(4, observer()->CrossSitePreconnected());
773 }
774
775 // Expect that the predictor correctly predicts subframe navigations.
776 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeCrossSitePrediction) {
777 ui_test_utils::NavigateToURL(
778 browser(), embedded_test_server()->GetURL(
779 "/predictor/predictor_cross_site_subframe_nav.html"));
780 bool result = false;
781 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
782 browser()->tab_strip_model()->GetActiveWebContents(),
783 base::StringPrintf(
784 "navigateSubframe('%s')",
785 cross_site_test_server()->GetURL("/title1.html").spec().c_str()),
786 &result));
787 EXPECT_TRUE(result);
788 EXPECT_EQ(1, observer()->CrossSiteLearned());
789
790 // The subframe navigation initiates two preconnects.
791 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
792
793 FlushClientSocketsOnUIThread();
794 FlushServerSocketsOnUIThread(cross_site_test_server());
795 cross_site_connection_listener_->ResetCounts();
796
797 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
798
799 // Navigate again and confirm a preconnect. Note that because the two
800 // embedded test servers have the same host_piece, an extra preconnect is
801 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
802 ui_test_utils::NavigateToURL(browser(),
803 embedded_test_server()->GetURL("/title1.html"));
804 EXPECT_EQ(4, observer()->CrossSitePreconnected());
805 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
806 }
807
808 // Expect that the predictor correctly preconnects an already learned resource
809 // if the host shows up in a subframe. This test is equivalent to
810 // CrossSiteSimplePredictionAfterOneNavigation, with the second navigation
811 // (which initiates the preconnect) happening for a subframe load.
812 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeInitiatesPreconnects) {
813 // Navigate to the normal cross site URL to learn the relationship.
814 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
815 EXPECT_EQ(1, observer()->CrossSiteLearned());
816
817 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
818
819 // Navigate again and confirm a preconnect. Note that because the two
820 // embedded test servers have the same host_piece, an extra preconnect is
821 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
822 NavigateToDataURLWithContent(
823 "<iframe src=\"" + embedded_test_server()->GetURL("/title1.html").spec() +
824 "\"></iframe>");
825 EXPECT_EQ(4, observer()->CrossSitePreconnected());
826 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
827 }
828
829 // Expect that the predictor correctly learns the subresources a subframe needs
830 // to preconnect to.
831 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeLearning) {
832 std::string path = base::StringPrintf(
833 "/predictor/"
834 "predictor_cross_site.html?subresourceHost=%s&"
835 "numCORSResources=1&sendImmediately=1",
836 cross_site_test_server()->base_url().spec().c_str());
837 NavigateToDataURLWithContent(
838 base::StringPrintf("<iframe src=\"%s\"></iframe>",
839 embedded_test_server()->GetURL(path).spec().c_str()));
840 EXPECT_EQ(1, observer()->CrossSiteLearned());
841
842 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
843
844 // Navigate again and confirm a preconnect. Note that because the two
845 // embedded test servers have the same host_piece, an extra preconnect is
846 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
847 NavigateToDataURLWithContent(
848 "<iframe src=\"" + embedded_test_server()->GetURL("/title1.html").spec() +
849 "\"></iframe>");
850 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
851 EXPECT_EQ(4u, cross_site_connection_listener_->GetAcceptedSocketCount());
852 EXPECT_EQ(4, observer()->CrossSitePreconnected());
853 }
854
855 // This test navigates to an html file with a tag:
856 // <meta name="referrer" content="never">. This tests the implementation details
857 // of the predictor. The current predictor only learns via the referrer header.
858 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
859 CrossSiteNoReferrerNoPredictionAfterOneNavigation) {
860 NavigateToCrossSiteHtmlUrl(2 /* num_cors */,
861 "_no_referrer" /* file_suffix */);
862 EXPECT_EQ(0, observer()->CrossSiteLearned());
863 EXPECT_EQ(2, observer()->SameSitePreconnected());
864
865 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
866
867 // Navigate again and confirm that no preconnects occurred.
868 ui_test_utils::NavigateToURL(browser(),
869 embedded_test_server()->GetURL("/title1.html"));
870 EXPECT_EQ(0, observer()->CrossSitePreconnected());
871 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
872 }
873
874 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
875 CrossSiteSimplePredictionAfterTwoNavigations) {
876 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
877 EXPECT_EQ(0, observer()->CrossSitePreconnected());
878
879 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
880 EXPECT_EQ(4, observer()->CrossSitePreconnected());
881 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
882
883 FlushClientSocketsOnUIThread();
884 FlushServerSocketsOnUIThread(cross_site_test_server());
885 cross_site_connection_listener_->ResetCounts();
886 observer()->ResetCounts();
887
888 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
889
890 // Navigate again and confirm a preconnect. Note that because the two
891 // embedded test servers have the same host_piece, an extra preconnect is
892 // issued. This results in ceil(((2 + .33) + .33)*.66) + 1 = 3 preconnects.
893 ui_test_utils::NavigateToURL(browser(),
894 embedded_test_server()->GetURL("/title1.html"));
895 EXPECT_EQ(3, observer()->CrossSitePreconnected());
896 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(3u);
897 }
898
899 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
900 CrossSiteSimplePredictionAfterTwoNavigations2) {
901 NavigateToCrossSiteHtmlUrl(2 /* num_cors */, "" /* file_suffix */);
902 EXPECT_EQ(0, observer()->CrossSitePreconnected());
903
904 NavigateToCrossSiteHtmlUrl(2 /* num_cors */, "" /* file_suffix */);
905
906 EXPECT_EQ(4, observer()->CrossSitePreconnected());
907 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
908
909 FlushClientSocketsOnUIThread();
910 FlushServerSocketsOnUIThread(cross_site_test_server());
911 cross_site_connection_listener_->ResetCounts();
912 observer()->ResetCounts();
913
914 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
915
916 // ((2 + .66) + .66)*.66 + 1 ~= 3.2.
917 ui_test_utils::NavigateToURL(browser(),
918 embedded_test_server()->GetURL("/title1.html"));
919 EXPECT_EQ(4, observer()->CrossSitePreconnected());
920 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
921 }
922
923 // The first navigation uses a subresource. Subsequent navigations don't use
924 // that subresource. This tests how the predictor forgets about these bad
925 // navigations.
926 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ForgetBadPrediction) {
927 NavigateToCrossSiteHtmlUrl(1 /* num_cors */, "" /* file_suffix */);
928 EXPECT_EQ(1, observer()->CrossSiteLearned());
929
930 ui_test_utils::NavigateToURL(browser(),
931 embedded_test_server()->GetURL("/title1.html"));
932 // (2 + .33) + 1 = 3.33.
933 EXPECT_EQ(4, observer()->CrossSitePreconnected());
934 observer()->ResetCounts();
935 ui_test_utils::NavigateToURL(browser(),
936 embedded_test_server()->GetURL("/title1.html"));
937 // ceil((2 + .33) * .66) + 1 = 3.
938 EXPECT_EQ(3, observer()->CrossSitePreconnected());
939 observer()->ResetCounts();
940 ui_test_utils::NavigateToURL(browser(),
941 embedded_test_server()->GetURL("/title1.html"));
942 // ceil((2 + .33) * .66 * .66) + 1 = 3.
943 EXPECT_EQ(3, observer()->CrossSitePreconnected());
944 observer()->ResetCounts();
945
946 ui_test_utils::NavigateToURL(browser(),
947 embedded_test_server()->GetURL("/title1.html"));
948 // Finally, (2 + .33) * .66^3 ~= .67. Not enough for a preconnect.
949 EXPECT_EQ(0, observer()->CrossSitePreconnected());
950 }
951
952 // The predictor does not follow redirects if the original url had a non-empty
953 // path (a path that was more than just "/").
954 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
955 CrossSiteRedirectNoPredictionWithPath) {
956 ui_test_utils::NavigateToURL(
957 browser(),
958 embedded_test_server()->GetURL(base::StringPrintf(
959 "/server-redirect?%s",
960 cross_site_test_server()->GetURL("/title1.html").spec().c_str())));
961 EXPECT_EQ(0, observer()->CrossSiteLearned());
962
963 EXPECT_EQ(2, observer()->CrossSitePreconnected());
964 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
965
966 FlushClientSocketsOnUIThread();
967 FlushServerSocketsOnUIThread(cross_site_test_server());
968 cross_site_connection_listener_->ResetCounts();
969 observer()->ResetCounts();
970
971 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
972
973 ui_test_utils::NavigateToURL(browser(),
974 embedded_test_server()->GetURL("/title1.html"));
975 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
976 EXPECT_EQ(0, observer()->CrossSitePreconnected());
977 }
978
979 // The predictor does follow redirects if the original url had an empty path
980 // (a path that was more than just "/"). Use the registered "/" path to redirect
981 // to the target test server.
982 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
983 CrossSiteRedirectPredictionWithNoPath) {
984 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
985 EXPECT_EQ(1, observer()->CrossSiteLearned());
986
987 EXPECT_EQ(2, observer()->CrossSitePreconnected());
988 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
989
990 FlushClientSocketsOnUIThread();
991 FlushServerSocketsOnUIThread(cross_site_test_server());
992 cross_site_connection_listener_->ResetCounts();
993 observer()->ResetCounts();
994
995 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
996
997 ui_test_utils::NavigateToURL(browser(),
998 embedded_test_server()->GetURL("/title1.html"));
999 // Preconnect 4 sockets because ceil(2 + .33) + 1 = 4.
1000 EXPECT_EQ(4, observer()->CrossSitePreconnected());
1001 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
1002 }
1003
1004 // This test uses "localhost" instead of "127.0.0.1" to avoid extra preconnects
1005 // to hosts with the same host piece (ignoring port). Note that the preconnect
1006 // observer is not used here due to its strict checks on hostname.
1007 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
1008 CrossSiteRedirectPredictionWithNoPathDifferentHostName) {
1009 std::string same_site_localhost_host = base::StringPrintf(
1010 "%s://localhost:%s", embedded_test_server()->base_url().scheme().c_str(),
1011 embedded_test_server()->base_url().port().c_str());
1012 // The default predictor observer does not use "localhost".
1013 InstallPredictorObserver(GURL(same_site_localhost_host),
1014 cross_site_test_server()->base_url());
1015 GURL localhost_source = GURL(base::StringPrintf(
1016 "%s/predictor/"
1017 "predictor_cross_site.html?subresourceHost=%s&numCORSResources=1",
1018 same_site_localhost_host.c_str(),
1019 cross_site_test_server()->base_url().spec().c_str()));
1020 ui_test_utils::NavigateToURL(browser(), localhost_source);
1021 bool result = false;
1022 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
1023 browser()->tab_strip_model()->GetActiveWebContents(),
1024 "startFetchesAndWaitForReply()", &result));
1025 EXPECT_TRUE(result);
1026
1027 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
1028
1029 ui_test_utils::NavigateToURL(
1030 browser(), GURL(base::StringPrintf("%s/title1.html",
1031 same_site_localhost_host.c_str())));
1032 // Preconnect 3 sockets because ceil(2 + .33) = 3. Note that this time there
1033 // is no additional connection due to same host.
1034 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(3u);
1035 }
1036
1037 // Perform the "/" redirect twice and make sure the predictor updates twice.
1038 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
1039 CrossSiteTwoRedirectsPredictionWithNoPath) {
1040 // Navigate once and redirect.
1041 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
1042 EXPECT_EQ(1, observer()->CrossSiteLearned());
1043
1044 EXPECT_EQ(2, observer()->CrossSitePreconnected());
1045 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
1046
1047 FlushClientSocketsOnUIThread();
1048 FlushServerSocketsOnUIThread(cross_site_test_server());
1049 cross_site_connection_listener_->ResetCounts();
1050 observer()->ResetCounts();
1051
1052 // Navigate again and redirect.
1053 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
1054 EXPECT_EQ(1, observer()->CrossSiteLearned());
1055
1056 // 2 + .33 + 1 = 3.33.
1057 EXPECT_EQ(4, observer()->CrossSitePreconnected());
1058 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
1059
1060 FlushClientSocketsOnUIThread();
1061 FlushServerSocketsOnUIThread(cross_site_test_server());
1062 cross_site_connection_listener_->ResetCounts();
1063 observer()->ResetCounts();
1064
1065 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
1066
1067 ui_test_utils::NavigateToURL(browser(),
1068 embedded_test_server()->GetURL("/title1.html"));
1069 // 3 preconnects expected because ((2 + .33)*.66 + .33)*.66 + 1 = 2.23.
1070 EXPECT_EQ(3, observer()->CrossSitePreconnected());
1071 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(3u);
1072 }
1073
1074 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
1075 PRE_ShutdownStartupCyclePreresolve) {
315 // Prepare state that will be serialized on this shut-down and read on next 1076 // Prepare state that will be serialized on this shut-down and read on next
316 // start-up. 1077 // start-up. Ensure preresolution over preconnection.
317 LearnAboutInitialNavigation(startup_url_); 1078 LearnAboutInitialNavigation(startup_url_);
1079 // The target url will have a expected connection count of 2 after this call.
1080 InstallPredictorObserver(referring_url_, target_url_);
318 LearnFromNavigation(referring_url_, target_url_); 1081 LearnFromNavigation(referring_url_, target_url_);
319 } 1082
320 1083 // In order to reduce the expected connection count < .8, issue predictions 3
321 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCycle) { 1084 // times. 2 * .66^3 ~= .58.
1085 PrepareFrameSubresources(referring_url_);
1086 PrepareFrameSubresources(referring_url_);
1087 PrepareFrameSubresources(referring_url_);
1088 }
1089
1090 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCyclePreresolve) {
322 // Make sure that the Preferences file is actually wiped of all DNS prefetch 1091 // Make sure that the Preferences file is actually wiped of all DNS prefetch
323 // related data after start-up. 1092 // related data after start-up.
324 std::string cleared_startup_list; 1093 std::string cleared_startup_list;
325 std::string cleared_referral_list; 1094 std::string cleared_referral_list;
326 GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList, 1095 GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList,
327 &cleared_startup_list); 1096 &cleared_startup_list);
328 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList, 1097 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList,
329 &cleared_referral_list); 1098 &cleared_referral_list);
330 1099
331 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host()))); 1100 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host())));
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 // Second navigation to content with an img. 1225 // Second navigation to content with an img.
457 std::string img_content = 1226 std::string img_content =
458 "<img src=\"" + preconnect_url.spec() + "test.gif\">"; 1227 "<img src=\"" + preconnect_url.spec() + "test.gif\">";
459 NavigateToDataURLWithContent(img_content); 1228 NavigateToDataURLWithContent(img_content);
460 connection_listener_->WaitUntilFirstConnectionRead(); 1229 connection_listener_->WaitUntilFirstConnectionRead();
461 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount()); 1230 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount());
462 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount()); 1231 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount());
463 } 1232 }
464 1233
465 } // namespace chrome_browser_net 1234 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/test/data/predictor/empty.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698