blob: a6c2d1abb0ffdce02d276bf2b1680dbfb8f892a4 [file] [log] [blame]
xunjieli100937eb52016-09-15 20:09:371// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <memory>
6
7#include "base/files/file_path.h"
8#include "base/macros.h"
9#include "base/memory/ptr_util.h"
10#include "base/run_loop.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/stringprintf.h"
13#include "net/base/load_timing_info.h"
14#include "net/base/network_delegate.h"
15#include "net/cert/mock_cert_verifier.h"
16#include "net/dns/mapped_host_resolver.h"
17#include "net/dns/mock_host_resolver.h"
zhongyid7dd2db12017-04-14 17:01:2518#include "net/log/net_log_event_type.h"
19#include "net/log/test_net_log.h"
20#include "net/log/test_net_log_entry.h"
xunjieli100937eb52016-09-15 20:09:3721#include "net/quic/chromium/crypto/proof_source_chromium.h"
22#include "net/quic/test_tools/crypto_test_utils.h"
23#include "net/test/cert_test_util.h"
24#include "net/test/gtest_util.h"
25#include "net/test/test_data_directory.h"
zhongyid7dd2db12017-04-14 17:01:2526#include "net/tools/quic/quic_dispatcher.h"
vasilvv28270e8f2016-12-01 21:38:0927#include "net/tools/quic/quic_http_response_cache.h"
zhongyid7dd2db12017-04-14 17:01:2528#include "net/tools/quic/quic_simple_dispatcher.h"
xunjieli100937eb52016-09-15 20:09:3729#include "net/tools/quic/quic_simple_server.h"
rhalavatib7bd7c792017-04-27 05:25:1630#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
xunjieli100937eb52016-09-15 20:09:3731#include "net/url_request/url_request.h"
32#include "net/url_request/url_request_test_util.h"
33#include "testing/gmock/include/gmock/gmock.h"
34#include "testing/gtest/include/gtest/gtest.h"
35#include "url/gurl.h"
36
37namespace net {
38
39namespace {
40
41// This must match the certificate used (quic_test.example.com.crt and
42// quic_test.example.com.key.pkcs8).
43const int kTestServerPort = 6121;
zhongyi6f20e71d2017-02-14 23:20:3944const char kTestServerHost[] = "test.example.com";
xunjieli100937eb52016-09-15 20:09:3745// Used as a simple response from the server.
46const char kHelloPath[] = "/hello.txt";
47const char kHelloBodyValue[] = "Hello from QUIC Server";
48const int kHelloStatus = 200;
49
50class URLRequestQuicTest : public ::testing::Test {
51 protected:
52 URLRequestQuicTest() : context_(new TestURLRequestContext(true)) {
53 StartQuicServer();
54
55 std::unique_ptr<HttpNetworkSession::Params> params(
56 new HttpNetworkSession::Params);
57 CertVerifyResult verify_result;
58 verify_result.verified_cert = ImportCertFromFile(
59 GetTestCertsDirectory(), "quic_test.example.com.crt");
60 cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
61 "test.example.com", verify_result,
62 OK);
63 verify_result.verified_cert = ImportCertFromFile(
64 GetTestCertsDirectory(), "quic_test_ecc.example.com.crt");
65 cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
66 "test.example.com", verify_result,
67 OK);
68 // To simplify the test, and avoid the race with the HTTP request, we force
69 // QUIC for these requests.
zhongyi6f20e71d2017-02-14 23:20:3970 params->origins_to_force_quic_on.insert(HostPortPair(kTestServerHost, 443));
xunjieli100937eb52016-09-15 20:09:3771 params->enable_quic = true;
zhongyid7dd2db12017-04-14 17:01:2572 params->enable_server_push_cancellation = true;
zhongyi6f20e71d2017-02-14 23:20:3973 context_->set_host_resolver(host_resolver_.get());
xunjieli100937eb52016-09-15 20:09:3774 context_->set_http_network_session_params(std::move(params));
75 context_->set_cert_verifier(&cert_verifier_);
zhongyid7dd2db12017-04-14 17:01:2576 context_->set_net_log(&net_log_);
xunjieli100937eb52016-09-15 20:09:3777 }
78
79 void TearDown() override {
zhongyid7dd2db12017-04-14 17:01:2580 if (server_) {
xunjieli100937eb52016-09-15 20:09:3781 server_->Shutdown();
zhongyid7dd2db12017-04-14 17:01:2582 // If possible, deliver the conncetion close packet to the client before
83 // destruct the TestURLRequestContext.
84 base::RunLoop().RunUntilIdle();
85 }
xunjieli100937eb52016-09-15 20:09:3786 }
87
88 // Sets a NetworkDelegate to use for |context_|. Must be done before Init().
89 void SetNetworkDelegate(NetworkDelegate* network_delegate) {
90 context_->set_network_delegate(network_delegate);
91 }
92
93 // Initializes the TestURLRequestContext |context_|.
94 void Init() { context_->Init(); }
95
96 std::unique_ptr<URLRequest> CreateRequest(const GURL& url,
97 RequestPriority priority,
98 URLRequest::Delegate* delegate) {
rhalavatib7bd7c792017-04-27 05:25:1699 return context_->CreateRequest(url, priority, delegate,
100 TRAFFIC_ANNOTATION_FOR_TESTS);
xunjieli100937eb52016-09-15 20:09:37101 }
102
zhongyid7dd2db12017-04-14 17:01:25103 void ExtractNetLog(NetLogEventType type,
104 TestNetLogEntry::List* entry_list) const {
105 net::TestNetLogEntry::List entries;
106 net_log_.GetEntries(&entries);
107
108 for (const auto& entry : entries) {
109 if (entry.type == type)
110 entry_list->push_back(entry);
111 }
112 }
113
114 unsigned int GetRstErrorCountReceivedByServer(
115 QuicRstStreamErrorCode error_code) const {
116 return (static_cast<QuicSimpleDispatcher*>(server_->dispatcher()))
117 ->GetRstErrorCount(error_code);
118 }
119
xunjieli100937eb52016-09-15 20:09:37120 private:
121 void StartQuicServer() {
122 // Set up in-memory cache.
vasilvv28270e8f2016-12-01 21:38:09123 response_cache_.AddSimpleResponse(kTestServerHost, kHelloPath, kHelloStatus,
124 kHelloBodyValue);
zhongyid7dd2db12017-04-14 17:01:25125 response_cache_.InitializeFromDirectory(ServerPushCacheDirectory());
xunjieli100937eb52016-09-15 20:09:37126 net::QuicConfig config;
127 // Set up server certs.
128 std::unique_ptr<net::ProofSourceChromium> proof_source(
129 new net::ProofSourceChromium());
130 base::FilePath directory = GetTestCertsDirectory();
131 CHECK(proof_source->Initialize(
132 directory.Append(FILE_PATH_LITERAL("quic_test.example.com.crt")),
133 directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.pkcs8")),
134 directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.sct"))));
135 server_.reset(new QuicSimpleServer(
fayangf5f4cd512017-02-07 16:57:11136 test::crypto_test_utils::ProofSourceForTesting(), config,
vasilvv479f0322016-11-29 16:06:48137 net::QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions(),
vasilvv28270e8f2016-12-01 21:38:09138 &response_cache_));
xunjieli100937eb52016-09-15 20:09:37139 int rv = server_->Listen(
140 net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kTestServerPort));
141 EXPECT_GE(rv, 0) << "Quic server fails to start";
142
143 std::unique_ptr<MockHostResolver> resolver(new MockHostResolver());
144 resolver->rules()->AddRule("test.example.com", "127.0.0.1");
145 host_resolver_.reset(new MappedHostResolver(std::move(resolver)));
zhongyi6f20e71d2017-02-14 23:20:39146 // Use a mapped host resolver so that request for test.example.com
xunjieli100937eb52016-09-15 20:09:37147 // reach the server running on localhost.
148 std::string map_rule = "MAP test.example.com test.example.com:" +
149 base::IntToString(server_->server_address().port());
150 EXPECT_TRUE(host_resolver_->AddRuleFromString(map_rule));
151 }
152
zhongyid7dd2db12017-04-14 17:01:25153 std::string ServerPushCacheDirectory() {
154 base::FilePath path;
155 PathService::Get(base::DIR_SOURCE_ROOT, &path);
156 path = path.AppendASCII("net").AppendASCII("data").AppendASCII(
157 "quic_http_response_cache_data_with_push");
158 // The file path is known to be an ascii string.
159 return path.MaybeAsASCII();
160 }
161
xunjieli100937eb52016-09-15 20:09:37162 std::unique_ptr<MappedHostResolver> host_resolver_;
163 std::unique_ptr<QuicSimpleServer> server_;
164 std::unique_ptr<TestURLRequestContext> context_;
zhongyid7dd2db12017-04-14 17:01:25165 TestNetLog net_log_;
vasilvv28270e8f2016-12-01 21:38:09166 QuicHttpResponseCache response_cache_;
xunjieli100937eb52016-09-15 20:09:37167 MockCertVerifier cert_verifier_;
168};
169
170// A URLRequest::Delegate that checks LoadTimingInfo when response headers are
171// received.
172class CheckLoadTimingDelegate : public TestDelegate {
173 public:
174 CheckLoadTimingDelegate(bool session_reused)
175 : session_reused_(session_reused) {}
176 void OnResponseStarted(URLRequest* request, int error) override {
177 TestDelegate::OnResponseStarted(request, error);
178 LoadTimingInfo load_timing_info;
179 request->GetLoadTimingInfo(&load_timing_info);
180 assertLoadTimingValid(load_timing_info, session_reused_);
181 }
182
183 private:
184 void assertLoadTimingValid(const LoadTimingInfo& load_timing_info,
185 bool session_reused) {
186 EXPECT_EQ(session_reused, load_timing_info.socket_reused);
187
188 // If |session_reused| is true, these fields should all be null, non-null
189 // otherwise.
190 EXPECT_EQ(session_reused,
191 load_timing_info.connect_timing.connect_start.is_null());
192 EXPECT_EQ(session_reused,
193 load_timing_info.connect_timing.connect_end.is_null());
194 EXPECT_EQ(session_reused,
195 load_timing_info.connect_timing.ssl_start.is_null());
196 EXPECT_EQ(session_reused,
197 load_timing_info.connect_timing.ssl_end.is_null());
198 EXPECT_EQ(load_timing_info.connect_timing.connect_start,
199 load_timing_info.connect_timing.ssl_start);
200 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
201 load_timing_info.connect_timing.ssl_end);
202 EXPECT_EQ(session_reused,
203 load_timing_info.connect_timing.dns_start.is_null());
204 EXPECT_EQ(session_reused,
205 load_timing_info.connect_timing.dns_end.is_null());
206 }
207
208 bool session_reused_;
209
210 DISALLOW_COPY_AND_ASSIGN(CheckLoadTimingDelegate);
211};
212
213// A TestNetworkDelegate that invokes |all_requests_completed_callback| when
214// |num_expected_requests| requests are completed.
215class WaitForCompletionNetworkDelegate : public net::TestNetworkDelegate {
216 public:
217 WaitForCompletionNetworkDelegate(
218 const base::Closure& all_requests_completed_callback,
219 size_t num_expected_requests)
220 : all_requests_completed_callback_(all_requests_completed_callback),
221 num_expected_requests_(num_expected_requests) {}
222
223 void OnCompleted(URLRequest* request, bool started, int net_error) override {
224 net::TestNetworkDelegate::OnCompleted(request, started, net_error);
225 num_expected_requests_--;
226 if (num_expected_requests_ == 0)
227 all_requests_completed_callback_.Run();
228 }
229
230 private:
231 const base::Closure all_requests_completed_callback_;
232 size_t num_expected_requests_;
233 DISALLOW_COPY_AND_ASSIGN(WaitForCompletionNetworkDelegate);
234};
235
236} // namespace
237
238TEST_F(URLRequestQuicTest, TestGetRequest) {
239 Init();
240 CheckLoadTimingDelegate delegate(false);
241 std::string url =
242 base::StringPrintf("https://%s%s", kTestServerHost, kHelloPath);
243 std::unique_ptr<URLRequest> request =
244 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
245
246 request->Start();
247 ASSERT_TRUE(request->is_pending());
248 base::RunLoop().Run();
249
250 EXPECT_TRUE(request->status().is_success());
251 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
252}
253
zhongyid7dd2db12017-04-14 17:01:25254TEST_F(URLRequestQuicTest, CancelPushIfCached) {
255 base::RunLoop run_loop;
256 Init();
257
258 // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
259 // cache.
260 CheckLoadTimingDelegate delegate_0(false);
261 std::string url_0 =
262 base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
263 std::unique_ptr<URLRequest> request_0 =
264 CreateRequest(GURL(url_0), DEFAULT_PRIORITY, &delegate_0);
265
266 request_0->Start();
267 ASSERT_TRUE(request_0->is_pending());
268
269 // Spin the message loop until the client receives the response for the first
270 // request.
271 do {
272 base::RunLoop().RunUntilIdle();
273 } while (request_0->status().is_io_pending());
274 EXPECT_TRUE(request_0->status().is_success());
275
276 // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
277 // Should cancel push for /kitten-1.jpg.
278 CheckLoadTimingDelegate delegate(true);
279 std::string url =
280 base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
281 std::unique_ptr<URLRequest> request =
282 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
283
284 request->Start();
285 ASSERT_TRUE(request->is_pending());
286
287 // Spin the message loop until the client receives the response for the second
288 // request.
289 do {
290 base::RunLoop().RunUntilIdle();
291 } while (request->status().is_io_pending());
292 EXPECT_TRUE(request->status().is_success());
293
294 // Extract net logs on client side to verify push lookup transactions.
295 net::TestNetLogEntry::List entries;
296 ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
297
298 EXPECT_EQ(4u, entries.size());
299
300 std::string value;
301 int net_error;
302 std::string push_url_1 =
303 base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
304 std::string push_url_2 =
305 base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
306
307 EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
308 EXPECT_EQ(value, push_url_1);
shivanisha8061c4202017-06-13 23:35:52309 EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
zhongyid7dd2db12017-04-14 17:01:25310 EXPECT_EQ(value, push_url_2);
311 // Net error code -400 is found for this lookup transaction, the push is not
312 // found in the cache.
shivanisha8061c4202017-06-13 23:35:52313 EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error));
zhongyid7dd2db12017-04-14 17:01:25314 EXPECT_EQ(net_error, -400);
shivanisha8061c4202017-06-13 23:35:52315 // No net error code for this lookup transaction, the push is found.
316 EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
zhongyid7dd2db12017-04-14 17:01:25317
318 // Verify the reset error count received on the server side.
319 EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
320}
321
322TEST_F(URLRequestQuicTest, CancelPushIfCached2) {
323 base::RunLoop run_loop;
324 Init();
325
326 // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
327 // cache.
328 CheckLoadTimingDelegate delegate_0(false);
329 std::string url_0 =
330 base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
331 std::unique_ptr<URLRequest> request_0 =
332 CreateRequest(GURL(url_0), DEFAULT_PRIORITY, &delegate_0);
333
334 request_0->Start();
335 ASSERT_TRUE(request_0->is_pending());
336
337 // Spin the message loop until the client receives the response for the first
338 // request.
339 do {
340 base::RunLoop().RunUntilIdle();
341 } while (request_0->status().is_io_pending());
342 EXPECT_TRUE(request_0->status().is_success());
343
344 // Send a request to the pushed url: /favicon.ico to pull the resource into
345 // cache.
346 CheckLoadTimingDelegate delegate_1(true);
347 std::string url_1 =
348 base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
349 std::unique_ptr<URLRequest> request_1 =
350 CreateRequest(GURL(url_1), DEFAULT_PRIORITY, &delegate_1);
351
352 request_1->Start();
353 ASSERT_TRUE(request_1->is_pending());
354
355 // Spin the message loop until the client receives the response for the second
356 // request.
357 do {
358 base::RunLoop().RunUntilIdle();
359 } while (request_1->status().is_io_pending());
360 EXPECT_TRUE(request_1->status().is_success());
361
362 // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
363 // Should cancel push for /kitten-1.jpg.
364 CheckLoadTimingDelegate delegate(true);
365 std::string url =
366 base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
367 std::unique_ptr<URLRequest> request =
368 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
369
370 request->Start();
371 ASSERT_TRUE(request->is_pending());
372
373 // Spin the message loop until the client receives the response for the third
374 // request.
375 do {
376 base::RunLoop().RunUntilIdle();
377 } while (request->status().is_io_pending());
378 EXPECT_TRUE(request->status().is_success());
379
380 // Extract net logs on client side to verify push lookup transactions.
381 net::TestNetLogEntry::List entries;
382 ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
383
384 EXPECT_EQ(4u, entries.size());
385
386 std::string value;
387 int net_error;
388 std::string push_url_1 =
389 base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
390 std::string push_url_2 =
391 base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
392
393 EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
394 EXPECT_EQ(value, push_url_1);
shivanisha1e2e3472017-04-26 20:09:12395
shivanisha8061c4202017-06-13 23:35:52396 EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
warxae7fa092017-04-27 02:45:58397 EXPECT_EQ(value, push_url_2);
shivanisha8061c4202017-06-13 23:35:52398
399 // No net error code for this lookup transaction, the push is found.
400 EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error));
401
zhongyid7dd2db12017-04-14 17:01:25402 // No net error code for this lookup transaction, the push is found.
403 EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
404
405 // Verify the reset error count received on the server side.
406 EXPECT_LE(2u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
407}
408
409TEST_F(URLRequestQuicTest, DoNotCancelPushIfNotFoundInCache) {
410 base::RunLoop run_loop;
411 Init();
412
413 // Send a request to /index2.hmtl which pushes /kitten-1.jpg and /favicon.ico
414 // and shouldn't cancel any since neither is in cache.
415 CheckLoadTimingDelegate delegate(false);
416 std::string url =
417 base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
418 std::unique_ptr<URLRequest> request =
419 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
420
421 request->Start();
422 ASSERT_TRUE(request->is_pending());
423
424 // Spin the message loop until the client receives response.
425 do {
426 base::RunLoop().RunUntilIdle();
427 } while (request->status().is_io_pending());
428 EXPECT_TRUE(request->status().is_success());
429
430 // Extract net logs on client side to verify push lookup transactions.
431 net::TestNetLogEntry::List entries;
432 ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
433
434 EXPECT_EQ(4u, entries.size());
435
436 std::string value;
437 int net_error;
438 std::string push_url_1 =
439 base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
440 std::string push_url_2 =
441 base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
442
443 EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
444 EXPECT_EQ(value, push_url_1);
445 EXPECT_TRUE(entries[1].GetIntegerValue("net_error", &net_error));
446 EXPECT_EQ(net_error, -400);
447
448 EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
449 EXPECT_EQ(value, push_url_2);
450 EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
451 EXPECT_EQ(net_error, -400);
452
453 // Verify the reset error count received on the server side.
454 EXPECT_EQ(0u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
455}
456
xunjieli100937eb52016-09-15 20:09:37457// Tests that if two requests use the same QUIC session, the second request
458// should not have |LoadTimingInfo::connect_timing|.
459TEST_F(URLRequestQuicTest, TestTwoRequests) {
460 base::RunLoop run_loop;
461 WaitForCompletionNetworkDelegate network_delegate(
462 run_loop.QuitClosure(), /*num_expected_requests=*/2);
463 SetNetworkDelegate(&network_delegate);
464 Init();
465 CheckLoadTimingDelegate delegate(false);
466 delegate.set_quit_on_complete(false);
467 std::string url =
468 base::StringPrintf("https://%s%s", kTestServerHost, kHelloPath);
469 std::unique_ptr<URLRequest> request =
470 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
471
472 CheckLoadTimingDelegate delegate2(true);
473 delegate2.set_quit_on_complete(false);
474 std::unique_ptr<URLRequest> request2 =
475 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate2);
476 request->Start();
477 request2->Start();
478 ASSERT_TRUE(request->is_pending());
479 ASSERT_TRUE(request2->is_pending());
480 run_loop.Run();
481
482 EXPECT_TRUE(request->status().is_success());
483 EXPECT_TRUE(request2->status().is_success());
484 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
485 EXPECT_EQ(kHelloBodyValue, delegate2.data_received());
486}
487
488} // namespace net