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

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

Powered by Google App Engine
This is Rietveld 408576698