1 // Copyright 2016 The Chromium Authors
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 #include <string_view>
7
8 #include "base/feature_list.h"
9 #include "base/files/file_path.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/test/bind.h"
15 #include "base/time/time.h"
16 #include "build/build_config.h"
17 #include "net/base/features.h"
18 #include "net/base/isolation_info.h"
19 #include "net/base/load_timing_info.h"
20 #include "net/base/network_delegate.h"
21 #include "net/cert/mock_cert_verifier.h"
22 #include "net/dns/mapped_host_resolver.h"
23 #include "net/dns/mock_host_resolver.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/log/net_log_event_type.h"
26 #include "net/log/test_net_log_util.h"
27 #include "net/quic/crypto_test_utils_chromium.h"
28 #include "net/quic/quic_context.h"
29 #include "net/test/cert_test_util.h"
30 #include "net/test/gtest_util.h"
31 #include "net/test/test_data_directory.h"
32 #include "net/test/test_with_task_environment.h"
33 #include "net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.h"
34 #include "net/third_party/quiche/src/quiche/quic/core/quic_time.h"
35 #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
36 #include "net/third_party/quiche/src/quiche/quic/tools/quic_memory_cache_backend.h"
37 #include "net/third_party/quiche/src/quiche/quic/tools/quic_simple_dispatcher.h"
38 #include "net/tools/quic/quic_simple_server.h"
39 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
40 #include "net/url_request/url_request.h"
41 #include "net/url_request/url_request_context.h"
42 #include "net/url_request/url_request_context_builder.h"
43 #include "net/url_request/url_request_test_util.h"
44 #include "testing/gmock/include/gmock/gmock.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "url/gurl.h"
47 #include "url/origin.h"
48
49 namespace net {
50
51 namespace {
52
53 // This must match the certificate used (quic-chain.pem and quic-leaf-cert.key).
54 const char kTestServerHost[] = "test.example.com";
55 // Used as a simple response from the server.
56 const char kHelloPath[] = "/hello.txt";
57 const char kHelloBodyValue[] = "Hello from QUIC Server";
58 const int kHelloStatus = 200;
59
60 class URLRequestQuicTest
61 : public TestWithTaskEnvironment,
62 public ::testing::WithParamInterface<quic::ParsedQuicVersion> {
63 protected:
URLRequestQuicTest()64 URLRequestQuicTest()
65 : context_builder_(CreateTestURLRequestContextBuilder()) {
66 QuicEnableVersion(version());
67 StartQuicServer(version());
68
69 HttpNetworkSessionParams params;
70 CertVerifyResult verify_result;
71 verify_result.verified_cert = ImportCertFromFile(
72 GetTestCertsDirectory(), "quic-chain.pem");
73 auto cert_verifier = std::make_unique<MockCertVerifier>();
74 cert_verifier->AddResultForCertAndHost(verify_result.verified_cert.get(),
75 kTestServerHost, verify_result, OK);
76 // To simplify the test, and avoid the race with the HTTP request, we force
77 // QUIC for these requests.
78 auto quic_context = std::make_unique<QuicContext>();
79 quic_context->params()->supported_versions = {version()};
80 quic_context->params()->origins_to_force_quic_on.insert(
81 HostPortPair(kTestServerHost, 443));
82 context_builder_->set_quic_context(std::move(quic_context));
83 params.enable_quic = true;
84 context_builder_->set_host_resolver(std::move(host_resolver_));
85 context_builder_->set_http_network_session_params(params);
86 context_builder_->SetCertVerifier(std::move(cert_verifier));
87 context_builder_->set_net_log(NetLog::Get());
88 }
89
TearDown()90 void TearDown() override {
91 if (server_) {
92 server_->Shutdown();
93 base::RunLoop().RunUntilIdle();
94 }
95 }
96
context_builder()97 URLRequestContextBuilder* context_builder() { return context_builder_.get(); }
98
BuildContext()99 std::unique_ptr<URLRequestContext> BuildContext() {
100 auto context = context_builder_->Build();
101 return context;
102 }
103
CreateRequest(URLRequestContext * context,const GURL & url,URLRequest::Delegate * delegate)104 static std::unique_ptr<URLRequest> CreateRequest(
105 URLRequestContext* context,
106 const GURL& url,
107 URLRequest::Delegate* delegate) {
108 return context->CreateRequest(url, DEFAULT_PRIORITY, delegate,
109 TRAFFIC_ANNOTATION_FOR_TESTS);
110 }
111
GetRstErrorCountReceivedByServer(quic::QuicRstStreamErrorCode error_code) const112 unsigned int GetRstErrorCountReceivedByServer(
113 quic::QuicRstStreamErrorCode error_code) const {
114 return (static_cast<quic::QuicSimpleDispatcher*>(server_->dispatcher()))
115 ->GetRstErrorCount(error_code);
116 }
117
FindEndBySource(const std::vector<NetLogEntry> & entries,const NetLogSource & source)118 static const NetLogEntry* FindEndBySource(
119 const std::vector<NetLogEntry>& entries,
120 const NetLogSource& source) {
121 for (const auto& entry : entries) {
122 if (entry.phase == NetLogEventPhase::END &&
123 entry.source.type == source.type && entry.source.id == source.id)
124 return &entry;
125 }
126 return nullptr;
127 }
128
version()129 quic::ParsedQuicVersion version() { return GetParam(); }
130
131 protected:
132 // Returns a fully-qualified URL for |path| on the test server.
UrlFromPath(std::string_view path)133 std::string UrlFromPath(std::string_view path) {
134 return std::string("https://") + std::string(kTestServerHost) +
135 std::string(path);
136 }
137
SetDelay(std::string_view host,std::string_view path,base::TimeDelta delay)138 void SetDelay(std::string_view host,
139 std::string_view path,
140 base::TimeDelta delay) {
141 memory_cache_backend_.SetResponseDelay(
142 host, path,
143 quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
144 }
145
146 private:
StartQuicServer(quic::ParsedQuicVersion version)147 void StartQuicServer(quic::ParsedQuicVersion version) {
148 // Set up in-memory cache.
149
150 // Add the simply hello response.
151 memory_cache_backend_.AddSimpleResponse(kTestServerHost, kHelloPath,
152 kHelloStatus, kHelloBodyValue);
153
154 quic::QuicConfig config;
155 // Set up server certs.
156 server_ = std::make_unique<QuicSimpleServer>(
157 net::test::ProofSourceForTestingChromium(), config,
158 quic::QuicCryptoServerConfig::ConfigOptions(),
159 quic::ParsedQuicVersionVector{version}, &memory_cache_backend_);
160 int rv =
161 server_->Listen(net::IPEndPoint(net::IPAddress::IPv4AllZeros(), 0));
162 EXPECT_GE(rv, 0) << "Quic server fails to start";
163
164 auto resolver = std::make_unique<MockHostResolver>();
165 resolver->rules()->AddRule("test.example.com", "127.0.0.1");
166 host_resolver_ = std::make_unique<MappedHostResolver>(std::move(resolver));
167 // Use a mapped host resolver so that request for test.example.com
168 // reach the server running on localhost.
169 std::string map_rule =
170 "MAP test.example.com test.example.com:" +
171 base::NumberToString(server_->server_address().port());
172 EXPECT_TRUE(host_resolver_->AddRuleFromString(map_rule));
173 }
174
175 std::unique_ptr<MappedHostResolver> host_resolver_;
176 std::unique_ptr<QuicSimpleServer> server_;
177 quic::QuicMemoryCacheBackend memory_cache_backend_;
178 std::unique_ptr<URLRequestContextBuilder> context_builder_;
179 quic::test::QuicFlagSaver flags_; // Save/restore all QUIC flag values.
180 };
181
182 // A URLRequest::Delegate that checks LoadTimingInfo when response headers are
183 // received.
184 class CheckLoadTimingDelegate : public TestDelegate {
185 public:
CheckLoadTimingDelegate(bool session_reused)186 explicit CheckLoadTimingDelegate(bool session_reused)
187 : session_reused_(session_reused) {}
188
189 CheckLoadTimingDelegate(const CheckLoadTimingDelegate&) = delete;
190 CheckLoadTimingDelegate& operator=(const CheckLoadTimingDelegate&) = delete;
191
OnResponseStarted(URLRequest * request,int error)192 void OnResponseStarted(URLRequest* request, int error) override {
193 TestDelegate::OnResponseStarted(request, error);
194 LoadTimingInfo load_timing_info;
195 request->GetLoadTimingInfo(&load_timing_info);
196 assertLoadTimingValid(load_timing_info, session_reused_);
197 }
198
199 private:
assertLoadTimingValid(const LoadTimingInfo & load_timing_info,bool session_reused)200 void assertLoadTimingValid(const LoadTimingInfo& load_timing_info,
201 bool session_reused) {
202 EXPECT_EQ(session_reused, load_timing_info.socket_reused);
203
204 // If |session_reused| is true, these fields should all be null, non-null
205 // otherwise.
206 EXPECT_EQ(session_reused,
207 load_timing_info.connect_timing.connect_start.is_null());
208 EXPECT_EQ(session_reused,
209 load_timing_info.connect_timing.connect_end.is_null());
210 EXPECT_EQ(session_reused,
211 load_timing_info.connect_timing.ssl_start.is_null());
212 EXPECT_EQ(session_reused,
213 load_timing_info.connect_timing.ssl_end.is_null());
214 EXPECT_EQ(load_timing_info.connect_timing.connect_start,
215 load_timing_info.connect_timing.ssl_start);
216 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
217 load_timing_info.connect_timing.ssl_end);
218 EXPECT_EQ(session_reused,
219 load_timing_info.connect_timing.domain_lookup_start.is_null());
220 EXPECT_EQ(session_reused,
221 load_timing_info.connect_timing.domain_lookup_end.is_null());
222 }
223
224 bool session_reused_;
225 };
226
227 // A TestNetworkDelegate that invokes |all_requests_completed_callback| when
228 // |num_expected_requests| requests are completed.
229 class WaitForCompletionNetworkDelegate : public net::TestNetworkDelegate {
230 public:
WaitForCompletionNetworkDelegate(base::OnceClosure all_requests_completed_callback,size_t num_expected_requests)231 WaitForCompletionNetworkDelegate(
232 base::OnceClosure all_requests_completed_callback,
233 size_t num_expected_requests)
234 : all_requests_completed_callback_(
235 std::move(all_requests_completed_callback)),
236 num_expected_requests_(num_expected_requests) {}
237
238 WaitForCompletionNetworkDelegate(const WaitForCompletionNetworkDelegate&) =
239 delete;
240 WaitForCompletionNetworkDelegate& operator=(
241 const WaitForCompletionNetworkDelegate&) = delete;
242
OnCompleted(URLRequest * request,bool started,int net_error)243 void OnCompleted(URLRequest* request, bool started, int net_error) override {
244 net::TestNetworkDelegate::OnCompleted(request, started, net_error);
245 num_expected_requests_--;
246 if (num_expected_requests_ == 0)
247 std::move(all_requests_completed_callback_).Run();
248 }
249
250 private:
251 base::OnceClosure all_requests_completed_callback_;
252 size_t num_expected_requests_;
253 };
254
255 } // namespace
256
257 // Used by ::testing::PrintToStringParamName().
PrintToString(const quic::ParsedQuicVersion & v)258 std::string PrintToString(const quic::ParsedQuicVersion& v) {
259 return quic::ParsedQuicVersionToString(v);
260 }
261
262 INSTANTIATE_TEST_SUITE_P(Version,
263 URLRequestQuicTest,
264 ::testing::ValuesIn(AllSupportedQuicVersions()),
265 ::testing::PrintToStringParamName());
266
TEST_P(URLRequestQuicTest,TestGetRequest)267 TEST_P(URLRequestQuicTest, TestGetRequest) {
268 auto context = BuildContext();
269 CheckLoadTimingDelegate delegate(false);
270 std::unique_ptr<URLRequest> request =
271 CreateRequest(context.get(), GURL(UrlFromPath(kHelloPath)), &delegate);
272
273 request->Start();
274 ASSERT_TRUE(request->is_pending());
275 delegate.RunUntilComplete();
276
277 EXPECT_EQ(OK, delegate.request_status());
278 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
279 EXPECT_TRUE(request->ssl_info().is_valid());
280 }
281
282 // Tests that if two requests use the same QUIC session, the second request
283 // should not have |LoadTimingInfo::connect_timing|.
TEST_P(URLRequestQuicTest,TestTwoRequests)284 TEST_P(URLRequestQuicTest, TestTwoRequests) {
285 base::RunLoop run_loop;
286 context_builder()->set_network_delegate(
287 std::make_unique<WaitForCompletionNetworkDelegate>(
288 run_loop.QuitClosure(), /*num_expected_requests=*/2));
289 auto context = BuildContext();
290
291 GURL url = GURL(UrlFromPath(kHelloPath));
292 auto isolation_info =
293 IsolationInfo::CreateForInternalRequest(url::Origin::Create(url));
294
295 CheckLoadTimingDelegate delegate(false);
296 delegate.set_on_complete(base::DoNothing());
297 std::unique_ptr<URLRequest> request =
298 CreateRequest(context.get(), url, &delegate);
299 request->set_isolation_info(isolation_info);
300
301 CheckLoadTimingDelegate delegate2(true);
302 delegate2.set_on_complete(base::DoNothing());
303 std::unique_ptr<URLRequest> request2 =
304 CreateRequest(context.get(), url, &delegate2);
305 request2->set_isolation_info(isolation_info);
306
307 request->Start();
308 request2->Start();
309 ASSERT_TRUE(request->is_pending());
310 ASSERT_TRUE(request2->is_pending());
311 run_loop.Run();
312
313 EXPECT_EQ(OK, delegate.request_status());
314 EXPECT_EQ(OK, delegate2.request_status());
315 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
316 EXPECT_EQ(kHelloBodyValue, delegate2.data_received());
317 }
318
TEST_P(URLRequestQuicTest,RequestHeadersCallback)319 TEST_P(URLRequestQuicTest, RequestHeadersCallback) {
320 auto context = BuildContext();
321 HttpRawRequestHeaders raw_headers;
322 TestDelegate delegate;
323 HttpRequestHeaders extra_headers;
324 extra_headers.SetHeader("X-Foo", "bar");
325
326 std::unique_ptr<URLRequest> request =
327 CreateRequest(context.get(), GURL(UrlFromPath(kHelloPath)), &delegate);
328
329 request->SetExtraRequestHeaders(extra_headers);
330 request->SetRequestHeadersCallback(
331 base::BindLambdaForTesting([&](HttpRawRequestHeaders raw_headers) {
332 // This should be invoked before the request is completed, or any bytes
333 // are read.
334 EXPECT_FALSE(delegate.response_completed());
335 EXPECT_FALSE(delegate.bytes_received());
336
337 EXPECT_FALSE(raw_headers.headers().empty());
338 std::string value;
339 EXPECT_TRUE(raw_headers.FindHeaderForTest("x-foo", &value));
340 EXPECT_EQ("bar", value);
341 EXPECT_TRUE(raw_headers.FindHeaderForTest("accept-encoding", &value));
342 EXPECT_EQ("gzip, deflate", value);
343 EXPECT_TRUE(raw_headers.FindHeaderForTest(":path", &value));
344 EXPECT_EQ("/hello.txt", value);
345 EXPECT_TRUE(raw_headers.FindHeaderForTest(":authority", &value));
346 EXPECT_EQ("test.example.com", value);
347 EXPECT_TRUE(raw_headers.request_line().empty());
348 }));
349 request->Start();
350 ASSERT_TRUE(request->is_pending());
351 delegate.RunUntilComplete();
352 EXPECT_EQ(OK, delegate.request_status());
353 }
354
TEST_P(URLRequestQuicTest,DelayedResponseStart)355 TEST_P(URLRequestQuicTest, DelayedResponseStart) {
356 auto context = BuildContext();
357 TestDelegate delegate;
358 std::unique_ptr<URLRequest> request =
359 CreateRequest(context.get(), GURL(UrlFromPath(kHelloPath)), &delegate);
360
361 constexpr auto delay = base::Milliseconds(300);
362
363 this->SetDelay(kTestServerHost, kHelloPath, delay);
364 request->Start();
365 ASSERT_TRUE(request->is_pending());
366 delegate.RunUntilComplete();
367 LoadTimingInfo timing_info;
368 request->GetLoadTimingInfo(&timing_info);
369 EXPECT_EQ(OK, delegate.request_status());
370 EXPECT_GE((timing_info.receive_headers_start - timing_info.request_start),
371 delay);
372 EXPECT_GE(timing_info.receive_non_informational_headers_start,
373 timing_info.receive_headers_start);
374 }
375
376 } // namespace net
377