1 // Copyright 2017 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 <stdint.h>
6
7 #include <limits>
8 #include <list>
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/auto_reset.h"
15 #include "base/bind.h"
16 #include "base/callback_helpers.h"
17 #include "base/compiler_specific.h"
18 #include "base/files/file.h"
19 #include "base/files/file_path.h"
20 #include "base/files/file_util.h"
21 #include "base/macros.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/metrics/statistics_recorder.h"
25 #include "base/optional.h"
26 #include "base/path_service.h"
27 #include "base/run_loop.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/test/bind.h"
30 #include "base/test/gtest_util.h"
31 #include "base/test/metrics/histogram_tester.h"
32 #include "base/test/task_environment.h"
33 #include "base/threading/thread_task_runner_handle.h"
34 #include "base/time/time.h"
35 #include "build/build_config.h"
36 #include "mojo/public/c/system/data_pipe.h"
37 #include "mojo/public/cpp/bindings/pending_remote.h"
38 #include "mojo/public/cpp/bindings/remote.h"
39 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
40 #include "mojo/public/cpp/system/data_pipe_utils.h"
41 #include "mojo/public/cpp/system/wait.h"
42 #include "net/base/escape.h"
43 #include "net/base/features.h"
44 #include "net/base/io_buffer.h"
45 #include "net/base/ip_endpoint.h"
46 #include "net/base/isolation_info.h"
47 #include "net/base/load_flags.h"
48 #include "net/base/mime_sniffer.h"
49 #include "net/base/net_errors.h"
50 #include "net/base/transport_info.h"
51 #include "net/cert/internal/parse_name.h"
52 #include "net/cert/test_root_certs.h"
53 #include "net/cookies/cookie_access_result.h"
54 #include "net/cookies/cookie_change_dispatcher.h"
55 #include "net/cookies/cookie_inclusion_status.h"
56 #include "net/cookies/cookie_util.h"
57 #include "net/dns/mock_host_resolver.h"
58 #include "net/http/http_response_info.h"
59 #include "net/proxy_resolution/configured_proxy_resolution_service.h"
60 #include "net/ssl/client_cert_identity_test_util.h"
61 #include "net/test/cert_test_util.h"
62 #include "net/test/embedded_test_server/controllable_http_response.h"
63 #include "net/test/embedded_test_server/embedded_test_server.h"
64 #include "net/test/embedded_test_server/http_response.h"
65 #include "net/test/gtest_util.h"
66 #include "net/test/quic_simple_test_server.h"
67 #include "net/test/test_data_directory.h"
68 #include "net/test/url_request/url_request_failed_job.h"
69 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
70 #include "net/url_request/url_request.h"
71 #include "net/url_request/url_request_context.h"
72 #include "net/url_request/url_request_context_builder.h"
73 #include "net/url_request/url_request_filter.h"
74 #include "net/url_request/url_request_interceptor.h"
75 #include "net/url_request/url_request_job.h"
76 #include "net/url_request/url_request_test_job.h"
77 #include "net/url_request/url_request_test_util.h"
78 #include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
79 #include "services/network/public/cpp/features.h"
80 #include "services/network/public/cpp/resource_request.h"
81 #include "services/network/public/mojom/cookie_access_observer.mojom-forward.h"
82 #include "services/network/public/mojom/cookie_access_observer.mojom.h"
83 #include "services/network/public/mojom/ip_address_space.mojom.h"
84 #include "services/network/public/mojom/network_context.mojom.h"
85 #include "services/network/public/mojom/origin_policy_manager.mojom.h"
86 #include "services/network/public/mojom/trust_tokens.mojom-shared.h"
87 #include "services/network/public/mojom/url_loader.mojom.h"
88 #include "services/network/resource_scheduler/resource_scheduler_client.h"
89 #include "services/network/test/test_data_pipe_getter.h"
90 #include "services/network/test/test_network_context_client.h"
91 #include "services/network/test/test_network_service_client.h"
92 #include "services/network/test/test_url_loader_client.h"
93 #include "services/network/test_chunked_data_pipe_getter.h"
94 #include "services/network/trust_tokens/trust_token_key_commitment_getter.h"
95 #include "services/network/trust_tokens/trust_token_request_helper.h"
96 #include "services/network/trust_tokens/trust_token_request_helper_factory.h"
97 #include "services/network/url_loader.h"
98 #include "services/network/url_request_context_owner.h"
99 #include "testing/gmock/include/gmock/gmock.h"
100 #include "testing/gtest/include/gtest/gtest.h"
101 #include "url/gurl.h"
102
103 namespace network {
104
105 namespace {
106
107 using ::net::test::IsError;
108 using ::net::test::IsOk;
109 using ::testing::Optional;
110 using ::testing::ValuesIn;
111
112 // Returns a URLLoader::DeleteCallback that destroys |url_loader| and quits
113 // |run_loop| when invoked. Tests must wait on the RunLoop to ensure nothing is
114 // leaked. Takes a std::unique_ptr<URLLoader>* instead of a unique_ptr because
115 // the callback must be created before the URLLoader is actually created.
DeleteLoaderCallback(base::RunLoop * run_loop,std::unique_ptr<URLLoader> * url_loader)116 URLLoader::DeleteCallback DeleteLoaderCallback(
117 base::RunLoop* run_loop,
118 std::unique_ptr<URLLoader>* url_loader) {
119 return base::BindOnce(
120 [](base::RunLoop* run_loop, std::unique_ptr<URLLoader>* url_loader,
121 mojom::URLLoader* url_loader_ptr) {
122 DCHECK_EQ(url_loader->get(), url_loader_ptr);
123 url_loader->reset();
124 run_loop->Quit();
125 },
126 run_loop, url_loader);
127 }
128
129 // Returns a URLLoader::DeleteCallback that does nothing, but calls NOTREACHED.
130 // Tests that use a URLLoader that actually tries to delete itself shouldn't use
131 // this method, as URLLoaders don't expect to be alive after they invoke their
132 // delete callback.
NeverInvokedDeleteLoaderCallback()133 URLLoader::DeleteCallback NeverInvokedDeleteLoaderCallback() {
134 return base::BindOnce([](mojom::URLLoader* /* loader*/) { NOTREACHED(); });
135 }
136
137 constexpr char kBodyReadFromNetBeforePausedHistogram[] =
138 "Network.URLLoader.BodyReadFromNetBeforePaused";
139
140 constexpr char kTestAuthURL[] = "/auth-basic?password=PASS&realm=REALM";
141
142 constexpr char kInsecureHost[] = "othersite.test";
143
CreateResourceRequest(const char * method,const GURL & url)144 static ResourceRequest CreateResourceRequest(const char* method,
145 const GURL& url) {
146 ResourceRequest request;
147 request.method = std::string(method);
148 request.url = url;
149 request.site_for_cookies =
150 net::SiteForCookies::FromUrl(url); // bypass third-party cookie blocking
151 url::Origin origin = url::Origin::Create(url);
152 request.request_initiator = origin; // ensure initiator is set
153 request.is_main_frame = true;
154 request.trusted_params = network::ResourceRequest::TrustedParams();
155 request.trusted_params->isolation_info =
156 net::IsolationInfo::CreateForInternalRequest(origin);
157 return request;
158 }
159
160 class URLRequestMultipleWritesJob : public net::URLRequestJob {
161 public:
URLRequestMultipleWritesJob(net::URLRequest * request,std::list<std::string> packets,net::Error net_error,bool async_reads)162 URLRequestMultipleWritesJob(net::URLRequest* request,
163 std::list<std::string> packets,
164 net::Error net_error,
165 bool async_reads)
166 : URLRequestJob(request),
167 packets_(std::move(packets)),
168 net_error_(net_error),
169 async_reads_(async_reads) {}
170
171 ~URLRequestMultipleWritesJob() override = default;
172
173 // net::URLRequestJob implementation:
Start()174 void Start() override {
175 base::ThreadTaskRunnerHandle::Get()->PostTask(
176 FROM_HERE, base::BindOnce(&URLRequestMultipleWritesJob::StartAsync,
177 weak_factory_.GetWeakPtr()));
178 }
179
ReadRawData(net::IOBuffer * buf,int buf_size)180 int ReadRawData(net::IOBuffer* buf, int buf_size) override {
181 int result;
182 if (packets_.empty()) {
183 result = net_error_;
184 } else {
185 std::string packet = packets_.front();
186 packets_.pop_front();
187 CHECK_GE(buf_size, static_cast<int>(packet.length()));
188 memcpy(buf->data(), packet.c_str(), packet.length());
189 result = packet.length();
190 }
191
192 if (async_reads_) {
193 base::ThreadTaskRunnerHandle::Get()->PostTask(
194 FROM_HERE,
195 base::BindOnce(&URLRequestMultipleWritesJob::ReadRawDataComplete,
196 weak_factory_.GetWeakPtr(), result));
197 return net::ERR_IO_PENDING;
198 }
199 return result;
200 }
201
202 private:
StartAsync()203 void StartAsync() { NotifyHeadersComplete(); }
204
205 std::list<std::string> packets_;
206 net::Error net_error_;
207 bool async_reads_;
208
209 base::WeakPtrFactory<URLRequestMultipleWritesJob> weak_factory_{this};
210
211 DISALLOW_COPY_AND_ASSIGN(URLRequestMultipleWritesJob);
212 };
213
214 class MultipleWritesInterceptor : public net::URLRequestInterceptor {
215 public:
MultipleWritesInterceptor(std::list<std::string> packets,net::Error net_error,bool async_reads)216 MultipleWritesInterceptor(std::list<std::string> packets,
217 net::Error net_error,
218 bool async_reads)
219 : packets_(std::move(packets)),
220 net_error_(net_error),
221 async_reads_(async_reads) {}
~MultipleWritesInterceptor()222 ~MultipleWritesInterceptor() override {}
223
GetURL()224 static GURL GetURL() { return GURL("http://foo"); }
225
226 // URLRequestInterceptor implementation:
MaybeInterceptRequest(net::URLRequest * request) const227 std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
228 net::URLRequest* request) const override {
229 return std::make_unique<URLRequestMultipleWritesJob>(
230 request, std::move(packets_), net_error_, async_reads_);
231 }
232
233 private:
234 std::list<std::string> packets_;
235 net::Error net_error_;
236 bool async_reads_;
237
238 DISALLOW_COPY_AND_ASSIGN(MultipleWritesInterceptor);
239 };
240
241 // Every read completes synchronously.
242 class URLRequestEternalSyncReadsJob : public net::URLRequestJob {
243 public:
244 // If |fill_entire_buffer| is true, each read fills the entire read buffer at
245 // once. Otherwise, one byte is read at a time.
URLRequestEternalSyncReadsJob(net::URLRequest * request,bool fill_entire_buffer)246 URLRequestEternalSyncReadsJob(net::URLRequest* request,
247 bool fill_entire_buffer)
248 : URLRequestJob(request), fill_entire_buffer_(fill_entire_buffer) {}
249
250 ~URLRequestEternalSyncReadsJob() override = default;
251
252 // net::URLRequestJob implementation:
Start()253 void Start() override {
254 base::ThreadTaskRunnerHandle::Get()->PostTask(
255 FROM_HERE, base::BindOnce(&URLRequestEternalSyncReadsJob::StartAsync,
256 weak_factory_.GetWeakPtr()));
257 }
258
ReadRawData(net::IOBuffer * buf,int buf_size)259 int ReadRawData(net::IOBuffer* buf, int buf_size) override {
260 DCHECK_GT(buf_size, 0);
261 if (fill_entire_buffer_) {
262 memset(buf->data(), 'a', buf_size);
263 return buf_size;
264 }
265
266 buf->data()[0] = 'a';
267 return 1;
268 }
269
270 private:
StartAsync()271 void StartAsync() { NotifyHeadersComplete(); }
272
273 const bool fill_entire_buffer_;
274
275 base::WeakPtrFactory<URLRequestEternalSyncReadsJob> weak_factory_{this};
276
277 DISALLOW_COPY_AND_ASSIGN(URLRequestEternalSyncReadsJob);
278 };
279
280 class EternalSyncReadsInterceptor : public net::URLRequestInterceptor {
281 public:
EternalSyncReadsInterceptor()282 EternalSyncReadsInterceptor() {}
~EternalSyncReadsInterceptor()283 ~EternalSyncReadsInterceptor() override {}
284
GetHostName()285 static std::string GetHostName() { return "eternal"; }
286
GetSingleByteURL()287 static GURL GetSingleByteURL() { return GURL("http://eternal/single-byte"); }
GetFillBufferURL()288 static GURL GetFillBufferURL() { return GURL("http://eternal/fill-buffer"); }
289
290 // URLRequestInterceptor implementation:
MaybeInterceptRequest(net::URLRequest * request) const291 std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
292 net::URLRequest* request) const override {
293 if (request->url() == GetSingleByteURL()) {
294 return std::make_unique<URLRequestEternalSyncReadsJob>(
295 request, false /* fill_entire_buffer */);
296 }
297 if (request->url() == GetFillBufferURL()) {
298 return std::make_unique<URLRequestEternalSyncReadsJob>(
299 request, true /* fill_entire_buffer */);
300 }
301 return nullptr;
302 }
303
304 private:
305 DISALLOW_COPY_AND_ASSIGN(EternalSyncReadsInterceptor);
306 };
307
308 // Simulates handing over things to the disk to write before returning to the
309 // caller.
310 class URLRequestSimulatedCacheJob : public net::URLRequestJob {
311 public:
312 // If |fill_entire_buffer| is true, each read fills the entire read buffer at
313 // once. Otherwise, one byte is read at a time.
URLRequestSimulatedCacheJob(net::URLRequest * request,scoped_refptr<net::IOBuffer> * simulated_cache_dest,bool use_text_plain)314 URLRequestSimulatedCacheJob(
315 net::URLRequest* request,
316 scoped_refptr<net::IOBuffer>* simulated_cache_dest,
317 bool use_text_plain)
318 : URLRequestJob(request),
319 simulated_cache_dest_(simulated_cache_dest),
320 use_text_plain_(use_text_plain) {}
321
322 ~URLRequestSimulatedCacheJob() override = default;
323
324 // net::URLRequestJob implementation:
Start()325 void Start() override {
326 base::ThreadTaskRunnerHandle::Get()->PostTask(
327 FROM_HERE, base::BindOnce(&URLRequestSimulatedCacheJob::StartAsync,
328 weak_factory_.GetWeakPtr()));
329 }
330
GetResponseInfo(net::HttpResponseInfo * info)331 void GetResponseInfo(net::HttpResponseInfo* info) override {
332 if (!use_text_plain_)
333 return URLRequestJob::GetResponseInfo(info);
334 if (!info->headers) {
335 info->headers = net::HttpResponseHeaders::TryToCreate(
336 "HTTP/1.1 200 OK\r\nContent-Type: text/plain");
337 }
338 }
339
ReadRawData(net::IOBuffer * buf,int buf_size)340 int ReadRawData(net::IOBuffer* buf, int buf_size) override {
341 DCHECK_GT(buf_size, 0);
342
343 // Pretend this is the entire network stack, which has sent the buffer
344 // to some worker thread to be written to disk.
345 memset(buf->data(), 'a', buf_size);
346 *simulated_cache_dest_ = buf;
347
348 // The network stack will not report the read result until the write
349 // completes.
350 return net::ERR_IO_PENDING;
351 }
352
353 private:
StartAsync()354 void StartAsync() { NotifyHeadersComplete(); }
355
356 scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
357 bool use_text_plain_;
358 base::WeakPtrFactory<URLRequestSimulatedCacheJob> weak_factory_{this};
359
360 DISALLOW_COPY_AND_ASSIGN(URLRequestSimulatedCacheJob);
361 };
362
363 class SimulatedCacheInterceptor : public net::URLRequestInterceptor {
364 public:
SimulatedCacheInterceptor(scoped_refptr<net::IOBuffer> * simulated_cache_dest,bool use_text_plain)365 explicit SimulatedCacheInterceptor(
366 scoped_refptr<net::IOBuffer>* simulated_cache_dest,
367 bool use_text_plain)
368 : simulated_cache_dest_(simulated_cache_dest),
369 use_text_plain_(use_text_plain) {}
370
MaybeInterceptRequest(net::URLRequest * request) const371 std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
372 net::URLRequest* request) const override {
373 return std::make_unique<URLRequestSimulatedCacheJob>(
374 request, simulated_cache_dest_, use_text_plain_);
375 }
376
377 private:
378 scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
379 bool use_text_plain_;
380 DISALLOW_COPY_AND_ASSIGN(SimulatedCacheInterceptor);
381 };
382
383 // Fakes the TransportInfo passed to URLRequest::Delegate::OnConnected().
384 class URLRequestFakeTransportInfoJob : public net::URLRequestJob {
385 public:
386 // |transport_info| is subsequently passed to the OnConnected() callback.
URLRequestFakeTransportInfoJob(net::URLRequest * request,const net::TransportInfo & transport_info)387 URLRequestFakeTransportInfoJob(net::URLRequest* request,
388 const net::TransportInfo& transport_info)
389 : URLRequestJob(request), transport_info_(transport_info) {}
390
391 URLRequestFakeTransportInfoJob(const URLRequestFakeTransportInfoJob&) =
392 delete;
393 URLRequestFakeTransportInfoJob& operator=(
394 const URLRequestFakeTransportInfoJob&) = delete;
395
396 ~URLRequestFakeTransportInfoJob() override = default;
397
398 // net::URLRequestJob implementation:
Start()399 void Start() override {
400 base::ThreadTaskRunnerHandle::Get()->PostTask(
401 FROM_HERE, base::BindOnce(&URLRequestFakeTransportInfoJob::StartAsync,
402 weak_factory_.GetWeakPtr()));
403 }
404
ReadRawData(net::IOBuffer * buf,int buf_size)405 int ReadRawData(net::IOBuffer* buf, int buf_size) override { return 0; }
406
407 private:
StartAsync()408 void StartAsync() {
409 const int result = NotifyConnected(transport_info_);
410 if (result != net::OK) {
411 NotifyStartError(result);
412 return;
413 }
414
415 NotifyHeadersComplete();
416 }
417
418 // The fake transport info we pass to OnConnected().
419 const net::TransportInfo transport_info_;
420
421 base::WeakPtrFactory<URLRequestFakeTransportInfoJob> weak_factory_{this};
422 };
423
424 // Intercepts URLRequestJob creation to a specific URL. All requests to this
425 // URL will report being connected with a fake TransportInfo struct.
426 class FakeTransportInfoInterceptor : public net::URLRequestInterceptor {
427 public:
428 // All intercepted requests will claim to be connected via |transport_info|.
FakeTransportInfoInterceptor(const net::TransportInfo & transport_info)429 explicit FakeTransportInfoInterceptor(
430 const net::TransportInfo& transport_info)
431 : transport_info_(transport_info) {}
432
433 ~FakeTransportInfoInterceptor() override = default;
434
435 FakeTransportInfoInterceptor(const FakeTransportInfoInterceptor&) = delete;
436 FakeTransportInfoInterceptor& operator=(const FakeTransportInfoInterceptor&) =
437 delete;
438
439 // URLRequestInterceptor implementation:
MaybeInterceptRequest(net::URLRequest * request) const440 std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
441 net::URLRequest* request) const override {
442 return std::make_unique<URLRequestFakeTransportInfoJob>(request,
443 transport_info_);
444 }
445
446 private:
447 const net::TransportInfo transport_info_;
448 };
449
450 // Returns a maximally-restrictive security state for use in tests.
NewSecurityState()451 mojom::ClientSecurityStatePtr NewSecurityState() {
452 auto result = mojom::ClientSecurityState::New();
453 result->is_web_secure_context = false;
454 result->private_network_request_policy =
455 mojom::PrivateNetworkRequestPolicy::kBlockFromInsecureToMorePrivate;
456 result->ip_address_space = mojom::IPAddressSpace::kUnknown;
457 return result;
458 }
459
460 // Returns whether monitoring was successfully set up. If yes,
461 // StopMonitorBodyReadFromNetBeforePausedHistogram() needs to be called later to
462 // stop monitoring.
463 //
464 // |*output_sample| needs to stay valid until monitoring is stopped.
StartMonitorBodyReadFromNetBeforePausedHistogram(const base::RepeatingClosure & quit_closure,base::HistogramBase::Sample * output_sample)465 WARN_UNUSED_RESULT bool StartMonitorBodyReadFromNetBeforePausedHistogram(
466 const base::RepeatingClosure& quit_closure,
467 base::HistogramBase::Sample* output_sample) {
468 return base::StatisticsRecorder::SetCallback(
469 kBodyReadFromNetBeforePausedHistogram,
470 base::BindRepeating(
471 [](const base::RepeatingClosure& quit_closure,
472 base::HistogramBase::Sample* output, const char* histogram_name,
473 uint64_t name_hash, base::HistogramBase::Sample sample) {
474 *output = sample;
475 quit_closure.Run();
476 },
477 quit_closure, output_sample));
478 }
479
StopMonitorBodyReadFromNetBeforePausedHistogram()480 void StopMonitorBodyReadFromNetBeforePausedHistogram() {
481 base::StatisticsRecorder::ClearCallback(
482 kBodyReadFromNetBeforePausedHistogram);
483 }
484
485 } // namespace
486
487 class URLLoaderTest : public testing::Test {
488 public:
URLLoaderTest()489 URLLoaderTest()
490 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {
491 net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance();
492 root_certs->AddFromFile(
493 net::GetTestCertsDirectory().AppendASCII("quic-root.pem"));
494
495 net::QuicSimpleTestServer::Start();
496 net::HttpNetworkSession::Params params;
497 auto quic_context = std::make_unique<net::QuicContext>();
498 quic_context->params()->origins_to_force_quic_on.insert(
499 net::HostPortPair(net::QuicSimpleTestServer::GetHost(),
500 net::QuicSimpleTestServer::GetPort()));
501 params.enable_quic = true;
502
503 net::URLRequestContextBuilder context_builder;
504 context_builder.set_http_network_session_params(params);
505 context_builder.set_quic_context(std::move(quic_context));
506 context_builder.set_proxy_resolution_service(
507 net::ConfiguredProxyResolutionService::CreateDirect());
508 auto test_network_delegate = std::make_unique<net::TestNetworkDelegate>();
509 unowned_test_network_delegate_ = test_network_delegate.get();
510 context_builder.set_network_delegate(std::move(test_network_delegate));
511 context_ = context_builder.Build();
512 resource_scheduler_client_ = base::MakeRefCounted<ResourceSchedulerClient>(
513 kProcessId, kRouteId, &resource_scheduler_,
514 context_->network_quality_estimator());
515 net::URLRequestFailedJob::AddUrlHandler();
516 }
~URLLoaderTest()517 ~URLLoaderTest() override {
518 net::URLRequestFilter::GetInstance()->ClearHandlers();
519 }
520
SetUp()521 void SetUp() override {
522 test_server_.AddDefaultHandlers(
523 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
524 // This Unretained is safe because test_server_ is owned by |this|.
525 test_server_.RegisterRequestMonitor(
526 base::BindRepeating(&URLLoaderTest::Monitor, base::Unretained(this)));
527 ASSERT_TRUE(test_server_.Start());
528
529 // Set up a scoped host resolver so that |kInsecureHost| will resolve to
530 // the loopback address and will let us access |test_server_|.
531 scoped_refptr<net::RuleBasedHostResolverProc> mock_resolver_proc =
532 base::MakeRefCounted<net::RuleBasedHostResolverProc>(nullptr);
533 mock_resolver_proc->AddRule("*", "127.0.0.1");
534 mock_host_resolver_ = std::make_unique<net::ScopedDefaultHostResolverProc>(
535 mock_resolver_proc.get());
536 }
537
TearDown()538 void TearDown() override { net::QuicSimpleTestServer::Shutdown(); }
539
540 // Attempts to load |url| and returns the resulting error code. If |body| is
541 // non-NULL, also attempts to read the response body. The advantage of using
542 // |body| instead of calling ReadBody() after Load is that it will load the
543 // response body before URLLoader is complete, so URLLoader completion won't
544 // block on trying to write the body buffer.
Load(const GURL & url,std::string * body=nullptr)545 int Load(const GURL& url, std::string* body = nullptr) WARN_UNUSED_RESULT {
546 DCHECK(!ran_);
547
548 ResourceRequest request =
549 CreateResourceRequest(!request_body_ ? "GET" : "POST", url);
550 uint32_t options = mojom::kURLLoadOptionNone;
551 if (send_ssl_with_response_)
552 options |= mojom::kURLLoadOptionSendSSLInfoWithResponse;
553 if (sniff_)
554 options |= mojom::kURLLoadOptionSniffMimeType;
555 if (send_ssl_for_cert_error_)
556 options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
557
558 std::unique_ptr<TestNetworkContextClient> network_context_client;
559 if (allow_file_uploads_) {
560 network_context_client = std::make_unique<TestNetworkContextClient>();
561 network_context_client->set_upload_files_invalid(upload_files_invalid_);
562 network_context_client->set_ignore_last_upload_file(
563 ignore_last_upload_file_);
564 }
565
566 if (request_body_)
567 request.request_body = request_body_;
568
569 request.trusted_params->client_security_state.Swap(
570 &request_client_security_state_);
571
572 base::RunLoop delete_run_loop;
573 mojo::Remote<mojom::URLLoader> loader;
574 std::unique_ptr<URLLoader> url_loader;
575
576 mojom::URLLoaderFactoryParams params;
577 params.process_id = mojom::kBrowserProcessId;
578 params.is_corb_enabled = false;
579 params.client_security_state.Swap(&factory_client_security_state_);
580
581 url::Origin origin = url::Origin::Create(url);
582 params.isolation_info =
583 net::IsolationInfo::CreateForInternalRequest(origin);
584 params.is_trusted = true;
585 url_loader = std::make_unique<URLLoader>(
586 context(), nullptr /* network_service_client */,
587 network_context_client.get(),
588 DeleteLoaderCallback(&delete_run_loop, &url_loader),
589 loader.BindNewPipeAndPassReceiver(), options, request,
590 client_.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
591 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
592 /*coep_reporter=*/nullptr, 0 /* request_id */,
593 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
594 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
595 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
596 mojo::NullRemote() /* cookie_observer */);
597
598 ran_ = true;
599
600 if (expect_redirect_) {
601 client_.RunUntilRedirectReceived();
602 loader->FollowRedirect({}, {}, {}, base::nullopt);
603 }
604
605 if (body) {
606 client_.RunUntilResponseBodyArrived();
607 *body = ReadBody();
608 }
609
610 client_.RunUntilComplete();
611 if (body) {
612 EXPECT_EQ(body->size(),
613 static_cast<size_t>(
614 client()->completion_status().decoded_body_length));
615 }
616
617 delete_run_loop.Run();
618
619 return client_.completion_status().error_code;
620 }
621
LoadAndCompareFile(const std::string & path)622 void LoadAndCompareFile(const std::string& path) {
623 base::FilePath file = GetTestFilePath(path);
624
625 std::string expected;
626 if (!base::ReadFileToString(file, &expected)) {
627 ADD_FAILURE() << "File not found: " << file.value();
628 return;
629 }
630
631 std::string body;
632 EXPECT_EQ(net::OK,
633 Load(test_server()->GetURL(std::string("/") + path), &body));
634 EXPECT_EQ(expected, body);
635 // The file isn't compressed, so both encoded and decoded body lengths
636 // should match the read body length.
637 EXPECT_EQ(
638 expected.size(),
639 static_cast<size_t>(client()->completion_status().decoded_body_length));
640 EXPECT_EQ(
641 expected.size(),
642 static_cast<size_t>(client()->completion_status().encoded_body_length));
643 // Over the wire length should include headers, so should be longer.
644 // TODO(mmenke): Worth adding better tests for encoded_data_length?
645 EXPECT_LT(
646 expected.size(),
647 static_cast<size_t>(client()->completion_status().encoded_data_length));
648 }
649
650 // Adds a MultipleWritesInterceptor for MultipleWritesInterceptor::GetURL()
651 // that results in seeing each element of |packets| read individually, and
652 // then a final read that returns |net_error|. The URLRequestInterceptor is
653 // not removed from URLFilter until the test fixture is torn down.
654 // |async_reads| indicates whether all reads (including those for |packets|
655 // and |net_error|) complete asynchronously or not.
AddMultipleWritesInterceptor(std::list<std::string> packets,net::Error net_error,bool async_reads)656 void AddMultipleWritesInterceptor(std::list<std::string> packets,
657 net::Error net_error,
658 bool async_reads) {
659 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
660 MultipleWritesInterceptor::GetURL(),
661 std::unique_ptr<net::URLRequestInterceptor>(
662 new MultipleWritesInterceptor(std::move(packets), net_error,
663 async_reads)));
664 }
665
666 // Adds an EternalSyncReadsInterceptor for
667 // EternalSyncReadsInterceptor::GetURL(), which creates URLRequestJobs where
668 // all reads return a sync byte that's read synchronously.
AddEternalSyncReadsInterceptor()669 void AddEternalSyncReadsInterceptor() {
670 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
671 "http", EternalSyncReadsInterceptor::GetHostName(),
672 std::make_unique<EternalSyncReadsInterceptor>());
673 }
674
675 // If |second| is empty, then it's ignored.
LoadPacketsAndVerifyContents(const std::string & first,const std::string & second)676 void LoadPacketsAndVerifyContents(const std::string& first,
677 const std::string& second) {
678 EXPECT_FALSE(first.empty());
679 std::list<std::string> packets;
680 packets.push_back(first);
681 if (!second.empty())
682 packets.push_back(second);
683 AddMultipleWritesInterceptor(std::move(packets), net::OK,
684 false /* async_reads */);
685
686 std::string expected_body = first + second;
687 std::string actual_body;
688 EXPECT_EQ(net::OK, Load(MultipleWritesInterceptor::GetURL(), &actual_body));
689
690 EXPECT_EQ(actual_body, expected_body);
691 }
692
test_server()693 net::EmbeddedTestServer* test_server() { return &test_server_; }
context()694 net::URLRequestContext* context() { return context_.get(); }
client()695 TestURLLoaderClient* client() { return &client_; }
DestroyContext()696 void DestroyContext() {
697 resource_scheduler_client_ = nullptr;
698 context_.reset();
699 }
700
701 // Returns the path of the requested file in the test data directory.
GetTestFilePath(const std::string & file_name)702 base::FilePath GetTestFilePath(const std::string& file_name) {
703 base::FilePath file_path;
704 base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
705 file_path = file_path.Append(FILE_PATH_LITERAL("services"));
706 file_path = file_path.Append(FILE_PATH_LITERAL("test"));
707 file_path = file_path.Append(FILE_PATH_LITERAL("data"));
708 return file_path.AppendASCII(file_name);
709 }
710
OpenFileForUpload(const base::FilePath & file_path)711 base::File OpenFileForUpload(const base::FilePath& file_path) {
712 int open_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
713 #if defined(OS_WIN)
714 open_flags |= base::File::FLAG_ASYNC;
715 #endif // defined(OS_WIN)
716 base::File file(file_path, open_flags);
717 EXPECT_TRUE(file.IsValid());
718 return file;
719 }
720
resource_scheduler()721 ResourceScheduler* resource_scheduler() { return &resource_scheduler_; }
resource_scheduler_client()722 scoped_refptr<ResourceSchedulerClient> resource_scheduler_client() {
723 return resource_scheduler_client_;
724 }
725
726 // Configure how Load() works.
allow_file_uploads()727 void allow_file_uploads() {
728 DCHECK(!ran_);
729 allow_file_uploads_ = true;
730 }
set_upload_files_invalid(bool upload_files_invalid)731 void set_upload_files_invalid(bool upload_files_invalid) {
732 DCHECK(!ran_);
733 upload_files_invalid_ = upload_files_invalid;
734 }
set_ignore_last_upload_file(bool ignore_last_upload_file)735 void set_ignore_last_upload_file(bool ignore_last_upload_file) {
736 DCHECK(!ran_);
737 ignore_last_upload_file_ = ignore_last_upload_file;
738 }
set_sniff()739 void set_sniff() {
740 DCHECK(!ran_);
741 sniff_ = true;
742 }
set_send_ssl_with_response()743 void set_send_ssl_with_response() {
744 DCHECK(!ran_);
745 send_ssl_with_response_ = true;
746 }
set_send_ssl_for_cert_error()747 void set_send_ssl_for_cert_error() {
748 DCHECK(!ran_);
749 send_ssl_for_cert_error_ = true;
750 }
set_expect_redirect()751 void set_expect_redirect() {
752 DCHECK(!ran_);
753 expect_redirect_ = true;
754 }
set_factory_client_security_state(mojom::ClientSecurityStatePtr state)755 void set_factory_client_security_state(mojom::ClientSecurityStatePtr state) {
756 factory_client_security_state_ = std::move(state);
757 }
set_request_client_security_state(mojom::ClientSecurityStatePtr state)758 void set_request_client_security_state(mojom::ClientSecurityStatePtr state) {
759 request_client_security_state_ = std::move(state);
760 }
set_request_body(scoped_refptr<ResourceRequestBody> request_body)761 void set_request_body(scoped_refptr<ResourceRequestBody> request_body) {
762 request_body_ = request_body;
763 }
764
765 // Convenience methods after calling Load();
mime_type() const766 std::string mime_type() const {
767 DCHECK(ran_);
768 return client_.response_head()->mime_type;
769 }
770
did_mime_sniff() const771 bool did_mime_sniff() const {
772 DCHECK(ran_);
773 return client_.response_head()->did_mime_sniff;
774 }
775
ssl_info() const776 const base::Optional<net::SSLInfo>& ssl_info() const {
777 DCHECK(ran_);
778 return client_.ssl_info();
779 }
780
781 // Reads the response body from client()->response_body() until the channel is
782 // closed. Expects client()->response_body() to already be populated, and
783 // non-NULL.
ReadBody()784 std::string ReadBody() {
785 std::string body;
786 while (true) {
787 MojoHandle consumer = client()->response_body().value();
788
789 const void* buffer;
790 uint32_t num_bytes;
791 MojoResult rv = MojoBeginReadData(consumer, nullptr, &buffer, &num_bytes);
792 // If no data has been received yet, spin the message loop until it has.
793 if (rv == MOJO_RESULT_SHOULD_WAIT) {
794 mojo::SimpleWatcher watcher(
795 FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC,
796 base::SequencedTaskRunnerHandle::Get());
797 base::RunLoop run_loop;
798
799 watcher.Watch(
800 client()->response_body(),
801 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
802 MOJO_WATCH_CONDITION_SATISFIED,
803 base::BindRepeating(
804 [](base::RepeatingClosure quit, MojoResult result,
805 const mojo::HandleSignalsState& state) { quit.Run(); },
806 run_loop.QuitClosure()));
807 run_loop.Run();
808 continue;
809 }
810
811 // The pipe was closed.
812 if (rv == MOJO_RESULT_FAILED_PRECONDITION)
813 return body;
814
815 CHECK_EQ(rv, MOJO_RESULT_OK);
816
817 body.append(static_cast<const char*>(buffer), num_bytes);
818 MojoEndReadData(consumer, num_bytes, nullptr);
819 }
820
821 return body;
822 }
823
ReadAvailableBody()824 std::string ReadAvailableBody() {
825 MojoHandle consumer = client()->response_body().value();
826
827 uint32_t num_bytes = 0;
828 MojoReadDataOptions options;
829 options.struct_size = sizeof(options);
830 options.flags = MOJO_READ_DATA_FLAG_QUERY;
831 MojoResult result = MojoReadData(consumer, &options, nullptr, &num_bytes);
832 CHECK_EQ(MOJO_RESULT_OK, result);
833 if (num_bytes == 0)
834 return std::string();
835
836 std::vector<char> buffer(num_bytes);
837 result = MojoReadData(consumer, nullptr, buffer.data(), &num_bytes);
838 CHECK_EQ(MOJO_RESULT_OK, result);
839 CHECK_EQ(num_bytes, buffer.size());
840
841 return std::string(buffer.data(), buffer.size());
842 }
843
sent_request() const844 const net::test_server::HttpRequest& sent_request() const {
845 return sent_request_;
846 }
847
test_network_delegate()848 net::TestNetworkDelegate* test_network_delegate() {
849 return unowned_test_network_delegate_;
850 }
851
RunUntilIdle()852 void RunUntilIdle() { task_environment_.RunUntilIdle(); }
853
854 static constexpr int kProcessId = 4;
855 static constexpr int kRouteId = 8;
856
857 // |OnServerReceivedRequest| allows subclasses to register additional logic to
858 // execute once a request reaches the test server.
OnServerReceivedRequest(const net::test_server::HttpRequest &)859 virtual void OnServerReceivedRequest(const net::test_server::HttpRequest&) {}
860
861 protected:
Monitor(const net::test_server::HttpRequest & request)862 void Monitor(const net::test_server::HttpRequest& request) {
863 sent_request_ = request;
864 OnServerReceivedRequest(request);
865 }
866
867 base::test::TaskEnvironment task_environment_;
868 net::EmbeddedTestServer test_server_;
869 std::unique_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_;
870 net::TestNetworkDelegate*
871 unowned_test_network_delegate_; // owned by |context_|
872 std::unique_ptr<net::URLRequestContext> context_;
873 ResourceScheduler resource_scheduler_;
874 scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
875
876 // Options applied to the created request in Load().
877 bool allow_file_uploads_ = false;
878 bool upload_files_invalid_ = false;
879 bool ignore_last_upload_file_ = false;
880 bool sniff_ = false;
881 bool send_ssl_with_response_ = false;
882 bool send_ssl_for_cert_error_ = false;
883 bool expect_redirect_ = false;
884 mojom::ClientSecurityStatePtr factory_client_security_state_;
885 mojom::ClientSecurityStatePtr request_client_security_state_;
886 scoped_refptr<ResourceRequestBody> request_body_;
887
888 // Used to ensure that methods are called either before or after a request is
889 // made, since the test fixture is meant to be used only once.
890 bool ran_ = false;
891 net::test_server::HttpRequest sent_request_;
892 TestURLLoaderClient client_;
893 };
894
895 constexpr int URLLoaderTest::kProcessId;
896 constexpr int URLLoaderTest::kRouteId;
897
TEST_F(URLLoaderTest,Basic)898 TEST_F(URLLoaderTest, Basic) {
899 LoadAndCompareFile("simple_page.html");
900 }
901
TEST_F(URLLoaderTest,Empty)902 TEST_F(URLLoaderTest, Empty) {
903 LoadAndCompareFile("empty.html");
904 }
905
TEST_F(URLLoaderTest,BasicSSL)906 TEST_F(URLLoaderTest, BasicSSL) {
907 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
908 https_server.ServeFilesFromSourceDirectory(
909 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
910 ASSERT_TRUE(https_server.Start());
911
912 GURL url = https_server.GetURL("/simple_page.html");
913 set_send_ssl_with_response();
914 EXPECT_EQ(net::OK, Load(url));
915 ASSERT_TRUE(!!ssl_info());
916 ASSERT_TRUE(!!ssl_info()->cert);
917
918 ASSERT_TRUE(https_server.GetCertificate()->EqualsExcludingChain(
919 ssl_info()->cert.get()));
920 }
921
TEST_F(URLLoaderTest,SSLSentOnlyWhenRequested)922 TEST_F(URLLoaderTest, SSLSentOnlyWhenRequested) {
923 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
924 https_server.ServeFilesFromSourceDirectory(
925 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
926 ASSERT_TRUE(https_server.Start());
927
928 GURL url = https_server.GetURL("/simple_page.html");
929 EXPECT_EQ(net::OK, Load(url));
930 ASSERT_FALSE(!!ssl_info());
931 }
932
933 // This test verifies that when the URLLoaderFactory's parameters are missing
934 // a client security state, requests to local network resources are authorized.
TEST_F(URLLoaderTest,MissingClientSecurityStateIsOk)935 TEST_F(URLLoaderTest, MissingClientSecurityStateIsOk) {
936 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
937 }
938
939 // These tests verify that requests from an secure page to an IP in the
940 // "local" address space are never blocked.
941
TEST_F(URLLoaderTest,SecureUnknownToLocalIsOk)942 TEST_F(URLLoaderTest, SecureUnknownToLocalIsOk) {
943 auto client_security_state = NewSecurityState();
944 client_security_state->is_web_secure_context = true;
945 client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
946 set_factory_client_security_state(std::move(client_security_state));
947
948 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
949 }
950
TEST_F(URLLoaderTest,SecurePublicToLocalIsOk)951 TEST_F(URLLoaderTest, SecurePublicToLocalIsOk) {
952 auto client_security_state = NewSecurityState();
953 client_security_state->is_web_secure_context = true;
954 client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
955 set_factory_client_security_state(std::move(client_security_state));
956
957 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
958 }
959
TEST_F(URLLoaderTest,SecurePrivateToLocalIsBlocked)960 TEST_F(URLLoaderTest, SecurePrivateToLocalIsBlocked) {
961 auto client_security_state = NewSecurityState();
962 client_security_state->is_web_secure_context = true;
963 client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
964 set_factory_client_security_state(std::move(client_security_state));
965
966 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
967 }
968
TEST_F(URLLoaderTest,SecureLocalToLocalIsOk)969 TEST_F(URLLoaderTest, SecureLocalToLocalIsOk) {
970 auto client_security_state = NewSecurityState();
971 client_security_state->is_web_secure_context = true;
972 client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
973 set_factory_client_security_state(std::move(client_security_state));
974
975 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
976 }
977
978 // These tests verify that requests from any page to an IP in the "local"
979 // address space are never blocked when the request policy is kAllow.
980
TEST_F(URLLoaderTest,PolicyIsAllowUnknownToLocalIsOk)981 TEST_F(URLLoaderTest, PolicyIsAllowUnknownToLocalIsOk) {
982 auto client_security_state = NewSecurityState();
983 client_security_state->private_network_request_policy =
984 mojom::PrivateNetworkRequestPolicy::kAllow;
985 client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
986 set_factory_client_security_state(std::move(client_security_state));
987
988 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
989 }
990
TEST_F(URLLoaderTest,PolicyIsAllowPublicToLocalIsOk)991 TEST_F(URLLoaderTest, PolicyIsAllowPublicToLocalIsOk) {
992 auto client_security_state = NewSecurityState();
993 client_security_state->private_network_request_policy =
994 mojom::PrivateNetworkRequestPolicy::kAllow;
995 client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
996 set_factory_client_security_state(std::move(client_security_state));
997
998 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
999 }
1000
TEST_F(URLLoaderTest,PolicyIsAllowPrivateToLocalIsBlocked)1001 TEST_F(URLLoaderTest, PolicyIsAllowPrivateToLocalIsBlocked) {
1002 auto client_security_state = NewSecurityState();
1003 client_security_state->private_network_request_policy =
1004 mojom::PrivateNetworkRequestPolicy::kAllow;
1005 client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
1006 set_factory_client_security_state(std::move(client_security_state));
1007
1008 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
1009 }
1010
TEST_F(URLLoaderTest,PolicyIsAllowLocalToLocalIsOk)1011 TEST_F(URLLoaderTest, PolicyIsAllowLocalToLocalIsOk) {
1012 auto client_security_state = NewSecurityState();
1013 client_security_state->private_network_request_policy =
1014 mojom::PrivateNetworkRequestPolicy::kAllow;
1015 client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
1016 set_factory_client_security_state(std::move(client_security_state));
1017
1018 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
1019 }
1020
1021 // These tests verify that requests from an insecure page to an IP in the
1022 // "local" address space are blocked unless the page came from the same address
1023 // space. In practice, the local address space contains only localhost.
1024 //
1025 // NOTE: These tests exercise the same codepath as
1026 // URLLoaderFakeTransportInfoTest below, except they use real URLRequestJob and
1027 // HttpTransaction implementations for higher confidence in the correctness of
1028 // the whole stack. OTOH, using an embedded test server prevents us from mocking
1029 // out the endpoint IP address.
1030
TEST_F(URLLoaderTest,InsecureRequestToLocalResource)1031 TEST_F(URLLoaderTest, InsecureRequestToLocalResource) {
1032 auto client_security_state = NewSecurityState();
1033 client_security_state->is_web_secure_context = false;
1034 client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
1035 set_factory_client_security_state(std::move(client_security_state));
1036
1037 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
1038 IsError(net::ERR_FAILED));
1039 EXPECT_THAT(client()->completion_status().cors_error_status,
1040 Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
1041 }
1042
TEST_F(URLLoaderTest,InsecurePublicToLocalIsBlocked)1043 TEST_F(URLLoaderTest, InsecurePublicToLocalIsBlocked) {
1044 auto client_security_state = NewSecurityState();
1045 client_security_state->is_web_secure_context = false;
1046 client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
1047 set_factory_client_security_state(std::move(client_security_state));
1048
1049 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
1050 IsError(net::ERR_FAILED));
1051 EXPECT_THAT(client()->completion_status().cors_error_status,
1052 Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
1053 }
1054
TEST_F(URLLoaderTest,InsecurePrivateToLocalIsBlocked)1055 TEST_F(URLLoaderTest, InsecurePrivateToLocalIsBlocked) {
1056 auto client_security_state = NewSecurityState();
1057 client_security_state->is_web_secure_context = false;
1058 client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
1059 set_factory_client_security_state(std::move(client_security_state));
1060
1061 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
1062 IsError(net::ERR_FAILED));
1063 EXPECT_THAT(client()->completion_status().cors_error_status,
1064 Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
1065 }
1066
TEST_F(URLLoaderTest,InsecureLocalToLocalIsOk)1067 TEST_F(URLLoaderTest, InsecureLocalToLocalIsOk) {
1068 auto client_security_state = NewSecurityState();
1069 client_security_state->is_web_secure_context = false;
1070 client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
1071 set_factory_client_security_state(std::move(client_security_state));
1072
1073 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
1074 }
1075
1076 // This test verifies that if the request's TrustedParams field carries a client
1077 // security state indicating that the request initiator is not a secure context
1078 // and came from the public IP address space, requests to local IP addresses
1079 // are blocked.
TEST_F(URLLoaderTest,TrustedParamsInsecurePublicToLocalIsBlocked)1080 TEST_F(URLLoaderTest, TrustedParamsInsecurePublicToLocalIsBlocked) {
1081 auto client_security_state = NewSecurityState();
1082 client_security_state->is_web_secure_context = false;
1083 client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
1084 set_request_client_security_state(std::move(client_security_state));
1085
1086 EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
1087 IsError(net::ERR_FAILED));
1088 EXPECT_THAT(client()->completion_status().cors_error_status,
1089 Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
1090 }
1091
1092 // Bundles together the inputs to a parameterized private network request test.
1093 struct URLLoaderFakeTransportInfoTestParams {
1094 // The address space of the client.
1095 mojom::IPAddressSpace client_address_space;
1096
1097 // The address space of the endpoint serving the request.
1098 mojom::IPAddressSpace endpoint_address_space;
1099
1100 // The expected request result.
1101 int expected_result;
1102 };
1103
1104 // For clarity when debugging parameterized test failures.
operator <<(std::ostream & out,const URLLoaderFakeTransportInfoTestParams & params)1105 std::ostream& operator<<(std::ostream& out,
1106 const URLLoaderFakeTransportInfoTestParams& params) {
1107 return out << "{ client_address_space: " << params.client_address_space
1108 << ", endpoint_address_space: " << params.endpoint_address_space
1109 << ", expected_result: "
1110 << net::ErrorToString(params.expected_result) << " }";
1111 }
1112
1113 class URLLoaderFakeTransportInfoTest
1114 : public URLLoaderTest,
1115 public testing::WithParamInterface<URLLoaderFakeTransportInfoTestParams> {
1116 protected:
1117 // Returns an address in the given IP address space.
FakeAddress(mojom::IPAddressSpace space)1118 static net::IPAddress FakeAddress(mojom::IPAddressSpace space) {
1119 switch (space) {
1120 case mojom::IPAddressSpace::kUnknown:
1121 return net::IPAddress();
1122 case mojom::IPAddressSpace::kPublic:
1123 return net::IPAddress(42, 0, 1, 2);
1124 case mojom::IPAddressSpace::kPrivate:
1125 return net::IPAddress(10, 0, 1, 2);
1126 case mojom::IPAddressSpace::kLocal:
1127 return net::IPAddress::IPv4Localhost();
1128 }
1129 }
1130
1131 // Returns an endpoint in the given IP address space.
FakeEndpoint(mojom::IPAddressSpace space)1132 static net::IPEndPoint FakeEndpoint(mojom::IPAddressSpace space) {
1133 return net::IPEndPoint(FakeAddress(space), 80);
1134 }
1135
1136 // Returns a transport info with an endpoint in the given IP address space.
FakeTransportInfo(mojom::IPAddressSpace space)1137 static net::TransportInfo FakeTransportInfo(mojom::IPAddressSpace space) {
1138 return net::TransportInfo(net::TransportType::kDirect, FakeEndpoint(space));
1139 }
1140 };
1141
1142 // This test verifies that requests made from insecure contexts are handled
1143 // appropriately when they go from a less-private address space to a
1144 // more-private address space or not. The test is parameterized by
1145 // (client address space, server address space, expected result) tuple.
TEST_P(URLLoaderFakeTransportInfoTest,PrivateNetworkRequestLoadsCorrectly)1146 TEST_P(URLLoaderFakeTransportInfoTest, PrivateNetworkRequestLoadsCorrectly) {
1147 const auto params = GetParam();
1148
1149 auto client_security_state = NewSecurityState();
1150 client_security_state->ip_address_space = params.client_address_space;
1151 set_factory_client_security_state(std::move(client_security_state));
1152
1153 const GURL url("http://fake-endpoint");
1154
1155 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
1156 url, std::make_unique<FakeTransportInfoInterceptor>(
1157 FakeTransportInfo(params.endpoint_address_space)));
1158
1159 // Despite its name, IsError(OK) asserts that the matched value is OK.
1160 EXPECT_THAT(Load(url), IsError(params.expected_result));
1161 if (params.expected_result != net::OK) {
1162 EXPECT_THAT(client()->completion_status().cors_error_status,
1163 Optional(CorsErrorStatus(params.endpoint_address_space)));
1164 }
1165 }
1166
1167 // Lists all combinations we want to test in URLLoaderFakeTransportInfoTest.
1168 constexpr URLLoaderFakeTransportInfoTestParams
1169 kURLLoaderFakeTransportInfoTestParamsList[] = {
1170 // Client: kUnknown
1171 {
1172 mojom::IPAddressSpace::kUnknown,
1173 mojom::IPAddressSpace::kUnknown,
1174 net::OK,
1175 },
1176 {
1177 mojom::IPAddressSpace::kUnknown,
1178 mojom::IPAddressSpace::kPublic,
1179 net::OK,
1180 },
1181 {
1182 mojom::IPAddressSpace::kUnknown,
1183 mojom::IPAddressSpace::kPrivate,
1184 net::ERR_FAILED,
1185 },
1186 {
1187 mojom::IPAddressSpace::kUnknown,
1188 mojom::IPAddressSpace::kLocal,
1189 net::ERR_FAILED,
1190 },
1191 // Client: kPublic
1192 {
1193 mojom::IPAddressSpace::kPublic,
1194 mojom::IPAddressSpace::kUnknown,
1195 net::OK,
1196 },
1197 {
1198 mojom::IPAddressSpace::kPublic,
1199 mojom::IPAddressSpace::kPublic,
1200 net::OK,
1201 },
1202 {
1203 mojom::IPAddressSpace::kPublic,
1204 mojom::IPAddressSpace::kPrivate,
1205 net::ERR_FAILED,
1206 },
1207 {
1208 mojom::IPAddressSpace::kPublic,
1209 mojom::IPAddressSpace::kLocal,
1210 net::ERR_FAILED,
1211 },
1212 // Client: kPrivate
1213 {
1214 mojom::IPAddressSpace::kPrivate,
1215 mojom::IPAddressSpace::kUnknown,
1216 net::OK,
1217 },
1218 {
1219 mojom::IPAddressSpace::kPrivate,
1220 mojom::IPAddressSpace::kPublic,
1221 net::OK,
1222 },
1223 {
1224 mojom::IPAddressSpace::kPrivate,
1225 mojom::IPAddressSpace::kPrivate,
1226 net::OK,
1227 },
1228 {
1229 mojom::IPAddressSpace::kPrivate,
1230 mojom::IPAddressSpace::kLocal,
1231 net::ERR_FAILED,
1232 },
1233 // Client: kLocal
1234 {
1235 mojom::IPAddressSpace::kLocal,
1236 mojom::IPAddressSpace::kUnknown,
1237 net::OK,
1238 },
1239 {
1240 mojom::IPAddressSpace::kLocal,
1241 mojom::IPAddressSpace::kPublic,
1242 net::OK,
1243 },
1244 {
1245 mojom::IPAddressSpace::kLocal,
1246 mojom::IPAddressSpace::kPrivate,
1247 net::OK,
1248 },
1249 {
1250 mojom::IPAddressSpace::kLocal,
1251 mojom::IPAddressSpace::kLocal,
1252 net::OK,
1253 },
1254 };
1255
1256 INSTANTIATE_TEST_SUITE_P(Parameterized,
1257 URLLoaderFakeTransportInfoTest,
1258 ValuesIn(kURLLoaderFakeTransportInfoTestParamsList));
1259
1260 // Tests that auth challenge info is present on the response when a request
1261 // receives an authentication challenge.
TEST_F(URLLoaderTest,AuthChallengeInfo)1262 TEST_F(URLLoaderTest, AuthChallengeInfo) {
1263 GURL url = test_server()->GetURL("/auth-basic");
1264 EXPECT_EQ(net::OK, Load(url));
1265 ASSERT_TRUE(client()->response_head()->auth_challenge_info.has_value());
1266 EXPECT_FALSE(client()->response_head()->auth_challenge_info->is_proxy);
1267 EXPECT_EQ(url::Origin::Create(url),
1268 client()->response_head()->auth_challenge_info->challenger);
1269 EXPECT_EQ("basic", client()->response_head()->auth_challenge_info->scheme);
1270 EXPECT_EQ("testrealm", client()->response_head()->auth_challenge_info->realm);
1271 EXPECT_EQ("Basic realm=\"testrealm\"",
1272 client()->response_head()->auth_challenge_info->challenge);
1273 EXPECT_EQ("/auth-basic",
1274 client()->response_head()->auth_challenge_info->path);
1275 }
1276
1277 // Tests that no auth challenge info is present on the response when a request
1278 // does not receive an authentication challenge.
TEST_F(URLLoaderTest,NoAuthChallengeInfo)1279 TEST_F(URLLoaderTest, NoAuthChallengeInfo) {
1280 GURL url = test_server()->GetURL("/");
1281 EXPECT_EQ(net::OK, Load(url));
1282 EXPECT_FALSE(client()->response_head()->auth_challenge_info.has_value());
1283 }
1284
1285 // Test decoded_body_length / encoded_body_length when they're different.
TEST_F(URLLoaderTest,GzipTest)1286 TEST_F(URLLoaderTest, GzipTest) {
1287 std::string body;
1288 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/gzip-body?Body"), &body));
1289 EXPECT_EQ("Body", body);
1290 // Deflating a 4-byte string should result in a longer string - main thing to
1291 // check here, though, is that the two lengths are of different.
1292 EXPECT_LT(client()->completion_status().decoded_body_length,
1293 client()->completion_status().encoded_body_length);
1294 // Over the wire length should include headers, so should be longer.
1295 EXPECT_LT(client()->completion_status().encoded_body_length,
1296 client()->completion_status().encoded_data_length);
1297 }
1298
TEST_F(URLLoaderTest,ErrorBeforeHeaders)1299 TEST_F(URLLoaderTest, ErrorBeforeHeaders) {
1300 EXPECT_EQ(net::ERR_EMPTY_RESPONSE,
1301 Load(test_server()->GetURL("/close-socket"), nullptr));
1302 EXPECT_FALSE(client()->response_body().is_valid());
1303 }
1304
TEST_F(URLLoaderTest,SyncErrorWhileReadingBody)1305 TEST_F(URLLoaderTest, SyncErrorWhileReadingBody) {
1306 std::string body;
1307 EXPECT_EQ(net::ERR_FAILED,
1308 Load(net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
1309 net::URLRequestFailedJob::READ_SYNC, net::ERR_FAILED),
1310 &body));
1311 EXPECT_EQ("", body);
1312 }
1313
TEST_F(URLLoaderTest,AsyncErrorWhileReadingBody)1314 TEST_F(URLLoaderTest, AsyncErrorWhileReadingBody) {
1315 std::string body;
1316 EXPECT_EQ(net::ERR_FAILED,
1317 Load(net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
1318 net::URLRequestFailedJob::READ_ASYNC, net::ERR_FAILED),
1319 &body));
1320 EXPECT_EQ("", body);
1321 }
1322
TEST_F(URLLoaderTest,SyncErrorWhileReadingBodyAfterBytesReceived)1323 TEST_F(URLLoaderTest, SyncErrorWhileReadingBodyAfterBytesReceived) {
1324 const std::string kBody("Foo.");
1325
1326 std::list<std::string> packets;
1327 packets.push_back(kBody);
1328 AddMultipleWritesInterceptor(packets, net::ERR_ACCESS_DENIED,
1329 false /*async_reads*/);
1330 std::string body;
1331 EXPECT_EQ(net::ERR_ACCESS_DENIED,
1332 Load(MultipleWritesInterceptor::GetURL(), &body));
1333 EXPECT_EQ(kBody, body);
1334 }
1335
TEST_F(URLLoaderTest,AsyncErrorWhileReadingBodyAfterBytesReceived)1336 TEST_F(URLLoaderTest, AsyncErrorWhileReadingBodyAfterBytesReceived) {
1337 const std::string kBody("Foo.");
1338
1339 std::list<std::string> packets;
1340 packets.push_back(kBody);
1341 AddMultipleWritesInterceptor(packets, net::ERR_ACCESS_DENIED,
1342 true /*async_reads*/);
1343 std::string body;
1344 EXPECT_EQ(net::ERR_ACCESS_DENIED,
1345 Load(MultipleWritesInterceptor::GetURL(), &body));
1346 EXPECT_EQ(kBody, body);
1347 }
1348
TEST_F(URLLoaderTest,DoNotSniffUnlessSpecified)1349 TEST_F(URLLoaderTest, DoNotSniffUnlessSpecified) {
1350 EXPECT_EQ(net::OK,
1351 Load(test_server()->GetURL("/content-sniffer-test0.html")));
1352 EXPECT_FALSE(did_mime_sniff());
1353 ASSERT_TRUE(mime_type().empty());
1354 }
1355
TEST_F(URLLoaderTest,SniffMimeType)1356 TEST_F(URLLoaderTest, SniffMimeType) {
1357 set_sniff();
1358 EXPECT_EQ(net::OK,
1359 Load(test_server()->GetURL("/content-sniffer-test0.html")));
1360 EXPECT_TRUE(did_mime_sniff());
1361 ASSERT_EQ(std::string("text/html"), mime_type());
1362 }
1363
TEST_F(URLLoaderTest,RespectNoSniff)1364 TEST_F(URLLoaderTest, RespectNoSniff) {
1365 set_sniff();
1366 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/nosniff-test.html")));
1367 EXPECT_FALSE(did_mime_sniff());
1368 ASSERT_EQ(std::string("text/plain"), mime_type());
1369 }
1370
TEST_F(URLLoaderTest,SniffTextPlainDoesNotResultInHTML)1371 TEST_F(URLLoaderTest, SniffTextPlainDoesNotResultInHTML) {
1372 set_sniff();
1373 EXPECT_EQ(net::OK,
1374 Load(test_server()->GetURL("/content-sniffer-test1.html")));
1375 EXPECT_TRUE(did_mime_sniff());
1376 ASSERT_EQ(std::string("text/plain"), mime_type());
1377 }
1378
TEST_F(URLLoaderTest,DoNotSniffHTMLFromImageGIF)1379 TEST_F(URLLoaderTest, DoNotSniffHTMLFromImageGIF) {
1380 set_sniff();
1381 EXPECT_EQ(net::OK,
1382 Load(test_server()->GetURL("/content-sniffer-test2.html")));
1383 EXPECT_FALSE(did_mime_sniff());
1384 ASSERT_EQ(std::string("image/gif"), mime_type());
1385 }
1386
TEST_F(URLLoaderTest,EmptyHtmlIsTextPlain)1387 TEST_F(URLLoaderTest, EmptyHtmlIsTextPlain) {
1388 set_sniff();
1389 EXPECT_EQ(net::OK,
1390 Load(test_server()->GetURL("/content-sniffer-test4.html")));
1391 EXPECT_TRUE(did_mime_sniff());
1392 ASSERT_EQ(std::string("text/plain"), mime_type());
1393 }
1394
TEST_F(URLLoaderTest,EmptyHtmlIsTextPlainWithAsyncResponse)1395 TEST_F(URLLoaderTest, EmptyHtmlIsTextPlainWithAsyncResponse) {
1396 set_sniff();
1397
1398 const std::string kBody;
1399
1400 std::list<std::string> packets;
1401 packets.push_back(kBody);
1402 AddMultipleWritesInterceptor(packets, net::OK, true /*async_reads*/);
1403
1404 std::string body;
1405 EXPECT_EQ(net::OK, Load(MultipleWritesInterceptor::GetURL(), &body));
1406 EXPECT_EQ(kBody, body);
1407 EXPECT_TRUE(did_mime_sniff());
1408 ASSERT_EQ(std::string("text/plain"), mime_type());
1409 }
1410
1411 // Tests the case where the first read doesn't have enough data to figure out
1412 // the right mime type. The second read would have enough data even though the
1413 // total bytes is still smaller than net::kMaxBytesToSniff.
TEST_F(URLLoaderTest,FirstReadNotEnoughToSniff1)1414 TEST_F(URLLoaderTest, FirstReadNotEnoughToSniff1) {
1415 set_sniff();
1416 std::string first(500, 'a');
1417 std::string second(std::string(100, 'b'));
1418 second[10] = 0;
1419 EXPECT_LE(first.size() + second.size(),
1420 static_cast<uint32_t>(net::kMaxBytesToSniff));
1421 LoadPacketsAndVerifyContents(first, second);
1422 EXPECT_TRUE(did_mime_sniff());
1423 ASSERT_EQ(std::string("application/octet-stream"), mime_type());
1424 }
1425
1426 // Like above, except that the total byte count is > kMaxBytesToSniff.
TEST_F(URLLoaderTest,FirstReadNotEnoughToSniff2)1427 TEST_F(URLLoaderTest, FirstReadNotEnoughToSniff2) {
1428 set_sniff();
1429 std::string first(500, 'a');
1430 std::string second(std::string(1000, 'b'));
1431 second[10] = 0;
1432 EXPECT_GE(first.size() + second.size(),
1433 static_cast<uint32_t>(net::kMaxBytesToSniff));
1434 LoadPacketsAndVerifyContents(first, second);
1435 EXPECT_TRUE(did_mime_sniff());
1436 ASSERT_EQ(std::string("application/octet-stream"), mime_type());
1437 }
1438
1439 // Tests that even if the first and only read is smaller than the minimum number
1440 // of bytes needed to sniff, the loader works correctly and returns the data.
TEST_F(URLLoaderTest,LoneReadNotEnoughToSniff)1441 TEST_F(URLLoaderTest, LoneReadNotEnoughToSniff) {
1442 set_sniff();
1443 std::string first(net::kMaxBytesToSniff - 100, 'a');
1444 LoadPacketsAndVerifyContents(first, std::string());
1445 EXPECT_TRUE(did_mime_sniff());
1446 ASSERT_EQ(std::string("text/plain"), mime_type());
1447 }
1448
1449 // Tests the simple case where the first read is enough to sniff.
TEST_F(URLLoaderTest,FirstReadIsEnoughToSniff)1450 TEST_F(URLLoaderTest, FirstReadIsEnoughToSniff) {
1451 set_sniff();
1452 std::string first(net::kMaxBytesToSniff + 100, 'a');
1453 LoadPacketsAndVerifyContents(first, std::string());
1454 EXPECT_TRUE(did_mime_sniff());
1455 ASSERT_EQ(std::string("text/plain"), mime_type());
1456 }
1457
1458 class NeverFinishedBodyHttpResponse : public net::test_server::HttpResponse {
1459 public:
1460 NeverFinishedBodyHttpResponse() = default;
1461 ~NeverFinishedBodyHttpResponse() override = default;
1462
1463 private:
1464 // net::test_server::HttpResponse implementation.
SendResponse(const net::test_server::SendBytesCallback & send,net::test_server::SendCompleteCallback done)1465 void SendResponse(const net::test_server::SendBytesCallback& send,
1466 net::test_server::SendCompleteCallback done) override {
1467 send.Run(
1468 "HTTP/1.1 200 OK\r\n"
1469 "Content-Type: text/plain\r\n\r\n"
1470 "long long ago..." +
1471 std::string(1024 * 1024, 'a'),
1472 base::DoNothing());
1473
1474 // Never call |done|, so the other side will never see the completion of the
1475 // response body.
1476 }
1477 };
1478
1479 // Check that the URLLoader tears itself down when the URLLoader pipe is closed.
TEST_F(URLLoaderTest,DestroyOnURLLoaderPipeClosed)1480 TEST_F(URLLoaderTest, DestroyOnURLLoaderPipeClosed) {
1481 net::EmbeddedTestServer server;
1482 server.RegisterRequestHandler(
1483 base::BindRepeating([](const net::test_server::HttpRequest& request) {
1484 std::unique_ptr<net::test_server::HttpResponse> response =
1485 std::make_unique<NeverFinishedBodyHttpResponse>();
1486 return response;
1487 }));
1488 ASSERT_TRUE(server.Start());
1489
1490 ResourceRequest request =
1491 CreateResourceRequest("GET", server.GetURL("/hello.html"));
1492
1493 base::RunLoop delete_run_loop;
1494 mojo::PendingRemote<mojom::URLLoader> loader;
1495 std::unique_ptr<URLLoader> url_loader;
1496 mojom::URLLoaderFactoryParams params;
1497 params.process_id = mojom::kBrowserProcessId;
1498 params.is_corb_enabled = false;
1499 url_loader = std::make_unique<URLLoader>(
1500 context(), nullptr /* network_service_client */,
1501 nullptr /* network_context_client */,
1502 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1503 loader.InitWithNewPipeAndPassReceiver(), 0, request,
1504 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
1505 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
1506 /*coep_reporter=*/nullptr, 0 /* request_id */,
1507 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1508 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1509 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1510 mojo::NullRemote() /* cookie_observer */);
1511
1512 // Run until the response body pipe arrives, to make sure that a live body
1513 // pipe does not result in keeping the loader alive when the URLLoader pipe is
1514 // closed.
1515 client()->RunUntilResponseBodyArrived();
1516 EXPECT_TRUE(client()->has_received_response());
1517 EXPECT_FALSE(client()->has_received_completion());
1518
1519 loader.reset();
1520
1521 // Spin the message loop until the delete callback is invoked, and then delete
1522 // the URLLoader.
1523 delete_run_loop.Run();
1524
1525 // client()->RunUntilConnectionError();
1526 // EXPECT_FALSE(client()->has_received_completion());
1527 client()->RunUntilComplete();
1528 EXPECT_EQ(net::ERR_FAILED, client()->completion_status().error_code);
1529 }
1530
1531 // Make sure that the URLLoader is destroyed when the data pipe is closed.
1532 // The pipe may either be closed in
1533 // URLLoader::OnResponseBodyStreamConsumerClosed() or URLLoader::DidRead(),
1534 // depending on whether the closed pipe is first noticed when trying to write to
1535 // it, or when a mojo close notification is received, so if only one path
1536 // breaks, this test may flakily fail.
TEST_F(URLLoaderTest,CloseResponseBodyConsumerBeforeProducer)1537 TEST_F(URLLoaderTest, CloseResponseBodyConsumerBeforeProducer) {
1538 net::EmbeddedTestServer server;
1539 server.RegisterRequestHandler(
1540 base::BindRepeating([](const net::test_server::HttpRequest& request) {
1541 std::unique_ptr<net::test_server::HttpResponse> response =
1542 std::make_unique<NeverFinishedBodyHttpResponse>();
1543 return response;
1544 }));
1545 ASSERT_TRUE(server.Start());
1546
1547 ResourceRequest request =
1548 CreateResourceRequest("GET", server.GetURL("/hello.html"));
1549
1550 base::RunLoop delete_run_loop;
1551 mojo::PendingRemote<mojom::URLLoader> loader;
1552 std::unique_ptr<URLLoader> url_loader;
1553 mojom::URLLoaderFactoryParams params;
1554 params.process_id = mojom::kBrowserProcessId;
1555 params.is_corb_enabled = false;
1556 url_loader = std::make_unique<URLLoader>(
1557 context(), nullptr /* network_service_client */,
1558 nullptr /* network_context_client */,
1559 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1560 loader.InitWithNewPipeAndPassReceiver(), 0, request,
1561 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
1562 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
1563 /*coep_reporter=*/nullptr, 0 /* request_id */,
1564 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1565 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1566 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1567 mojo::NullRemote() /* cookie_observer */);
1568
1569 client()->RunUntilResponseBodyArrived();
1570 EXPECT_TRUE(client()->has_received_response());
1571 EXPECT_FALSE(client()->has_received_completion());
1572
1573 // Wait for a little amount of time for the response body pipe to be filled.
1574 // (Please note that this doesn't guarantee that the pipe is filled to the
1575 // point that it is not writable anymore.)
1576 base::RunLoop run_loop;
1577 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1578 FROM_HERE, run_loop.QuitClosure(),
1579 base::TimeDelta::FromMilliseconds(100));
1580 run_loop.Run();
1581
1582 auto response_body = client()->response_body_release();
1583 response_body.reset();
1584
1585 // Spin the message loop until the delete callback is invoked, and then delete
1586 // the URLLoader.
1587 delete_run_loop.Run();
1588
1589 client()->RunUntilComplete();
1590 EXPECT_EQ(net::ERR_FAILED, client()->completion_status().error_code);
1591 }
1592
TEST_F(URLLoaderTest,PauseReadingBodyFromNetBeforeResponseHeaders)1593 TEST_F(URLLoaderTest, PauseReadingBodyFromNetBeforeResponseHeaders) {
1594 const char* const kPath = "/hello.html";
1595 const char* const kBodyContents = "This is the data as you requested.";
1596
1597 base::HistogramBase::Sample output_sample = -1;
1598 base::RunLoop histogram_run_loop;
1599 EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
1600 histogram_run_loop.QuitClosure(), &output_sample));
1601
1602 net::EmbeddedTestServer server;
1603 net::test_server::ControllableHttpResponse response_controller(&server,
1604 kPath);
1605 ASSERT_TRUE(server.Start());
1606
1607 ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
1608
1609 base::RunLoop delete_run_loop;
1610 mojo::Remote<mojom::URLLoader> loader;
1611 std::unique_ptr<URLLoader> url_loader;
1612 mojom::URLLoaderFactoryParams params;
1613 params.process_id = mojom::kBrowserProcessId;
1614 params.is_corb_enabled = false;
1615 url_loader = std::make_unique<URLLoader>(
1616 context(), nullptr /* network_service_client */,
1617 nullptr /* network_context_client */,
1618 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1619 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
1620 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
1621 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
1622 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1623 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1624 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1625 mojo::NullRemote() /* cookie_observer */);
1626
1627 // Pausing reading response body from network stops future reads from the
1628 // underlying URLRequest. So no data should be sent using the response body
1629 // data pipe.
1630 loader->PauseReadingBodyFromNet();
1631 // In order to avoid flakiness, make sure PauseReadBodyFromNet() is handled by
1632 // the loader before the test HTTP server serves the response.
1633 loader.FlushForTesting();
1634
1635 response_controller.WaitForRequest();
1636 response_controller.Send(
1637 "HTTP/1.1 200 OK\r\n"
1638 "Content-Type: text/plain\r\n\r\n" +
1639 std::string(kBodyContents));
1640 response_controller.Done();
1641
1642 // We will still receive the response body data pipe, although there won't be
1643 // any data available until ResumeReadBodyFromNet() is called.
1644 client()->RunUntilResponseBodyArrived();
1645 EXPECT_TRUE(client()->has_received_response());
1646 EXPECT_FALSE(client()->has_received_completion());
1647
1648 // Wait for a little amount of time so that if the loader mistakenly reads
1649 // response body from the underlying URLRequest, it is easier to find out.
1650 base::RunLoop run_loop;
1651 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1652 FROM_HERE, run_loop.QuitClosure(),
1653 base::TimeDelta::FromMilliseconds(100));
1654 run_loop.Run();
1655
1656 std::string available_data = ReadAvailableBody();
1657 EXPECT_TRUE(available_data.empty());
1658
1659 loader->ResumeReadingBodyFromNet();
1660 client()->RunUntilComplete();
1661
1662 available_data = ReadBody();
1663 EXPECT_EQ(kBodyContents, available_data);
1664
1665 delete_run_loop.Run();
1666 client()->Unbind();
1667 histogram_run_loop.Run();
1668 EXPECT_EQ(0, output_sample);
1669 StopMonitorBodyReadFromNetBeforePausedHistogram();
1670 }
1671
TEST_F(URLLoaderTest,PauseReadingBodyFromNetWhenReadIsPending)1672 TEST_F(URLLoaderTest, PauseReadingBodyFromNetWhenReadIsPending) {
1673 const char* const kPath = "/hello.html";
1674 const char* const kBodyContentsFirstHalf = "This is the first half.";
1675 const char* const kBodyContentsSecondHalf = "This is the second half.";
1676
1677 base::HistogramBase::Sample output_sample = -1;
1678 base::RunLoop histogram_run_loop;
1679 EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
1680 histogram_run_loop.QuitClosure(), &output_sample));
1681
1682 net::EmbeddedTestServer server;
1683 net::test_server::ControllableHttpResponse response_controller(&server,
1684 kPath);
1685 ASSERT_TRUE(server.Start());
1686
1687 ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
1688
1689 base::RunLoop delete_run_loop;
1690 mojo::Remote<mojom::URLLoader> loader;
1691 std::unique_ptr<URLLoader> url_loader;
1692 mojom::URLLoaderFactoryParams params;
1693 params.process_id = mojom::kBrowserProcessId;
1694 params.is_corb_enabled = false;
1695 url_loader = std::make_unique<URLLoader>(
1696 context(), nullptr /* network_service_client */,
1697 nullptr /* network_context_client */,
1698 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1699 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
1700 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
1701 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
1702 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1703 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1704 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1705 mojo::NullRemote() /* cookie_observer */);
1706
1707 response_controller.WaitForRequest();
1708 response_controller.Send(
1709 "HTTP/1.1 200 OK\r\n"
1710 "Content-Type: text/plain\r\n\r\n" +
1711 std::string(kBodyContentsFirstHalf));
1712
1713 client()->RunUntilResponseBodyArrived();
1714 EXPECT_TRUE(client()->has_received_response());
1715 EXPECT_FALSE(client()->has_received_completion());
1716
1717 loader->PauseReadingBodyFromNet();
1718 loader.FlushForTesting();
1719
1720 response_controller.Send(kBodyContentsSecondHalf);
1721 response_controller.Done();
1722
1723 // It is uncertain how much data has been read before reading is actually
1724 // paused, because if there is a pending read when PauseReadingBodyFromNet()
1725 // arrives, the pending read won't be cancelled. Therefore, this test only
1726 // checks that after ResumeReadingBodyFromNet() we should be able to get the
1727 // whole response body.
1728 loader->ResumeReadingBodyFromNet();
1729 client()->RunUntilComplete();
1730
1731 EXPECT_EQ(std::string(kBodyContentsFirstHalf) +
1732 std::string(kBodyContentsSecondHalf),
1733 ReadBody());
1734
1735 delete_run_loop.Run();
1736 client()->Unbind();
1737 histogram_run_loop.Run();
1738 EXPECT_LE(0, output_sample);
1739 StopMonitorBodyReadFromNetBeforePausedHistogram();
1740 }
1741
TEST_F(URLLoaderTest,ResumeReadingBodyFromNetAfterClosingConsumer)1742 TEST_F(URLLoaderTest, ResumeReadingBodyFromNetAfterClosingConsumer) {
1743 const char* const kPath = "/hello.html";
1744 const char* const kBodyContentsFirstHalf = "This is the first half.";
1745
1746 base::HistogramBase::Sample output_sample = -1;
1747 base::RunLoop histogram_run_loop;
1748 EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
1749 histogram_run_loop.QuitClosure(), &output_sample));
1750
1751 net::EmbeddedTestServer server;
1752 net::test_server::ControllableHttpResponse response_controller(&server,
1753 kPath);
1754 ASSERT_TRUE(server.Start());
1755
1756 ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
1757
1758 base::RunLoop delete_run_loop;
1759 mojo::Remote<mojom::URLLoader> loader;
1760 std::unique_ptr<URLLoader> url_loader;
1761 mojom::URLLoaderFactoryParams params;
1762 params.process_id = mojom::kBrowserProcessId;
1763 params.is_corb_enabled = false;
1764 url_loader = std::make_unique<URLLoader>(
1765 context(), nullptr /* network_service_client */,
1766 nullptr /* network_context_client */,
1767 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1768 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
1769 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
1770 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
1771 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1772 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1773 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1774 mojo::NullRemote() /* cookie_observer */);
1775
1776 loader->PauseReadingBodyFromNet();
1777 loader.FlushForTesting();
1778
1779 response_controller.WaitForRequest();
1780 response_controller.Send(
1781 "HTTP/1.1 200 OK\r\n"
1782 "Content-Type: text/plain\r\n\r\n" +
1783 std::string(kBodyContentsFirstHalf));
1784
1785 client()->RunUntilResponseBodyArrived();
1786 EXPECT_TRUE(client()->has_received_response());
1787 EXPECT_FALSE(client()->has_received_completion());
1788
1789 auto response_body = client()->response_body_release();
1790 response_body.reset();
1791
1792 // It shouldn't cause any issue even if a ResumeReadingBodyFromNet() call is
1793 // made after the response body data pipe is closed.
1794 loader->ResumeReadingBodyFromNet();
1795 loader.FlushForTesting();
1796
1797 loader.reset();
1798 client()->Unbind();
1799 delete_run_loop.Run();
1800 histogram_run_loop.Run();
1801 EXPECT_EQ(0, output_sample);
1802 StopMonitorBodyReadFromNetBeforePausedHistogram();
1803 }
1804
TEST_F(URLLoaderTest,MultiplePauseResumeReadingBodyFromNet)1805 TEST_F(URLLoaderTest, MultiplePauseResumeReadingBodyFromNet) {
1806 const char* const kPath = "/hello.html";
1807 const char* const kBodyContentsFirstHalf = "This is the first half.";
1808 const char* const kBodyContentsSecondHalf = "This is the second half.";
1809
1810 base::HistogramBase::Sample output_sample = -1;
1811 base::RunLoop histogram_run_loop;
1812 EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
1813 histogram_run_loop.QuitClosure(), &output_sample));
1814
1815 net::EmbeddedTestServer server;
1816 net::test_server::ControllableHttpResponse response_controller(&server,
1817 kPath);
1818 ASSERT_TRUE(server.Start());
1819
1820 ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
1821
1822 base::RunLoop delete_run_loop;
1823 mojo::Remote<mojom::URLLoader> loader;
1824 std::unique_ptr<URLLoader> url_loader;
1825 mojom::URLLoaderFactoryParams params;
1826 params.process_id = mojom::kBrowserProcessId;
1827 params.is_corb_enabled = false;
1828 url_loader = std::make_unique<URLLoader>(
1829 context(), nullptr /* network_service_client */,
1830 nullptr /* network_context_client */,
1831 DeleteLoaderCallback(&delete_run_loop, &url_loader),
1832 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
1833 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
1834 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
1835 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
1836 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
1837 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
1838 mojo::NullRemote() /* cookie_observer */);
1839
1840 // It is okay to call ResumeReadingBodyFromNet() even if there is no prior
1841 // PauseReadingBodyFromNet().
1842 loader->ResumeReadingBodyFromNet();
1843 loader.FlushForTesting();
1844
1845 response_controller.WaitForRequest();
1846 response_controller.Send(
1847 "HTTP/1.1 200 OK\r\n"
1848 "Content-Type: text/plain\r\n\r\n" +
1849 std::string(kBodyContentsFirstHalf));
1850
1851 loader->PauseReadingBodyFromNet();
1852
1853 client()->RunUntilResponseBodyArrived();
1854 EXPECT_TRUE(client()->has_received_response());
1855 EXPECT_FALSE(client()->has_received_completion());
1856
1857 loader->PauseReadingBodyFromNet();
1858 loader->PauseReadingBodyFromNet();
1859 loader.FlushForTesting();
1860
1861 response_controller.Send(kBodyContentsSecondHalf);
1862 response_controller.Done();
1863
1864 // One ResumeReadingBodyFromNet() call will resume reading even if there are
1865 // multiple PauseReadingBodyFromNet() calls before it.
1866 loader->ResumeReadingBodyFromNet();
1867
1868 delete_run_loop.Run();
1869 client()->RunUntilComplete();
1870
1871 EXPECT_EQ(std::string(kBodyContentsFirstHalf) +
1872 std::string(kBodyContentsSecondHalf),
1873 ReadBody());
1874
1875 loader.reset();
1876 client()->Unbind();
1877 histogram_run_loop.Run();
1878 EXPECT_LE(0, output_sample);
1879 StopMonitorBodyReadFromNetBeforePausedHistogram();
1880 }
1881
TEST_F(URLLoaderTest,UploadBytes)1882 TEST_F(URLLoaderTest, UploadBytes) {
1883 const std::string kRequestBody = "Request Body";
1884
1885 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1886 request_body->AppendBytes(kRequestBody.c_str(), kRequestBody.length());
1887 set_request_body(std::move(request_body));
1888
1889 std::string response_body;
1890 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
1891 EXPECT_EQ(kRequestBody, response_body);
1892 }
1893
TEST_F(URLLoaderTest,UploadFile)1894 TEST_F(URLLoaderTest, UploadFile) {
1895 allow_file_uploads();
1896 base::FilePath file_path = GetTestFilePath("simple_page.html");
1897
1898 std::string expected_body;
1899 ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
1900 << "File not found: " << file_path.value();
1901
1902 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1903 request_body->AppendFileRange(
1904 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
1905 set_request_body(std::move(request_body));
1906
1907 std::string response_body;
1908 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
1909 EXPECT_EQ(expected_body, response_body);
1910 }
1911
TEST_F(URLLoaderTest,UploadFileWithRange)1912 TEST_F(URLLoaderTest, UploadFileWithRange) {
1913 allow_file_uploads();
1914 base::FilePath file_path = GetTestFilePath("simple_page.html");
1915
1916 std::string expected_body;
1917 ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
1918 << "File not found: " << file_path.value();
1919 expected_body = expected_body.substr(1, expected_body.size() - 2);
1920
1921 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1922 request_body->AppendFileRange(file_path, 1, expected_body.size(),
1923 base::Time());
1924 set_request_body(std::move(request_body));
1925
1926 std::string response_body;
1927 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
1928 EXPECT_EQ(expected_body, response_body);
1929 }
1930
TEST_F(URLLoaderTest,UploadTwoFiles)1931 TEST_F(URLLoaderTest, UploadTwoFiles) {
1932 allow_file_uploads();
1933 base::FilePath file_path1 = GetTestFilePath("simple_page.html");
1934 base::FilePath file_path2 = GetTestFilePath("hello.html");
1935
1936 std::string expected_body1;
1937 std::string expected_body2;
1938 ASSERT_TRUE(base::ReadFileToString(file_path1, &expected_body1))
1939 << "File not found: " << file_path1.value();
1940 ASSERT_TRUE(base::ReadFileToString(file_path2, &expected_body2))
1941 << "File not found: " << file_path2.value();
1942
1943 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1944 request_body->AppendFileRange(
1945 file_path1, 0, std::numeric_limits<uint64_t>::max(), base::Time());
1946 request_body->AppendFileRange(
1947 file_path2, 0, std::numeric_limits<uint64_t>::max(), base::Time());
1948 set_request_body(std::move(request_body));
1949
1950 std::string response_body;
1951 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
1952 EXPECT_EQ(expected_body1 + expected_body2, response_body);
1953 }
1954
TEST_F(URLLoaderTest,UploadTwoBatchesOfFiles)1955 TEST_F(URLLoaderTest, UploadTwoBatchesOfFiles) {
1956 allow_file_uploads();
1957 base::FilePath file_path = GetTestFilePath("simple_page.html");
1958
1959 std::string expected_body;
1960 size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
1961 for (size_t i = 0; i < num_files; ++i) {
1962 std::string tmp_expected_body;
1963 ASSERT_TRUE(base::ReadFileToString(file_path, &tmp_expected_body))
1964 << "File not found: " << file_path.value();
1965 expected_body += tmp_expected_body;
1966 }
1967
1968 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1969 for (size_t i = 0; i < num_files; ++i) {
1970 request_body->AppendFileRange(
1971 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
1972 }
1973 set_request_body(std::move(request_body));
1974
1975 std::string response_body;
1976 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
1977 EXPECT_EQ(expected_body, response_body);
1978 }
1979
TEST_F(URLLoaderTest,UploadTwoBatchesOfFilesWithRespondInvalidFile)1980 TEST_F(URLLoaderTest, UploadTwoBatchesOfFilesWithRespondInvalidFile) {
1981 allow_file_uploads();
1982 set_upload_files_invalid(true);
1983 base::FilePath file_path = GetTestFilePath("simple_page.html");
1984
1985 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
1986 size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
1987 for (size_t i = 0; i < num_files; ++i) {
1988 request_body->AppendFileRange(
1989 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
1990 }
1991 set_request_body(std::move(request_body));
1992
1993 EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
1994 }
1995
TEST_F(URLLoaderTest,UploadTwoBatchesOfFilesWithRespondDifferentNumOfFiles)1996 TEST_F(URLLoaderTest, UploadTwoBatchesOfFilesWithRespondDifferentNumOfFiles) {
1997 allow_file_uploads();
1998 set_ignore_last_upload_file(true);
1999 base::FilePath file_path = GetTestFilePath("simple_page.html");
2000
2001 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
2002 size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
2003 for (size_t i = 0; i < num_files; ++i) {
2004 request_body->AppendFileRange(
2005 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
2006 }
2007 set_request_body(std::move(request_body));
2008
2009 EXPECT_EQ(net::ERR_FAILED, Load(test_server()->GetURL("/echo")));
2010 }
2011
TEST_F(URLLoaderTest,UploadInvalidFile)2012 TEST_F(URLLoaderTest, UploadInvalidFile) {
2013 allow_file_uploads();
2014 set_upload_files_invalid(true);
2015 base::FilePath file_path = GetTestFilePath("simple_page.html");
2016
2017 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
2018 request_body->AppendFileRange(
2019 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
2020 set_request_body(std::move(request_body));
2021
2022 EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
2023 }
2024
TEST_F(URLLoaderTest,UploadFileWithoutNetworkServiceClient)2025 TEST_F(URLLoaderTest, UploadFileWithoutNetworkServiceClient) {
2026 // Don't call allow_file_uploads();
2027 base::FilePath file_path = GetTestFilePath("simple_page.html");
2028
2029 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
2030 request_body->AppendFileRange(
2031 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
2032 set_request_body(std::move(request_body));
2033
2034 EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
2035 }
2036
2037 class CallbackSavingNetworkContextClient : public TestNetworkContextClient {
2038 public:
OnFileUploadRequested(int32_t process_id,bool async,const std::vector<base::FilePath> & file_paths,OnFileUploadRequestedCallback callback)2039 void OnFileUploadRequested(int32_t process_id,
2040 bool async,
2041 const std::vector<base::FilePath>& file_paths,
2042 OnFileUploadRequestedCallback callback) override {
2043 file_upload_requested_callback_ = std::move(callback);
2044 if (quit_closure_for_on_file_upload_requested_)
2045 std::move(quit_closure_for_on_file_upload_requested_).Run();
2046 }
2047
RunUntilUploadRequested(OnFileUploadRequestedCallback * callback)2048 void RunUntilUploadRequested(OnFileUploadRequestedCallback* callback) {
2049 if (!file_upload_requested_callback_) {
2050 base::RunLoop run_loop;
2051 quit_closure_for_on_file_upload_requested_ = run_loop.QuitClosure();
2052 run_loop.Run();
2053 }
2054 *callback = std::move(file_upload_requested_callback_);
2055 }
2056
2057 private:
2058 base::OnceClosure quit_closure_for_on_file_upload_requested_;
2059 OnFileUploadRequestedCallback file_upload_requested_callback_;
2060 };
2061
TEST_F(URLLoaderTest,UploadFileCanceled)2062 TEST_F(URLLoaderTest, UploadFileCanceled) {
2063 base::FilePath file_path = GetTestFilePath("simple_page.html");
2064 std::vector<base::File> opened_file;
2065 opened_file.emplace_back(file_path, base::File::FLAG_OPEN |
2066 base::File::FLAG_READ |
2067 base::File::FLAG_ASYNC);
2068 ASSERT_TRUE(opened_file.back().IsValid());
2069
2070 ResourceRequest request =
2071 CreateResourceRequest("POST", test_server()->GetURL("/echo"));
2072 request.request_body = new ResourceRequestBody();
2073 request.request_body->AppendFileRange(
2074 file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
2075
2076 base::RunLoop delete_run_loop;
2077 mojo::Remote<mojom::URLLoader> loader;
2078 static mojom::URLLoaderFactoryParams params;
2079 params.process_id = mojom::kBrowserProcessId;
2080 params.is_corb_enabled = false;
2081 auto network_context_client =
2082 std::make_unique<CallbackSavingNetworkContextClient>();
2083 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
2084 context(), nullptr /* network_service_client */,
2085 network_context_client.get(),
2086 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2087 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
2088 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2089 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
2090 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2091 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2092 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2093 mojo::NullRemote() /* cookie_observer */);
2094
2095 mojom::NetworkContextClient::OnFileUploadRequestedCallback callback;
2096 network_context_client->RunUntilUploadRequested(&callback);
2097
2098 // Check we can call the callback from a deleted URLLoader without crashing.
2099 url_loader.reset();
2100 base::RunLoop().RunUntilIdle();
2101 std::move(callback).Run(net::OK, std::move(opened_file));
2102 base::RunLoop().RunUntilIdle();
2103 }
2104
2105 // Tests a request body with a data pipe element.
TEST_F(URLLoaderTest,UploadDataPipe)2106 TEST_F(URLLoaderTest, UploadDataPipe) {
2107 const std::string kRequestBody = "Request Body";
2108
2109 mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_remote;
2110 auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
2111 kRequestBody, data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
2112
2113 auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
2114 resource_request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
2115 set_request_body(std::move(resource_request_body));
2116
2117 std::string response_body;
2118 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
2119 EXPECT_EQ(kRequestBody, response_body);
2120 }
2121
2122 // Same as above and tests that the body is sent after a 307 redirect.
TEST_F(URLLoaderTest,UploadDataPipe_Redirect307)2123 TEST_F(URLLoaderTest, UploadDataPipe_Redirect307) {
2124 const std::string kRequestBody = "Request Body";
2125
2126 mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_remote;
2127 auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
2128 kRequestBody, data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
2129
2130 auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
2131 resource_request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
2132 set_request_body(std::move(resource_request_body));
2133 set_expect_redirect();
2134
2135 std::string response_body;
2136 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/redirect307-to-echo"),
2137 &response_body));
2138 EXPECT_EQ(kRequestBody, response_body);
2139 }
2140
2141 // Tests a large request body, which should result in multiple asynchronous
2142 // reads.
TEST_F(URLLoaderTest,UploadDataPipeWithLotsOfData)2143 TEST_F(URLLoaderTest, UploadDataPipeWithLotsOfData) {
2144 std::string request_body;
2145 request_body.reserve(5 * 1024 * 1024);
2146 // Using a repeating patter with a length that's prime is more likely to spot
2147 // out of order or repeated chunks of data.
2148 while (request_body.size() < 5 * 1024 * 1024)
2149 request_body.append("foppity");
2150
2151 mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_remote;
2152 auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
2153 request_body, data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
2154
2155 auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
2156 resource_request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
2157 set_request_body(std::move(resource_request_body));
2158
2159 std::string response_body;
2160 EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
2161 EXPECT_EQ(request_body, response_body);
2162 }
2163
TEST_F(URLLoaderTest,UploadDataPipeError)2164 TEST_F(URLLoaderTest, UploadDataPipeError) {
2165 const std::string kRequestBody = "Request Body";
2166
2167 mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_remote;
2168 auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
2169 kRequestBody, data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
2170 data_pipe_getter->set_start_error(net::ERR_ACCESS_DENIED);
2171
2172 auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
2173 resource_request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
2174 set_request_body(std::move(resource_request_body));
2175
2176 EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
2177 }
2178
TEST_F(URLLoaderTest,UploadDataPipeClosedEarly)2179 TEST_F(URLLoaderTest, UploadDataPipeClosedEarly) {
2180 const std::string kRequestBody = "Request Body";
2181
2182 mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_remote;
2183 auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
2184 kRequestBody, data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
2185 data_pipe_getter->set_pipe_closed_early(true);
2186
2187 auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
2188 resource_request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
2189 set_request_body(std::move(resource_request_body));
2190
2191 std::string response_body;
2192 EXPECT_EQ(net::ERR_FAILED, Load(test_server()->GetURL("/echo")));
2193 }
2194
2195 // Tests a request body with a chunked data pipe element.
TEST_F(URLLoaderTest,UploadChunkedDataPipe)2196 TEST_F(URLLoaderTest, UploadChunkedDataPipe) {
2197 const std::string kRequestBody = "Request Body";
2198
2199 TestChunkedDataPipeGetter data_pipe_getter;
2200
2201 ResourceRequest request =
2202 CreateResourceRequest("POST", test_server()->GetURL("/echo"));
2203 request.request_body = base::MakeRefCounted<ResourceRequestBody>();
2204 request.request_body->SetToChunkedDataPipe(
2205 data_pipe_getter.GetDataPipeGetterRemote());
2206
2207 base::RunLoop delete_run_loop;
2208 mojo::Remote<mojom::URLLoader> loader;
2209 std::unique_ptr<URLLoader> url_loader;
2210 mojom::URLLoaderFactoryParams params;
2211 params.process_id = mojom::kBrowserProcessId;
2212 params.is_corb_enabled = false;
2213 url_loader = std::make_unique<URLLoader>(
2214 context(), nullptr /* network_service_client */,
2215 nullptr /* network_context_client */,
2216 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2217 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
2218 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2219 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
2220 0 /* keepalive_request_size */, nullptr /* resource_scheduler_client */,
2221 nullptr /* keepalive_statistics_reporter */,
2222 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2223 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2224 mojo::NullRemote() /* cookie_observer */);
2225
2226 mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback =
2227 data_pipe_getter.WaitForGetSize();
2228 mojo::BlockingCopyFromString(kRequestBody,
2229 data_pipe_getter.WaitForStartReading());
2230 std::move(get_size_callback).Run(net::OK, kRequestBody.size());
2231 delete_run_loop.Run();
2232 client()->RunUntilComplete();
2233
2234 EXPECT_EQ(kRequestBody, ReadBody());
2235 EXPECT_EQ(net::OK, client()->completion_status().error_code);
2236 }
2237
2238 // Tests a request body with ReadOnceStream.
TEST_F(URLLoaderTest,UploadReadOnceStream)2239 TEST_F(URLLoaderTest, UploadReadOnceStream) {
2240 const std::string kRequestBody = "Request Body";
2241
2242 TestChunkedDataPipeGetter data_pipe_getter;
2243
2244 ResourceRequest request =
2245 CreateResourceRequest("POST", test_server()->GetURL("/echo"));
2246 request.request_body = base::MakeRefCounted<ResourceRequestBody>();
2247 request.request_body->SetToReadOnceStream(
2248 data_pipe_getter.GetDataPipeGetterRemote());
2249
2250 base::HistogramTester tester;
2251 std::string histogram_allowh1("Net.Fetch.UploadStreamingProtocolAllowH1");
2252 std::string histogram_notallowh1(
2253 "Net.Fetch.UploadStreamingProtocolNotAllowH1");
2254 tester.ExpectTotalCount(histogram_allowh1, 0);
2255 tester.ExpectTotalCount(histogram_notallowh1, 0);
2256
2257 base::RunLoop delete_run_loop;
2258 mojo::Remote<mojom::URLLoader> loader;
2259 std::unique_ptr<URLLoader> url_loader;
2260 mojom::URLLoaderFactoryParams params;
2261 params.process_id = mojom::kBrowserProcessId;
2262 params.is_corb_enabled = false;
2263 url_loader = std::make_unique<URLLoader>(
2264 context(), nullptr /* network_service_client */,
2265 nullptr /* network_context_client */,
2266 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2267 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
2268 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2269 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
2270 0 /* keepalive_request_size */, nullptr /* resource_scheduler_client */,
2271 nullptr /* keepalive_statistics_reporter */,
2272 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2273 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2274 mojo::NullRemote() /* cookie_observer */);
2275
2276 mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback =
2277 data_pipe_getter.WaitForGetSize();
2278 mojo::BlockingCopyFromString(kRequestBody,
2279 data_pipe_getter.WaitForStartReading());
2280 std::move(get_size_callback).Run(net::OK, kRequestBody.size());
2281 delete_run_loop.Run();
2282 client()->RunUntilComplete();
2283
2284 EXPECT_EQ(kRequestBody, ReadBody());
2285 EXPECT_EQ(net::OK, client()->completion_status().error_code);
2286
2287 tester.ExpectTotalCount(histogram_allowh1, 1);
2288 // From ReportFetchUploadStreamingUMA()
2289 constexpr int kHTTP1_1 = 0;
2290 tester.ExpectBucketCount(histogram_allowh1, kHTTP1_1, 1);
2291 tester.ExpectTotalCount(histogram_notallowh1, 0);
2292 }
2293
2294 // Tests that SSLInfo is not attached to OnComplete messages when there is no
2295 // certificate error.
TEST_F(URLLoaderTest,NoSSLInfoWithoutCertificateError)2296 TEST_F(URLLoaderTest, NoSSLInfoWithoutCertificateError) {
2297 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
2298 ASSERT_TRUE(https_server.Start());
2299 set_send_ssl_for_cert_error();
2300 EXPECT_EQ(net::OK, Load(https_server.GetURL("/")));
2301 EXPECT_FALSE(client()->completion_status().ssl_info.has_value());
2302 }
2303
2304 // Tests that SSLInfo is not attached to OnComplete messages when the
2305 // corresponding option is not set.
TEST_F(URLLoaderTest,NoSSLInfoOnComplete)2306 TEST_F(URLLoaderTest, NoSSLInfoOnComplete) {
2307 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
2308 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
2309 ASSERT_TRUE(https_server.Start());
2310 EXPECT_EQ(net::ERR_INSECURE_RESPONSE, Load(https_server.GetURL("/")));
2311 EXPECT_FALSE(client()->completion_status().ssl_info.has_value());
2312 }
2313
2314 // Tests that SSLInfo is attached to OnComplete messages when the corresponding
2315 // option is set.
TEST_F(URLLoaderTest,SSLInfoOnComplete)2316 TEST_F(URLLoaderTest, SSLInfoOnComplete) {
2317 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
2318 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
2319 ASSERT_TRUE(https_server.Start());
2320 set_send_ssl_for_cert_error();
2321 EXPECT_EQ(net::ERR_INSECURE_RESPONSE, Load(https_server.GetURL("/")));
2322 ASSERT_TRUE(client()->completion_status().ssl_info.has_value());
2323 EXPECT_TRUE(client()->completion_status().ssl_info.value().cert);
2324 EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
2325 client()->completion_status().ssl_info.value().cert_status);
2326 }
2327
2328 // Make sure the client can modify headers during a redirect.
TEST_F(URLLoaderTest,RedirectModifiedHeaders)2329 TEST_F(URLLoaderTest, RedirectModifiedHeaders) {
2330 ResourceRequest request = CreateResourceRequest(
2331 "GET", test_server()->GetURL("/redirect307-to-echo"));
2332 request.headers.SetHeader("Header1", "Value1");
2333 request.headers.SetHeader("Header2", "Value2");
2334
2335 base::RunLoop delete_run_loop;
2336 mojo::Remote<mojom::URLLoader> loader;
2337 std::unique_ptr<URLLoader> url_loader;
2338 mojom::URLLoaderFactoryParams params;
2339 params.process_id = mojom::kBrowserProcessId;
2340 params.is_corb_enabled = false;
2341 url_loader = std::make_unique<URLLoader>(
2342 context(), nullptr /* network_service_client */,
2343 nullptr /* network_context_client */,
2344 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2345 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2346 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2347 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2348 /*coep_reporter=*/nullptr,
2349
2350 0 /* request_id */, 0 /* keepalive_request_size */,
2351 resource_scheduler_client(), nullptr,
2352 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2353 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2354 mojo::NullRemote() /* cookie_observer */);
2355
2356 client()->RunUntilRedirectReceived();
2357
2358 // Initial request should only have initial headers.
2359 const auto& request_headers1 = sent_request().headers;
2360 EXPECT_EQ("Value1", request_headers1.find("Header1")->second);
2361 EXPECT_EQ("Value2", request_headers1.find("Header2")->second);
2362 EXPECT_EQ(request_headers1.end(), request_headers1.find("Header3"));
2363
2364 // Overwrite Header2 and add Header3.
2365 net::HttpRequestHeaders redirect_headers;
2366 redirect_headers.SetHeader("Header2", "");
2367 redirect_headers.SetHeader("Header3", "Value3");
2368 loader->FollowRedirect({}, redirect_headers, {}, base::nullopt);
2369
2370 client()->RunUntilComplete();
2371 delete_run_loop.Run();
2372
2373 // Redirected request should also have modified headers.
2374 const auto& request_headers2 = sent_request().headers;
2375 EXPECT_EQ("Value1", request_headers2.find("Header1")->second);
2376 EXPECT_EQ("", request_headers2.find("Header2")->second);
2377 EXPECT_EQ("Value3", request_headers2.find("Header3")->second);
2378 }
2379
TEST_F(URLLoaderTest,RedirectFailsOnModifyUnsafeHeader)2380 TEST_F(URLLoaderTest, RedirectFailsOnModifyUnsafeHeader) {
2381 const char* kUnsafeHeaders[] = {
2382 net::HttpRequestHeaders::kContentLength,
2383 net::HttpRequestHeaders::kHost,
2384 net::HttpRequestHeaders::kProxyConnection,
2385 net::HttpRequestHeaders::kProxyAuthorization,
2386 "Proxy-Foo",
2387 };
2388
2389 for (const auto* unsafe_header : kUnsafeHeaders) {
2390 TestURLLoaderClient client;
2391 ResourceRequest request = CreateResourceRequest(
2392 "GET", test_server()->GetURL("/redirect307-to-echo"));
2393
2394 base::RunLoop delete_run_loop;
2395 mojo::Remote<mojom::URLLoader> loader;
2396 std::unique_ptr<URLLoader> url_loader;
2397 mojom::URLLoaderFactoryParams params;
2398 params.process_id = mojom::kBrowserProcessId;
2399 params.is_corb_enabled = false;
2400 url_loader = std::make_unique<URLLoader>(
2401 context(), nullptr /* network_service_client */,
2402 nullptr /* network_context_client */,
2403 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2404 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2405 client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2406 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2407 /*coep_reporter=*/nullptr, 0 /* request_id */,
2408 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2409 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2410 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2411 mojo::NullRemote() /* cookie_observer */);
2412
2413 client.RunUntilRedirectReceived();
2414
2415 net::HttpRequestHeaders redirect_headers;
2416 redirect_headers.SetHeader(unsafe_header, "foo");
2417 loader->FollowRedirect({}, redirect_headers, {}, base::nullopt);
2418
2419 client.RunUntilComplete();
2420 delete_run_loop.Run();
2421
2422 EXPECT_TRUE(client.has_received_completion());
2423 EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client.completion_status().error_code);
2424 }
2425 }
2426
TEST_F(URLLoaderTest,RedirectLogsModifiedConcerningHeader)2427 TEST_F(URLLoaderTest, RedirectLogsModifiedConcerningHeader) {
2428 using ConcerningHeaderId = URLLoader::ConcerningHeaderId;
2429 base::HistogramTester histograms;
2430
2431 TestURLLoaderClient client;
2432
2433 ResourceRequest request = CreateResourceRequest(
2434 "GET", test_server()->GetURL("/redirect307-to-echo"));
2435
2436 base::RunLoop delete_run_loop;
2437 mojo::Remote<mojom::URLLoader> loader;
2438 std::unique_ptr<URLLoader> url_loader;
2439 mojom::URLLoaderFactoryParams params;
2440 params.process_id = mojom::kBrowserProcessId;
2441 params.is_corb_enabled = false;
2442 url_loader = std::make_unique<URLLoader>(
2443 context(), nullptr /* network_service_client */,
2444 nullptr /* network_context_client */,
2445 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2446 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2447 client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2448 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2449 /*coep_reporter=*/nullptr, 0 /* request_id */,
2450 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2451 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2452 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2453 mojo::NullRemote() /* cookie_observer */);
2454
2455 client.RunUntilRedirectReceived();
2456
2457 net::HttpRequestHeaders redirect_headers;
2458 redirect_headers.SetHeader(net::HttpRequestHeaders::kReferer,
2459 "https://somewhere.test/");
2460 redirect_headers.SetHeader("Via", "Albuquerque");
2461 loader->FollowRedirect({}, redirect_headers, {}, base::nullopt);
2462
2463 client.RunUntilComplete();
2464 delete_run_loop.Run();
2465
2466 EXPECT_TRUE(client.has_received_completion());
2467 EXPECT_EQ(net::OK, client.completion_status().error_code);
2468
2469 histograms.ExpectBucketCount(
2470 "NetworkService.ConcerningRequestHeader.AddedOnRedirect", true, 1);
2471 histograms.ExpectBucketCount(
2472 "NetworkService.ConcerningRequestHeader.AddedOnRedirect", false, 0);
2473 for (int i = 0; i < static_cast<int>(ConcerningHeaderId::kMaxValue); ++i) {
2474 if (i == static_cast<int>(ConcerningHeaderId::kReferer) ||
2475 i == static_cast<int>(ConcerningHeaderId::kVia)) {
2476 histograms.ExpectBucketCount(
2477 "NetworkService.ConcerningRequestHeader.HeaderAddedOnRedirect", i, 1);
2478 } else {
2479 histograms.ExpectBucketCount(
2480 "NetworkService.ConcerningRequestHeader.HeaderAddedOnRedirect", i, 0);
2481 }
2482 }
2483 }
2484
2485 // Test the client can remove headers during a redirect.
TEST_F(URLLoaderTest,RedirectRemoveHeader)2486 TEST_F(URLLoaderTest, RedirectRemoveHeader) {
2487 ResourceRequest request = CreateResourceRequest(
2488 "GET", test_server()->GetURL("/redirect307-to-echo"));
2489 request.headers.SetHeader("Header1", "Value1");
2490 request.headers.SetHeader("Header2", "Value2");
2491
2492 base::RunLoop delete_run_loop;
2493 mojo::Remote<mojom::URLLoader> loader;
2494 std::unique_ptr<URLLoader> url_loader;
2495 mojom::URLLoaderFactoryParams params;
2496 params.process_id = mojom::kBrowserProcessId;
2497 params.is_corb_enabled = false;
2498 url_loader = std::make_unique<URLLoader>(
2499 context(), nullptr /* network_service_client */,
2500 nullptr /* network_context_client */,
2501 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2502 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2503 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2504 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2505 /*coep_reporter=*/nullptr, 0 /* request_id */,
2506 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2507 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2508 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2509 mojo::NullRemote() /* cookie_observer */);
2510
2511 client()->RunUntilRedirectReceived();
2512
2513 // Initial request should only have initial headers.
2514 const auto& request_headers1 = sent_request().headers;
2515 EXPECT_EQ("Value1", request_headers1.find("Header1")->second);
2516 EXPECT_EQ("Value2", request_headers1.find("Header2")->second);
2517
2518 // Remove Header1.
2519 std::vector<std::string> removed_headers = {"Header1"};
2520 loader->FollowRedirect(removed_headers, {}, {}, base::nullopt);
2521
2522 client()->RunUntilComplete();
2523 delete_run_loop.Run();
2524
2525 // Redirected request should have the updated headers.
2526 const auto& request_headers2 = sent_request().headers;
2527 EXPECT_EQ(request_headers2.end(), request_headers2.find("Header1"));
2528 EXPECT_EQ("Value2", request_headers2.find("Header2")->second);
2529 }
2530
2531 // Test the client can remove headers and add headers back during a redirect.
TEST_F(URLLoaderTest,RedirectRemoveHeaderAndAddItBack)2532 TEST_F(URLLoaderTest, RedirectRemoveHeaderAndAddItBack) {
2533 ResourceRequest request = CreateResourceRequest(
2534 "GET", test_server()->GetURL("/redirect307-to-echo"));
2535 request.headers.SetHeader("Header1", "Value1");
2536 request.headers.SetHeader("Header2", "Value2");
2537
2538 base::RunLoop delete_run_loop;
2539 mojo::Remote<mojom::URLLoader> loader;
2540 std::unique_ptr<URLLoader> url_loader;
2541 mojom::URLLoaderFactoryParams params;
2542 params.process_id = mojom::kBrowserProcessId;
2543 params.is_corb_enabled = false;
2544 url_loader = std::make_unique<URLLoader>(
2545 context(), nullptr /* network_service_client */,
2546 nullptr /* network_context_client */,
2547 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2548 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2549 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2550 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2551 /*coep_reporter=*/nullptr, 0 /* request_id */,
2552 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2553 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2554 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2555 mojo::NullRemote() /* cookie_observer */);
2556
2557 client()->RunUntilRedirectReceived();
2558
2559 // Initial request should only have initial headers.
2560 const auto& request_headers1 = sent_request().headers;
2561 EXPECT_EQ("Value1", request_headers1.find("Header1")->second);
2562 EXPECT_EQ("Value2", request_headers1.find("Header2")->second);
2563
2564 // Remove Header1 and add it back using a different value.
2565 std::vector<std::string> removed_headers = {"Header1"};
2566 net::HttpRequestHeaders modified_headers;
2567 modified_headers.SetHeader("Header1", "NewValue1");
2568 loader->FollowRedirect(removed_headers, modified_headers, {}, base::nullopt);
2569
2570 client()->RunUntilComplete();
2571 delete_run_loop.Run();
2572
2573 // Redirected request should have the updated headers.
2574 const auto& request_headers2 = sent_request().headers;
2575 EXPECT_EQ("NewValue1", request_headers2.find("Header1")->second);
2576 EXPECT_EQ("Value2", request_headers2.find("Header2")->second);
2577 }
2578
2579 // Validate Sec- prefixed headers are handled properly when redirecting from
2580 // insecure => secure urls. The Sec-Fetch-Site header should be re-added on the
2581 // secure url.
TEST_F(URLLoaderTest,UpgradeAddsSecHeaders)2582 TEST_F(URLLoaderTest, UpgradeAddsSecHeaders) {
2583 // Set up a redirect to signal we will go from insecure => secure.
2584 GURL url = test_server()->GetURL(
2585 kInsecureHost,
2586 "/server-redirect?" + test_server()->GetURL("/echo").spec());
2587 ResourceRequest request = CreateResourceRequest("GET", url);
2588
2589 base::RunLoop delete_run_loop;
2590 mojo::Remote<mojom::URLLoader> loader;
2591 std::unique_ptr<URLLoader> url_loader;
2592 mojom::URLLoaderFactoryParams params;
2593 params.process_id = mojom::kBrowserProcessId;
2594 url_loader = std::make_unique<URLLoader>(
2595 context(), nullptr /* network_service_client */,
2596 nullptr /* network_context_client */,
2597 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2598 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2599 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2600 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2601 /*coep_reporter=*/nullptr, 0 /* request_id */,
2602 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2603 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2604 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2605 mojo::NullRemote() /* cookie_observer */);
2606
2607 client()->RunUntilRedirectReceived();
2608
2609 // The initial request is received when the redirect before it has been
2610 // followed. It should have no added Sec- headers as it is not trustworthy.
2611 const auto& request_headers1 = sent_request().headers;
2612 EXPECT_EQ(request_headers1.end(), request_headers1.find("Sec-Fetch-Site"));
2613 EXPECT_EQ(request_headers1.end(), request_headers1.find("Sec-Fetch-User"));
2614
2615 // Now follow the redirect to the final destination and validate again.
2616 loader->FollowRedirect({}, {}, {}, base::nullopt);
2617 client()->RunUntilComplete();
2618 delete_run_loop.Run();
2619
2620 // The Sec-Fetch-Site header should have been added again since we are now on
2621 // a trustworthy url again.
2622 const auto& request_headers2 = sent_request().headers;
2623 EXPECT_EQ("cross-site", request_headers2.find("Sec-Fetch-Site")->second);
2624 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-Fetch-User"));
2625 }
2626
2627 // Validate Sec- prefixed headers are properly handled when redirecting from
2628 // secure => insecure urls. All Sec-CH- and Sec-Fetch- prefixed
2629 // headers should be removed.
TEST_F(URLLoaderTest,DowngradeRemovesSecHeaders)2630 TEST_F(URLLoaderTest, DowngradeRemovesSecHeaders) {
2631 // Set up a redirect to signal we will go from secure => insecure.
2632 GURL url = test_server()->GetURL(
2633 "/server-redirect?" +
2634 test_server()->GetURL(kInsecureHost, "/echo").spec());
2635
2636 // Add some initial headers to ensure the right ones are removed and
2637 // everything else is left alone.
2638 ResourceRequest request = CreateResourceRequest("GET", url);
2639 request.headers.SetHeader("Sec-CH-UA", "Value1");
2640 request.headers.SetHeader("Sec-Other-Type", "Value2");
2641 request.headers.SetHeader("Other-Header", "Value3");
2642
2643 base::RunLoop delete_run_loop;
2644 mojo::Remote<mojom::URLLoader> loader;
2645 std::unique_ptr<URLLoader> url_loader;
2646 mojom::URLLoaderFactoryParams params;
2647 params.process_id = mojom::kBrowserProcessId;
2648 url_loader = std::make_unique<URLLoader>(
2649 context(), nullptr /* network_service_client */,
2650 nullptr /* network_context_client */,
2651 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2652 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2653 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2654 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2655 /*coep_reporter=*/nullptr, 0 /* request_id */,
2656 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2657 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2658 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2659 mojo::NullRemote() /* cookie_observer */);
2660
2661 client()->RunUntilRedirectReceived();
2662
2663 // The initial request is received when the redirect before it has been
2664 // followed. It should have all the Sec- headers as it is trustworthy. It
2665 // should also have added a Sec-Fetch-Site header
2666 const auto& request_headers1 = sent_request().headers;
2667 EXPECT_EQ("Value1", request_headers1.find("Sec-CH-UA")->second);
2668 EXPECT_EQ("Value2", request_headers1.find("Sec-Other-Type")->second);
2669 EXPECT_EQ("Value3", request_headers1.find("Other-Header")->second);
2670 EXPECT_EQ("same-origin", request_headers1.find("Sec-Fetch-Site")->second);
2671 EXPECT_EQ(request_headers1.end(), request_headers1.find("Sec-Fetch-User"));
2672
2673 // Now follow the redirect to the final destination and validate again.
2674 loader->FollowRedirect({}, {}, {}, base::nullopt);
2675 client()->RunUntilComplete();
2676 delete_run_loop.Run();
2677
2678 // We should have removed our special Sec-CH- and Sec-Fetch- prefixed headers
2679 // and left the others. We are now operating on an un-trustworthy context.
2680 const auto& request_headers2 = sent_request().headers;
2681 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-CH-UA"));
2682 EXPECT_EQ("Value2", request_headers2.find("Sec-Other-Type")->second);
2683 EXPECT_EQ("Value3", request_headers2.find("Other-Header")->second);
2684 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-Fetch-Site"));
2685 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-Fetch-User"));
2686 }
2687
2688 // Validate Sec- prefixed headers are properly handled when redirecting from
2689 // secure => insecure => secure urls.The headers on insecure
2690 // urls should be removed and Sec-Fetch-Site should be re-added on secure ones.
TEST_F(URLLoaderTest,RedirectChainRemovesAndAddsSecHeaders)2691 TEST_F(URLLoaderTest, RedirectChainRemovesAndAddsSecHeaders) {
2692 // Set up a redirect to signal we will go from secure => insecure => secure.
2693 GURL insecure_upgrade_url = test_server()->GetURL(
2694 kInsecureHost,
2695 "/server-redirect?" + test_server()->GetURL("/echo").spec());
2696 GURL url =
2697 test_server()->GetURL("/server-redirect?" + insecure_upgrade_url.spec());
2698
2699 // Add some initial headers to ensure the right ones are removed and
2700 // everything else is left alone.
2701 ResourceRequest request = CreateResourceRequest("GET", url);
2702 request.headers.SetHeader("Sec-CH-UA", "Value1");
2703 request.headers.SetHeader("Sec-Other-Type", "Value2");
2704 request.headers.SetHeader("Other-Header", "Value3");
2705
2706 base::RunLoop delete_run_loop;
2707 mojo::Remote<mojom::URLLoader> loader;
2708 std::unique_ptr<URLLoader> url_loader;
2709 mojom::URLLoaderFactoryParams params;
2710 params.process_id = mojom::kBrowserProcessId;
2711 url_loader = std::make_unique<URLLoader>(
2712 context(), nullptr /* network_service_client */,
2713 nullptr /* network_context_client */,
2714 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2715 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
2716 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2717 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2718 /*coep_reporter=*/nullptr, 0 /* request_id */,
2719 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2720 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2721 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2722 mojo::NullRemote() /* cookie_observer */);
2723
2724 client()->RunUntilRedirectReceived();
2725
2726 // The initial request is received when the redirect before it has been
2727 // followed. It should have all the Sec- headers as it is trustworthy. It
2728 // should also have added a Sec-Fetch-Site header
2729 const auto& request_headers1 = sent_request().headers;
2730 EXPECT_EQ("Value1", request_headers1.find("Sec-CH-UA")->second);
2731 EXPECT_EQ("Value2", request_headers1.find("Sec-Other-Type")->second);
2732 EXPECT_EQ("Value3", request_headers1.find("Other-Header")->second);
2733 EXPECT_EQ("same-origin", request_headers1.find("Sec-Fetch-Site")->second);
2734 EXPECT_EQ(request_headers1.end(), request_headers1.find("Sec-Fetch-User"));
2735
2736 // Follow our redirect and then verify again.
2737 loader->FollowRedirect({}, {}, {}, base::nullopt);
2738 client()->ClearHasReceivedRedirect();
2739 client()->RunUntilRedirectReceived();
2740
2741 // Special Sec-CH- and Sec-Fetch- prefixed headers should have been removed
2742 // and the others left alone. We are now operating on an un-trustworthy
2743 // context.
2744 const auto& request_headers2 = sent_request().headers;
2745 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-CH-UA"));
2746 EXPECT_EQ("Value2", request_headers2.find("Sec-Other-Type")->second);
2747 EXPECT_EQ("Value3", request_headers2.find("Other-Header")->second);
2748 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-Fetch-Site"));
2749 EXPECT_EQ(request_headers2.end(), request_headers2.find("Sec-Fetch-User"));
2750
2751 // Now follow the final redirect back to a trustworthy destination and
2752 // re-validate.
2753 loader->FollowRedirect({}, {}, {}, base::nullopt);
2754 client()->RunUntilComplete();
2755 delete_run_loop.Run();
2756
2757 const auto& request_headers3 = sent_request().headers;
2758 EXPECT_EQ(request_headers3.end(), request_headers3.find("Sec-CH-UA"));
2759 EXPECT_EQ("Value2", request_headers3.find("Sec-Other-Type")->second);
2760 EXPECT_EQ("Value3", request_headers3.find("Other-Header")->second);
2761 EXPECT_EQ("cross-site", request_headers3.find("Sec-Fetch-Site")->second);
2762 EXPECT_EQ(request_headers3.end(), request_headers3.find("Sec-Fetch-User"));
2763 }
2764
2765 // Validate Sec-Fetch-User header is properly handled.
TEST_F(URLLoaderTest,RedirectSecHeadersUser)2766 TEST_F(URLLoaderTest, RedirectSecHeadersUser) {
2767 GURL url = test_server()->GetURL("/server-redirect?" +
2768 test_server()->GetURL("/echo").spec());
2769
2770 // Add some initial headers to ensure the right ones are removed and
2771 // everything else is left alone.
2772 ResourceRequest request = CreateResourceRequest("GET", url);
2773 request.trusted_params->has_user_activation = true;
2774
2775 base::RunLoop delete_run_loop;
2776 mojo::PendingRemote<mojom::URLLoader> loader;
2777 std::unique_ptr<URLLoader> url_loader;
2778 mojom::URLLoaderFactoryParams params;
2779 params.process_id = mojom::kBrowserProcessId;
2780 url_loader = std::make_unique<URLLoader>(
2781 context(), nullptr /* network_service_client */,
2782 nullptr /* network_context_client */,
2783 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2784 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
2785 request, client()->CreateRemote(),
2786 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2787 ¶ms,
2788 /*coep_reporter=*/nullptr, 0 /* request_id */,
2789 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2790 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2791 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2792 mojo::NullRemote() /* cookie_observer */);
2793
2794 client()->RunUntilRedirectReceived();
2795
2796 const auto& request_headers = sent_request().headers;
2797 EXPECT_EQ("same-origin", request_headers.find("Sec-Fetch-Site")->second);
2798 EXPECT_EQ("?1", request_headers.find("Sec-Fetch-User")->second);
2799 }
2800
2801 // Validate Sec-Fetch-User header cannot be modified by manually set the value.
TEST_F(URLLoaderTest,RedirectDirectlyModifiedSecHeadersUser)2802 TEST_F(URLLoaderTest, RedirectDirectlyModifiedSecHeadersUser) {
2803 GURL url = test_server()->GetURL("/server-redirect?" +
2804 test_server()->GetURL("/echo").spec());
2805
2806 // Try to modify `Sec-Fetch-User` directly.
2807 ResourceRequest request = CreateResourceRequest("GET", url);
2808 request.headers.SetHeader("Sec-Fetch-User", "?1");
2809 request.headers.SetHeader("Sec-Fetch-Dest", "embed");
2810
2811 base::RunLoop delete_run_loop;
2812 mojo::PendingRemote<mojom::URLLoader> loader;
2813 std::unique_ptr<URLLoader> url_loader;
2814 mojom::URLLoaderFactoryParams params;
2815 params.process_id = mojom::kBrowserProcessId;
2816 url_loader = std::make_unique<URLLoader>(
2817 context(), nullptr /* network_service_client */,
2818 nullptr /* network_context_client */,
2819 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2820 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
2821 request, client()->CreateRemote(),
2822 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2823 ¶ms,
2824 /*coep_reporter=*/nullptr, 0 /* request_id */,
2825 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2826 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2827 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2828 mojo::NullRemote() /* cookie_observer */);
2829
2830 client()->RunUntilRedirectReceived();
2831
2832 const auto& request_headers = sent_request().headers;
2833 EXPECT_EQ(request_headers.end(), request_headers.find("Sec-Fetch-User"));
2834 EXPECT_EQ("empty", request_headers.find("Sec-Fetch-Dest")->second);
2835 }
2836
2837 // A mock URLRequestJob which simulates an HTTPS request with a certificate
2838 // error.
2839 class MockHTTPSURLRequestJob : public net::URLRequestTestJob {
2840 public:
MockHTTPSURLRequestJob(net::URLRequest * request,const std::string & response_headers,const std::string & response_data,bool auto_advance)2841 MockHTTPSURLRequestJob(net::URLRequest* request,
2842 const std::string& response_headers,
2843 const std::string& response_data,
2844 bool auto_advance)
2845 : net::URLRequestTestJob(request,
2846 response_headers,
2847 response_data,
2848 auto_advance) {}
2849
2850 ~MockHTTPSURLRequestJob() override = default;
2851
2852 // net::URLRequestTestJob:
GetResponseInfo(net::HttpResponseInfo * info)2853 void GetResponseInfo(net::HttpResponseInfo* info) override {
2854 // Get the original response info, but override the SSL info.
2855 net::URLRequestJob::GetResponseInfo(info);
2856 info->ssl_info.cert =
2857 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
2858 info->ssl_info.cert_status = net::CERT_STATUS_DATE_INVALID;
2859 }
2860
2861 private:
2862 DISALLOW_COPY_AND_ASSIGN(MockHTTPSURLRequestJob);
2863 };
2864
2865 class MockHTTPSJobURLRequestInterceptor : public net::URLRequestInterceptor {
2866 public:
MockHTTPSJobURLRequestInterceptor()2867 MockHTTPSJobURLRequestInterceptor() {}
~MockHTTPSJobURLRequestInterceptor()2868 ~MockHTTPSJobURLRequestInterceptor() override {}
2869
2870 // net::URLRequestInterceptor:
MaybeInterceptRequest(net::URLRequest * request) const2871 std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
2872 net::URLRequest* request) const override {
2873 return std::make_unique<MockHTTPSURLRequestJob>(request, std::string(),
2874 "dummy response", true);
2875 }
2876 };
2877
2878 // Tests that |cert_status| is set on the resource response.
TEST_F(URLLoaderTest,CertStatusOnResponse)2879 TEST_F(URLLoaderTest, CertStatusOnResponse) {
2880 net::URLRequestFilter::GetInstance()->ClearHandlers();
2881 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
2882 "https", "example.test",
2883 std::unique_ptr<net::URLRequestInterceptor>(
2884 new MockHTTPSJobURLRequestInterceptor()));
2885
2886 EXPECT_EQ(net::OK, Load(GURL("https://example.test/")));
2887 EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
2888 client()->response_head()->cert_status);
2889 }
2890
2891 // Verifies if URLLoader works well with ResourceScheduler.
TEST_F(URLLoaderTest,ResourceSchedulerIntegration)2892 TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
2893 // ResourceScheduler limits the number of connections for the same host
2894 // by 6.
2895 constexpr int kRepeat = 6;
2896 constexpr char kPath[] = "/hello.html";
2897
2898 net::EmbeddedTestServer server;
2899 // This is needed to stall all requests to the server.
2900 net::test_server::ControllableHttpResponse response_controllers[kRepeat] = {
2901 {&server, kPath}, {&server, kPath}, {&server, kPath},
2902 {&server, kPath}, {&server, kPath}, {&server, kPath},
2903 };
2904
2905 ASSERT_TRUE(server.Start());
2906
2907 ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
2908 request.load_flags = net::LOAD_DISABLE_CACHE;
2909 request.priority = net::IDLE;
2910
2911 // Fill up the ResourceScheduler with delayable requests.
2912 std::vector<
2913 std::pair<std::unique_ptr<URLLoader>, mojo::Remote<mojom::URLLoader>>>
2914 loaders;
2915 mojom::URLLoaderFactoryParams params;
2916 params.process_id = kProcessId;
2917 params.is_corb_enabled = false;
2918 for (int i = 0; i < kRepeat; ++i) {
2919 TestURLLoaderClient client;
2920 mojo::PendingRemote<mojom::URLLoader> loader_remote;
2921
2922 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
2923 context(), nullptr /* network_service_client */,
2924 nullptr /* network_context_client */,
2925 NeverInvokedDeleteLoaderCallback(),
2926 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
2927 client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2928 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2929 /*coep_reporter=*/nullptr, 0 /* request_id */,
2930 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2931 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2932 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2933 mojo::NullRemote() /* cookie_observer */);
2934
2935 loaders.emplace_back(
2936 std::make_pair(std::move(url_loader), std::move(loader_remote)));
2937 }
2938
2939 base::RunLoop().RunUntilIdle();
2940 for (const auto& pair : loaders) {
2941 URLLoader* loader = pair.first.get();
2942 ASSERT_NE(loader, nullptr);
2943 EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_RESPONSE,
2944 loader->GetLoadStateForTesting());
2945 }
2946
2947 mojo::PendingRemote<mojom::URLLoader> loader_remote;
2948 std::unique_ptr<URLLoader> loader = std::make_unique<URLLoader>(
2949 context(), nullptr /* network_service_client */,
2950 nullptr /* network_context_client */, NeverInvokedDeleteLoaderCallback(),
2951 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
2952 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
2953 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
2954 /*coep_reporter=*/nullptr, 0 /* request_id */,
2955 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2956 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2957 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2958 mojo::NullRemote() /* cookie_observer */);
2959 base::RunLoop().RunUntilIdle();
2960
2961 // Make sure that the ResourceScheduler throttles this request.
2962 EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_DELEGATE,
2963 loader->GetLoadStateForTesting());
2964
2965 loader->SetPriority(net::HIGHEST, 0 /* intra_priority_value */);
2966 base::RunLoop().RunUntilIdle();
2967
2968 // Make sure that the ResourceScheduler stops throtting.
2969 EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET,
2970 loader->GetLoadStateForTesting());
2971 }
2972
2973 // This tests that case where a read pipe is closed while there's a post task to
2974 // invoke ReadMore.
TEST_F(URLLoaderTest,ReadPipeClosedWhileReadTaskPosted)2975 TEST_F(URLLoaderTest, ReadPipeClosedWhileReadTaskPosted) {
2976 AddEternalSyncReadsInterceptor();
2977
2978 ResourceRequest request = CreateResourceRequest(
2979 "GET", EternalSyncReadsInterceptor::GetSingleByteURL());
2980
2981 base::RunLoop delete_run_loop;
2982 mojo::PendingRemote<mojom::URLLoader> loader;
2983 std::unique_ptr<URLLoader> url_loader;
2984 mojom::URLLoaderFactoryParams params;
2985 params.process_id = mojom::kBrowserProcessId;
2986 params.is_corb_enabled = false;
2987 url_loader = std::make_unique<URLLoader>(
2988 context(), nullptr /* network_service_client */,
2989 nullptr /* network_context_client */,
2990 DeleteLoaderCallback(&delete_run_loop, &url_loader),
2991 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
2992 request, client()->CreateRemote(),
2993 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
2994 ¶ms,
2995 /*coep_reporter=*/nullptr, 0 /* request_id */,
2996 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
2997 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
2998 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
2999 mojo::NullRemote() /* cookie_observer */);
3000
3001 client()->RunUntilResponseBodyArrived();
3002 client()->response_body_release();
3003 delete_run_loop.Run();
3004 }
3005
3006 class FakeSSLPrivateKeyImpl : public network::mojom::SSLPrivateKey {
3007 public:
FakeSSLPrivateKeyImpl(scoped_refptr<net::SSLPrivateKey> ssl_private_key)3008 explicit FakeSSLPrivateKeyImpl(
3009 scoped_refptr<net::SSLPrivateKey> ssl_private_key)
3010 : ssl_private_key_(std::move(ssl_private_key)) {}
~FakeSSLPrivateKeyImpl()3011 ~FakeSSLPrivateKeyImpl() override {}
3012
3013 // network::mojom::SSLPrivateKey:
Sign(uint16_t algorithm,const std::vector<uint8_t> & input,network::mojom::SSLPrivateKey::SignCallback callback)3014 void Sign(uint16_t algorithm,
3015 const std::vector<uint8_t>& input,
3016 network::mojom::SSLPrivateKey::SignCallback callback) override {
3017 base::span<const uint8_t> input_span(input);
3018 ssl_private_key_->Sign(
3019 algorithm, input_span,
3020 base::BindOnce(&FakeSSLPrivateKeyImpl::Callback, base::Unretained(this),
3021 std::move(callback)));
3022 }
3023
3024 private:
Callback(network::mojom::SSLPrivateKey::SignCallback callback,net::Error net_error,const std::vector<uint8_t> & signature)3025 void Callback(network::mojom::SSLPrivateKey::SignCallback callback,
3026 net::Error net_error,
3027 const std::vector<uint8_t>& signature) {
3028 std::move(callback).Run(static_cast<int32_t>(net_error), signature);
3029 }
3030
3031 scoped_refptr<net::SSLPrivateKey> ssl_private_key_;
3032
3033 DISALLOW_COPY_AND_ASSIGN(FakeSSLPrivateKeyImpl);
3034 };
3035
3036 using CookieAccessType = mojom::CookieAccessDetails::Type;
3037
3038 class MockCookieObserver : public network::mojom::CookieAccessObserver {
3039 public:
MockCookieObserver(base::Optional<CookieAccessType> access_type=base::nullopt)3040 explicit MockCookieObserver(
3041 base::Optional<CookieAccessType> access_type = base::nullopt)
3042 : access_type_(access_type) {}
3043 ~MockCookieObserver() override = default;
3044
3045 struct CookieDetails {
CookieDetailsnetwork::MockCookieObserver::CookieDetails3046 CookieDetails(const mojom::CookieAccessDetailsPtr& details,
3047 const net::CookieWithAccessResult cookie)
3048 : type(details->type),
3049 name(cookie.cookie.Name()),
3050 value(cookie.cookie.Value()),
3051 is_include(cookie.access_result.status.IsInclude()),
3052 url(details->url),
3053 status(cookie.access_result.status) {}
3054
CookieDetailsnetwork::MockCookieObserver::CookieDetails3055 CookieDetails(CookieAccessType type,
3056 std::string name,
3057 std::string value,
3058 bool is_include)
3059 : type(type), name(name), value(value), is_include(is_include) {}
3060
operator ==network::MockCookieObserver::CookieDetails3061 bool operator==(const CookieDetails& other) const {
3062 return type == other.type && name == other.name && value == other.value &&
3063 is_include == other.is_include;
3064 }
3065
3066 CookieAccessType type;
3067 std::string name;
3068 std::string value;
3069 bool is_include;
3070
3071 // The full details are available for the tests to query manually, but
3072 // they are not covered by operator== (and testing::ElementsAre).
3073 GURL url;
3074 net::CookieInclusionStatus status;
3075 };
3076
GetRemote()3077 mojo::PendingRemote<mojom::CookieAccessObserver> GetRemote() {
3078 mojo::PendingRemote<mojom::CookieAccessObserver> remote;
3079 receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
3080 return remote;
3081 }
3082
OnCookiesAccessed(mojom::CookieAccessDetailsPtr details)3083 void OnCookiesAccessed(mojom::CookieAccessDetailsPtr details) override {
3084 if (access_type_ && access_type_ != details->type)
3085 return;
3086
3087 for (const auto& cookie_with_status : details->cookie_list) {
3088 observed_cookies_.emplace_back(details, cookie_with_status);
3089 }
3090 if (wait_for_cookie_count_ &&
3091 observed_cookies().size() >= wait_for_cookie_count_) {
3092 std::move(wait_for_cookies_quit_closure_).Run();
3093 }
3094 }
3095
WaitForCookies(size_t cookie_count)3096 void WaitForCookies(size_t cookie_count) {
3097 if (observed_cookies_.size() < cookie_count) {
3098 wait_for_cookie_count_ = cookie_count;
3099 base::RunLoop run_loop;
3100 wait_for_cookies_quit_closure_ = run_loop.QuitClosure();
3101 run_loop.Run();
3102 }
3103 EXPECT_EQ(observed_cookies_.size(), cookie_count);
3104 }
3105
Clone(mojo::PendingReceiver<mojom::CookieAccessObserver> observer)3106 void Clone(
3107 mojo::PendingReceiver<mojom::CookieAccessObserver> observer) override {
3108 receivers_.Add(this, std::move(observer));
3109 }
3110
observed_cookies()3111 const std::vector<CookieDetails>& observed_cookies() {
3112 return observed_cookies_;
3113 }
3114
3115 private:
3116 base::Optional<CookieAccessType> access_type_;
3117 size_t wait_for_cookie_count_ = 0;
3118 base::OnceClosure wait_for_cookies_quit_closure_;
3119 std::vector<CookieDetails> observed_cookies_;
3120 mojo::ReceiverSet<mojom::CookieAccessObserver> receivers_;
3121 };
3122
3123 class MockNetworkServiceClient : public TestNetworkServiceClient {
3124 public:
3125 MockNetworkServiceClient() = default;
3126 ~MockNetworkServiceClient() override = default;
3127
3128 // mojom::NetworkServiceClient:
OnRawRequest(int32_t process_id,int32_t routing_id,const std::string & devtools_request_id,const net::CookieAccessResultList & cookies_with_access_result,std::vector<network::mojom::HttpRawHeaderPairPtr> headers)3129 void OnRawRequest(
3130 int32_t process_id,
3131 int32_t routing_id,
3132 const std::string& devtools_request_id,
3133 const net::CookieAccessResultList& cookies_with_access_result,
3134 std::vector<network::mojom::HttpRawHeaderPairPtr> headers) override {
3135 raw_request_cookies_.insert(raw_request_cookies_.end(),
3136 cookies_with_access_result.begin(),
3137 cookies_with_access_result.end());
3138
3139 devtools_request_id_ = devtools_request_id;
3140
3141 if (wait_for_raw_request_ &&
3142 raw_request_cookies_.size() >= wait_for_raw_request_goal_) {
3143 std::move(wait_for_raw_request_).Run();
3144 }
3145 }
3146
OnRawResponse(int32_t process_id,int32_t routing_id,const std::string & devtools_request_id,const net::CookieAndLineAccessResultList & cookies_with_access_result,std::vector<network::mojom::HttpRawHeaderPairPtr> headers,const base::Optional<std::string> & raw_response_headers)3147 void OnRawResponse(
3148 int32_t process_id,
3149 int32_t routing_id,
3150 const std::string& devtools_request_id,
3151 const net::CookieAndLineAccessResultList& cookies_with_access_result,
3152 std::vector<network::mojom::HttpRawHeaderPairPtr> headers,
3153 const base::Optional<std::string>& raw_response_headers) override {
3154 raw_response_cookies_.insert(raw_response_cookies_.end(),
3155 cookies_with_access_result.begin(),
3156 cookies_with_access_result.end());
3157
3158 devtools_request_id_ = devtools_request_id;
3159
3160 raw_response_headers_ = raw_response_headers;
3161
3162 if (wait_for_raw_response_ &&
3163 raw_response_cookies_.size() >= wait_for_raw_response_goal_) {
3164 std::move(wait_for_raw_response_).Run();
3165 }
3166 }
3167
WaitUntilRawResponse(size_t goal)3168 void WaitUntilRawResponse(size_t goal) {
3169 if (raw_response_cookies_.size() < goal) {
3170 wait_for_raw_response_goal_ = goal;
3171 base::RunLoop run_loop;
3172 wait_for_raw_response_ = run_loop.QuitClosure();
3173 run_loop.Run();
3174 }
3175 EXPECT_EQ(goal, raw_response_cookies_.size());
3176 }
3177
WaitUntilRawRequest(size_t goal)3178 void WaitUntilRawRequest(size_t goal) {
3179 if (raw_request_cookies_.size() < goal) {
3180 wait_for_raw_request_goal_ = goal;
3181 base::RunLoop run_loop;
3182 wait_for_raw_request_ = run_loop.QuitClosure();
3183 run_loop.Run();
3184 }
3185 EXPECT_EQ(goal, raw_request_cookies_.size());
3186 }
3187
raw_response_cookies() const3188 const net::CookieAndLineAccessResultList& raw_response_cookies() const {
3189 return raw_response_cookies_;
3190 }
3191
raw_request_cookies() const3192 const net::CookieAccessResultList& raw_request_cookies() const {
3193 return raw_request_cookies_;
3194 }
3195
devtools_request_id()3196 const std::string devtools_request_id() { return devtools_request_id_; }
3197
raw_response_headers()3198 const base::Optional<std::string> raw_response_headers() {
3199 return raw_response_headers_;
3200 }
3201
3202 private:
3203 net::CookieAndLineAccessResultList raw_response_cookies_;
3204 base::OnceClosure wait_for_raw_response_;
3205 size_t wait_for_raw_response_goal_ = 0u;
3206 std::string devtools_request_id_;
3207 base::Optional<std::string> raw_response_headers_;
3208
3209 net::CookieAccessResultList raw_request_cookies_;
3210 base::OnceClosure wait_for_raw_request_;
3211 size_t wait_for_raw_request_goal_ = 0u;
3212
3213 DISALLOW_COPY_AND_ASSIGN(MockNetworkServiceClient);
3214 };
3215
3216 // 1. Responds auth challenges with previously set credentials.
3217 // 2. Responds certificate request with previously set responses.
3218 // 2. Records any reported cookie activity.
3219 class MockNetworkContextClient : public TestNetworkContextClient {
3220 public:
3221 enum class CredentialsResponse {
3222 NO_CREDENTIALS,
3223 CORRECT_CREDENTIALS,
3224 INCORRECT_CREDENTIALS_THEN_CORRECT_ONES,
3225 };
3226
3227 enum class CertificateResponse {
3228 INVALID = -1,
3229 URL_LOADER_REQUEST_CANCELLED,
3230 CANCEL_CERTIFICATE_SELECTION,
3231 NULL_CERTIFICATE,
3232 VALID_CERTIFICATE_SIGNATURE,
3233 INVALID_CERTIFICATE_SIGNATURE,
3234 DESTROY_CLIENT_CERT_RESPONDER,
3235 };
3236
3237 MockNetworkContextClient() = default;
3238 ~MockNetworkContextClient() override = default;
3239
OnAuthRequired(const base::Optional<base::UnguessableToken> & window_id,int32_t process_id,int32_t routing_id,uint32_t request_id,const GURL & url,bool first_auth_attempt,const net::AuthChallengeInfo & auth_info,network::mojom::URLResponseHeadPtr head,mojo::PendingRemote<mojom::AuthChallengeResponder> auth_challenge_responder)3240 void OnAuthRequired(const base::Optional<base::UnguessableToken>& window_id,
3241 int32_t process_id,
3242 int32_t routing_id,
3243 uint32_t request_id,
3244 const GURL& url,
3245 bool first_auth_attempt,
3246 const net::AuthChallengeInfo& auth_info,
3247 network::mojom::URLResponseHeadPtr head,
3248 mojo::PendingRemote<mojom::AuthChallengeResponder>
3249 auth_challenge_responder) override {
3250 if (head)
3251 EXPECT_TRUE(head->auth_challenge_info.has_value());
3252 switch (credentials_response_) {
3253 case CredentialsResponse::NO_CREDENTIALS:
3254 auth_credentials_ = base::nullopt;
3255 break;
3256 case CredentialsResponse::CORRECT_CREDENTIALS:
3257 auth_credentials_ = net::AuthCredentials(base::ASCIIToUTF16("USER"),
3258 base::ASCIIToUTF16("PASS"));
3259 break;
3260 case CredentialsResponse::INCORRECT_CREDENTIALS_THEN_CORRECT_ONES:
3261 auth_credentials_ = net::AuthCredentials(base::ASCIIToUTF16("USER"),
3262 base::ASCIIToUTF16("FAIL"));
3263 credentials_response_ = CredentialsResponse::CORRECT_CREDENTIALS;
3264 break;
3265 }
3266 mojo::Remote<mojom::AuthChallengeResponder> auth_challenge_responder_remote(
3267 std::move(auth_challenge_responder));
3268 auth_challenge_responder_remote->OnAuthCredentials(auth_credentials_);
3269 ++on_auth_required_call_counter_;
3270 last_seen_response_headers_ = head ? head->headers : nullptr;
3271 }
3272
OnCertificateRequested(const base::Optional<base::UnguessableToken> & window_id,int32_t process_id,int32_t routing_id,uint32_t request_id,const scoped_refptr<net::SSLCertRequestInfo> & cert_info,mojo::PendingRemote<mojom::ClientCertificateResponder> client_cert_responder_remote)3273 void OnCertificateRequested(
3274 const base::Optional<base::UnguessableToken>& window_id,
3275 int32_t process_id,
3276 int32_t routing_id,
3277 uint32_t request_id,
3278 const scoped_refptr<net::SSLCertRequestInfo>& cert_info,
3279 mojo::PendingRemote<mojom::ClientCertificateResponder>
3280 client_cert_responder_remote) override {
3281 mojo::Remote<mojom::ClientCertificateResponder> client_cert_responder(
3282 std::move(client_cert_responder_remote));
3283 switch (certificate_response_) {
3284 case CertificateResponse::INVALID:
3285 NOTREACHED();
3286 break;
3287 case CertificateResponse::URL_LOADER_REQUEST_CANCELLED:
3288 ASSERT_TRUE(url_loader_remote_);
3289 url_loader_remote_->reset();
3290 break;
3291 case CertificateResponse::CANCEL_CERTIFICATE_SELECTION:
3292 client_cert_responder->CancelRequest();
3293 break;
3294 case CertificateResponse::NULL_CERTIFICATE:
3295 client_cert_responder->ContinueWithoutCertificate();
3296 break;
3297 case CertificateResponse::VALID_CERTIFICATE_SIGNATURE:
3298 case CertificateResponse::INVALID_CERTIFICATE_SIGNATURE:
3299 client_cert_responder->ContinueWithCertificate(
3300 std::move(certificate_), provider_name_, algorithm_preferences_,
3301 std::move(ssl_private_key_remote_));
3302 break;
3303 case CertificateResponse::DESTROY_CLIENT_CERT_RESPONDER:
3304 // Send no response and let the local variable be destroyed.
3305 break;
3306 }
3307 ++on_certificate_requested_counter_;
3308 }
3309
set_credentials_response(CredentialsResponse credentials_response)3310 void set_credentials_response(CredentialsResponse credentials_response) {
3311 credentials_response_ = credentials_response;
3312 }
3313
on_auth_required_call_counter()3314 int on_auth_required_call_counter() { return on_auth_required_call_counter_; }
3315
last_seen_response_headers()3316 net::HttpResponseHeaders* last_seen_response_headers() {
3317 return last_seen_response_headers_.get();
3318 }
3319
set_certificate_response(CertificateResponse certificate_response)3320 void set_certificate_response(CertificateResponse certificate_response) {
3321 certificate_response_ = certificate_response;
3322 }
3323
set_private_key(scoped_refptr<net::SSLPrivateKey> ssl_private_key)3324 void set_private_key(scoped_refptr<net::SSLPrivateKey> ssl_private_key) {
3325 ssl_private_key_ = std::move(ssl_private_key);
3326 provider_name_ = ssl_private_key_->GetProviderName();
3327 algorithm_preferences_ = ssl_private_key_->GetAlgorithmPreferences();
3328 mojo::MakeSelfOwnedReceiver(
3329 std::make_unique<FakeSSLPrivateKeyImpl>(std::move(ssl_private_key_)),
3330 ssl_private_key_remote_.InitWithNewPipeAndPassReceiver());
3331 }
3332
set_certificate(scoped_refptr<net::X509Certificate> certificate)3333 void set_certificate(scoped_refptr<net::X509Certificate> certificate) {
3334 certificate_ = std::move(certificate);
3335 }
3336
on_certificate_requested_counter()3337 int on_certificate_requested_counter() {
3338 return on_certificate_requested_counter_;
3339 }
3340
set_url_loader_remote(mojo::Remote<mojom::URLLoader> * url_loader_remote)3341 void set_url_loader_remote(
3342 mojo::Remote<mojom::URLLoader>* url_loader_remote) {
3343 url_loader_remote_ = url_loader_remote;
3344 }
3345
3346 private:
3347 CredentialsResponse credentials_response_ =
3348 CredentialsResponse::NO_CREDENTIALS;
3349 base::Optional<net::AuthCredentials> auth_credentials_;
3350 int on_auth_required_call_counter_ = 0;
3351 scoped_refptr<net::HttpResponseHeaders> last_seen_response_headers_;
3352 CertificateResponse certificate_response_ = CertificateResponse::INVALID;
3353 scoped_refptr<net::SSLPrivateKey> ssl_private_key_;
3354 scoped_refptr<net::X509Certificate> certificate_;
3355 mojo::PendingRemote<network::mojom::SSLPrivateKey> ssl_private_key_remote_;
3356 std::string provider_name_;
3357 std::vector<uint16_t> algorithm_preferences_;
3358 int on_certificate_requested_counter_ = 0;
3359 mojo::Remote<mojom::URLLoader>* url_loader_remote_ = nullptr;
3360
3361 DISALLOW_COPY_AND_ASSIGN(MockNetworkContextClient);
3362 };
3363
TEST_F(URLLoaderTest,SetAuth)3364 TEST_F(URLLoaderTest, SetAuth) {
3365 MockNetworkServiceClient network_service_client;
3366 MockNetworkContextClient network_context_client;
3367 network_context_client.set_credentials_response(
3368 MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
3369
3370 ResourceRequest request =
3371 CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
3372 base::RunLoop delete_run_loop;
3373 mojo::PendingRemote<mojom::URLLoader> loader;
3374 mojom::URLLoaderFactoryParams params;
3375 params.process_id = kProcessId;
3376 params.is_corb_enabled = false;
3377 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3378 context(), &network_service_client, &network_context_client,
3379 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3380 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3381 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3382 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3383 /*coep_reporter=*/nullptr, 0 /* request_id */,
3384 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3385 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3386 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3387 mojo::NullRemote() /* cookie_observer */);
3388 base::RunLoop().RunUntilIdle();
3389
3390 ASSERT_TRUE(url_loader);
3391
3392 client()->RunUntilResponseBodyArrived();
3393 EXPECT_TRUE(client()->has_received_response());
3394 EXPECT_FALSE(client()->has_received_completion());
3395
3396 // Spin the message loop until the delete callback is invoked, and then delete
3397 // the URLLoader.
3398 delete_run_loop.Run();
3399
3400 client()->RunUntilComplete();
3401 EXPECT_TRUE(client()->has_received_completion());
3402 scoped_refptr<net::HttpResponseHeaders> headers =
3403 client()->response_head()->headers;
3404 ASSERT_TRUE(headers);
3405 EXPECT_EQ(200, headers->response_code());
3406 EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
3407 ASSERT_FALSE(url_loader);
3408 EXPECT_FALSE(client()->response_head()->auth_challenge_info.has_value());
3409 }
3410
TEST_F(URLLoaderTest,CancelAuth)3411 TEST_F(URLLoaderTest, CancelAuth) {
3412 MockNetworkServiceClient network_service_client;
3413 MockNetworkContextClient network_context_client;
3414 network_context_client.set_credentials_response(
3415 MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
3416
3417 ResourceRequest request =
3418 CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
3419 base::RunLoop delete_run_loop;
3420 mojo::PendingRemote<mojom::URLLoader> loader;
3421 mojom::URLLoaderFactoryParams params;
3422 params.process_id = kProcessId;
3423 params.is_corb_enabled = false;
3424 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3425 context(), &network_service_client, &network_context_client,
3426 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3427 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3428 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3429 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3430 /*coep_reporter=*/nullptr, 0 /* request_id */,
3431 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3432 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3433 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3434 mojo::NullRemote() /* cookie_observer */);
3435 base::RunLoop().RunUntilIdle();
3436
3437 ASSERT_TRUE(url_loader);
3438
3439 client()->RunUntilResponseBodyArrived();
3440 EXPECT_TRUE(client()->has_received_response());
3441 EXPECT_FALSE(client()->has_received_completion());
3442
3443 // Spin the message loop until the delete callback is invoked, and then delete
3444 // the URLLoader.
3445 delete_run_loop.Run();
3446
3447 client()->RunUntilComplete();
3448 EXPECT_TRUE(client()->has_received_completion());
3449 scoped_refptr<net::HttpResponseHeaders> headers =
3450 client()->response_head()->headers;
3451 ASSERT_TRUE(headers);
3452 EXPECT_EQ(401, headers->response_code());
3453 EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
3454 ASSERT_FALSE(url_loader);
3455 }
3456
TEST_F(URLLoaderTest,TwoChallenges)3457 TEST_F(URLLoaderTest, TwoChallenges) {
3458 MockNetworkServiceClient network_service_client;
3459 MockNetworkContextClient network_context_client;
3460 network_context_client.set_credentials_response(
3461 MockNetworkContextClient::CredentialsResponse::
3462 INCORRECT_CREDENTIALS_THEN_CORRECT_ONES);
3463
3464 ResourceRequest request =
3465 CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
3466 base::RunLoop delete_run_loop;
3467 mojo::PendingRemote<mojom::URLLoader> loader;
3468 mojom::URLLoaderFactoryParams params;
3469 params.process_id = kProcessId;
3470 params.is_corb_enabled = false;
3471 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3472 context(), &network_service_client, &network_context_client,
3473 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3474 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3475 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3476 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3477 /*coep_reporter=*/nullptr, 0 /* request_id */,
3478 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3479 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3480 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3481 mojo::NullRemote() /* cookie_observer */);
3482 base::RunLoop().RunUntilIdle();
3483
3484 ASSERT_TRUE(url_loader);
3485
3486 client()->RunUntilResponseBodyArrived();
3487 EXPECT_TRUE(client()->has_received_response());
3488 EXPECT_FALSE(client()->has_received_completion());
3489
3490 // Spin the message loop until the delete callback is invoked, and then delete
3491 // the URLLoader.
3492 delete_run_loop.Run();
3493
3494 client()->RunUntilComplete();
3495 EXPECT_TRUE(client()->has_received_completion());
3496 scoped_refptr<net::HttpResponseHeaders> headers =
3497 client()->response_head()->headers;
3498 ASSERT_TRUE(headers);
3499 EXPECT_EQ(200, headers->response_code());
3500 EXPECT_EQ(2, network_context_client.on_auth_required_call_counter());
3501 ASSERT_FALSE(url_loader);
3502 }
3503
TEST_F(URLLoaderTest,NoAuthRequiredForFavicon)3504 TEST_F(URLLoaderTest, NoAuthRequiredForFavicon) {
3505 constexpr char kFaviconTestPage[] = "/has_favicon.html";
3506
3507 MockNetworkServiceClient network_service_client;
3508 MockNetworkContextClient network_context_client;
3509 network_context_client.set_credentials_response(
3510 MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
3511
3512 ResourceRequest request =
3513 CreateResourceRequest("GET", test_server()->GetURL(kFaviconTestPage));
3514 base::RunLoop delete_run_loop;
3515 mojo::PendingRemote<mojom::URLLoader> loader;
3516 mojom::URLLoaderFactoryParams params;
3517 params.process_id = kProcessId;
3518 params.is_corb_enabled = false;
3519 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3520 context(), &network_service_client, &network_context_client,
3521 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3522 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3523 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3524 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3525 /*coep_reporter=*/nullptr, 0 /* request_id */,
3526 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3527 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3528 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3529 mojo::NullRemote() /* cookie_observer */);
3530 base::RunLoop().RunUntilIdle();
3531
3532 ASSERT_TRUE(url_loader);
3533
3534 client()->RunUntilResponseBodyArrived();
3535 EXPECT_TRUE(client()->has_received_response());
3536 EXPECT_FALSE(client()->has_received_completion());
3537
3538 // Spin the message loop until the delete callback is invoked, and then delete
3539 // the URLLoader.
3540 delete_run_loop.Run();
3541
3542 client()->RunUntilComplete();
3543 EXPECT_TRUE(client()->has_received_completion());
3544 scoped_refptr<net::HttpResponseHeaders> headers =
3545 client()->response_head()->headers;
3546 ASSERT_TRUE(headers);
3547 EXPECT_EQ(200, headers->response_code());
3548 // No auth required for favicon.
3549 EXPECT_EQ(0, network_context_client.on_auth_required_call_counter());
3550 ASSERT_FALSE(url_loader);
3551 }
3552
TEST_F(URLLoaderTest,HttpAuthResponseHeadersAvailable)3553 TEST_F(URLLoaderTest, HttpAuthResponseHeadersAvailable) {
3554 MockNetworkServiceClient network_service_client;
3555 MockNetworkContextClient network_context_client;
3556 network_context_client.set_credentials_response(
3557 MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
3558
3559 ResourceRequest request =
3560 CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
3561 base::RunLoop delete_run_loop;
3562 mojo::PendingRemote<mojom::URLLoader> loader;
3563 mojom::URLLoaderFactoryParams params;
3564 params.process_id = kProcessId;
3565 params.is_corb_enabled = false;
3566 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3567 context(), &network_service_client, &network_context_client,
3568 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3569 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3570 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3571 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3572 /*coep_reporter=*/nullptr, 0 /* request_id */,
3573 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3574 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3575 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3576 mojo::NullRemote() /* cookie_observer */);
3577 base::RunLoop().RunUntilIdle();
3578
3579 ASSERT_TRUE(url_loader);
3580
3581 client()->RunUntilResponseBodyArrived();
3582
3583 // Spin the message loop until the delete callback is invoked, and then delete
3584 // the URLLoader.
3585 delete_run_loop.Run();
3586
3587 EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
3588
3589 auto* auth_required_headers =
3590 network_context_client.last_seen_response_headers();
3591 ASSERT_TRUE(auth_required_headers);
3592 EXPECT_EQ(auth_required_headers->response_code(), 401);
3593 }
3594
3595 // This simulates plugins without universal access, like PNaCl. These make
3596 // cross-origin fetches with CORS, and we expect CORB to block them.
TEST_F(URLLoaderTest,CorbEffectiveWithCors)3597 TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
3598 int kResourceType = 1;
3599 ResourceRequest request =
3600 CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
3601 request.resource_type = kResourceType;
3602 request.mode = mojom::RequestMode::kCors;
3603 request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
3604 request.corb_excluded = true;
3605
3606 base::RunLoop delete_run_loop;
3607 mojo::PendingRemote<mojom::URLLoader> loader;
3608 std::unique_ptr<URLLoader> url_loader;
3609 mojom::URLLoaderFactoryParams params;
3610 url_loader = std::make_unique<URLLoader>(
3611 context(), nullptr /* network_service_client */,
3612 nullptr /* network_context_client */,
3613 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3614 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3615 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3616 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3617 /*coep_reporter=*/nullptr, 0 /* request_id */,
3618 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3619 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3620 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3621 mojo::NullRemote() /* cookie_observer */);
3622
3623 client()->RunUntilResponseBodyArrived();
3624 std::string body = ReadBody();
3625
3626 client()->RunUntilComplete();
3627
3628 delete_run_loop.Run();
3629
3630 // Blocked because this is a cross-origin request made with a CORS request
3631 // header, but without a valid CORS response header.
3632 // request.corb_excluded does not apply in that case.
3633 ASSERT_EQ(std::string(), body);
3634 }
3635
3636 // This simulates plugins with universal access, like Flash. These can make
3637 // cross-origin requests that are not subject to CORB.
TEST_F(URLLoaderTest,CorbExcludedWithNoCors)3638 TEST_F(URLLoaderTest, CorbExcludedWithNoCors) {
3639 int kResourceType = 1;
3640 ResourceRequest request =
3641 CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
3642 request.resource_type = kResourceType;
3643 request.mode = mojom::RequestMode::kNoCors;
3644 request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
3645 request.corb_excluded = true;
3646
3647 base::RunLoop delete_run_loop;
3648 mojo::PendingRemote<mojom::URLLoader> loader;
3649 std::unique_ptr<URLLoader> url_loader;
3650 mojom::URLLoaderFactoryParams params;
3651 params.process_id = 123;
3652 CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(123);
3653 url_loader = std::make_unique<URLLoader>(
3654 context(), nullptr /* network_service_client */,
3655 nullptr /* network_context_client */,
3656 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3657 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3658 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3659 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3660 /*coep_reporter=*/nullptr, 0 /* request_id */,
3661 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3662 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3663 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3664 mojo::NullRemote() /* cookie_observer */);
3665
3666 client()->RunUntilResponseBodyArrived();
3667 std::string body = ReadBody();
3668
3669 client()->RunUntilComplete();
3670
3671 delete_run_loop.Run();
3672
3673 // The request body is allowed through because CORB isn't applied.
3674 ASSERT_NE(std::string(), body);
3675
3676 CrossOriginReadBlockingExceptionForPlugin::RemoveExceptionForPlugin(123);
3677 }
3678
3679 // This simulates a renderer that pretends to be proxying requests for Flash
3680 // (when browser didn't actually confirm that Flash is hosted by the given
3681 // process via
3682 // CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin). We should
3683 // still apply CORB in this case.
TEST_F(URLLoaderTest,CorbEffectiveWithNoCorsWhenNoActualPlugin)3684 TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
3685 int kResourceType = 1;
3686 ResourceRequest request =
3687 CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
3688 request.resource_type = kResourceType;
3689 request.mode = mojom::RequestMode::kNoCors;
3690 request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
3691 request.corb_excluded = true;
3692
3693 base::RunLoop delete_run_loop;
3694 mojo::PendingRemote<mojom::URLLoader> loader;
3695 std::unique_ptr<URLLoader> url_loader;
3696 mojom::URLLoaderFactoryParams params;
3697 params.process_id = 234;
3698 // No call to
3699 // CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(123) -
3700 // this is what we primarily want to cover in this test.
3701 url_loader = std::make_unique<URLLoader>(
3702 context(), nullptr /* network_service_client */,
3703 nullptr /* network_context_client */,
3704 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3705 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3706 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3707 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3708 /*coep_reporter=*/nullptr, 0 /* request_id */,
3709 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3710 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3711 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3712 mojo::NullRemote() /* cookie_observer */);
3713
3714 client()->RunUntilResponseBodyArrived();
3715 std::string body = ReadBody();
3716
3717 client()->RunUntilComplete();
3718
3719 delete_run_loop.Run();
3720
3721 // The request body should be blocked by CORB.
3722 ASSERT_EQ(std::string(), body);
3723 }
3724
3725 // Make sure the client can't call FollowRedirect if there's no pending
3726 // redirect.
TEST_F(URLLoaderTest,FollowRedirectTwice)3727 TEST_F(URLLoaderTest, FollowRedirectTwice) {
3728 ResourceRequest request = CreateResourceRequest(
3729 "GET", test_server()->GetURL("/redirect307-to-echo"));
3730 request.headers.SetHeader("Header1", "Value1");
3731 request.headers.SetHeader("Header2", "Value2");
3732
3733 base::RunLoop delete_run_loop;
3734 mojo::PendingRemote<mojom::URLLoader> loader;
3735 std::unique_ptr<URLLoader> url_loader;
3736 mojom::URLLoaderFactoryParams params;
3737 params.process_id = mojom::kBrowserProcessId;
3738 params.is_corb_enabled = false;
3739 url_loader = std::make_unique<URLLoader>(
3740 context(), nullptr /* network_service_client */,
3741 nullptr /* network_context_client */,
3742 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3743 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
3744 request, client()->CreateRemote(),
3745 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
3746 ¶ms,
3747 /*coep_reporter=*/nullptr, 0 /* request_id */,
3748 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3749 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3750 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3751 mojo::NullRemote() /* cookie_observer */);
3752
3753 client()->RunUntilRedirectReceived();
3754
3755 url_loader->FollowRedirect({}, {}, {}, base::nullopt);
3756 EXPECT_DCHECK_DEATH(url_loader->FollowRedirect({}, {}, {}, base::nullopt));
3757
3758 client()->RunUntilComplete();
3759 delete_run_loop.Run();
3760 }
3761
3762 class TestSSLPrivateKey : public net::SSLPrivateKey {
3763 public:
TestSSLPrivateKey(scoped_refptr<net::SSLPrivateKey> key)3764 explicit TestSSLPrivateKey(scoped_refptr<net::SSLPrivateKey> key)
3765 : key_(std::move(key)) {}
3766
set_fail_signing(bool fail_signing)3767 void set_fail_signing(bool fail_signing) { fail_signing_ = fail_signing; }
sign_count() const3768 int sign_count() const { return sign_count_; }
3769
GetProviderName()3770 std::string GetProviderName() override { return key_->GetProviderName(); }
GetAlgorithmPreferences()3771 std::vector<uint16_t> GetAlgorithmPreferences() override {
3772 return key_->GetAlgorithmPreferences();
3773 }
Sign(uint16_t algorithm,base::span<const uint8_t> input,SignCallback callback)3774 void Sign(uint16_t algorithm,
3775 base::span<const uint8_t> input,
3776 SignCallback callback) override {
3777 sign_count_++;
3778 if (fail_signing_) {
3779 base::ThreadTaskRunnerHandle::Get()->PostTask(
3780 FROM_HERE, base::BindOnce(std::move(callback),
3781 net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED,
3782 std::vector<uint8_t>()));
3783 } else {
3784 key_->Sign(algorithm, input, std::move(callback));
3785 }
3786 }
3787
3788 private:
3789 ~TestSSLPrivateKey() override = default;
3790
3791 scoped_refptr<net::SSLPrivateKey> key_;
3792 bool fail_signing_ = false;
3793 int sign_count_ = 0;
3794
3795 DISALLOW_COPY_AND_ASSIGN(TestSSLPrivateKey);
3796 };
3797
3798 #if !defined(OS_IOS)
TEST_F(URLLoaderTest,ClientAuthRespondTwice)3799 TEST_F(URLLoaderTest, ClientAuthRespondTwice) {
3800 // This tests that one URLLoader can handle two client cert requests.
3801
3802 net::SSLServerConfig ssl_config;
3803 ssl_config.client_cert_type =
3804 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
3805
3806 net::EmbeddedTestServer test_server_1(net::EmbeddedTestServer::TYPE_HTTPS);
3807 test_server_1.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
3808 test_server_1.AddDefaultHandlers(
3809 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
3810 ASSERT_TRUE(test_server_1.Start());
3811
3812 net::EmbeddedTestServer test_server_2(net::EmbeddedTestServer::TYPE_HTTPS);
3813 test_server_2.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
3814 test_server_2.AddDefaultHandlers(
3815 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
3816 ASSERT_TRUE(test_server_2.Start());
3817
3818 std::unique_ptr<net::FakeClientCertIdentity> identity =
3819 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
3820 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
3821 ASSERT_TRUE(identity);
3822 scoped_refptr<TestSSLPrivateKey> private_key =
3823 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
3824
3825 MockNetworkServiceClient network_service_client;
3826 MockNetworkContextClient network_context_client;
3827 network_context_client.set_certificate_response(
3828 MockNetworkContextClient::CertificateResponse::
3829 VALID_CERTIFICATE_SIGNATURE);
3830 network_context_client.set_private_key(private_key);
3831 network_context_client.set_certificate(identity->certificate());
3832
3833 // Create a request to server_1 that will redirect to server_2
3834 ResourceRequest request = CreateResourceRequest(
3835 "GET",
3836 test_server_1.GetURL("/server-redirect-307?" +
3837 net::EscapeQueryParamValue(
3838 test_server_2.GetURL("/echo").spec(), true)));
3839
3840 base::RunLoop delete_run_loop;
3841 mojo::Remote<mojom::URLLoader> loader;
3842 std::unique_ptr<URLLoader> url_loader;
3843 mojom::URLLoaderFactoryParams params;
3844 params.process_id = kProcessId;
3845 params.is_corb_enabled = false;
3846 url_loader = std::make_unique<URLLoader>(
3847 context(), &network_service_client, &network_context_client,
3848 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3849 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
3850 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3851 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3852 /*coep_reporter=*/nullptr, 0 /* request_id */,
3853 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3854 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3855 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3856 mojo::NullRemote() /* cookie_observer */);
3857
3858 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
3859 EXPECT_EQ(0, private_key->sign_count());
3860
3861 client()->RunUntilRedirectReceived();
3862 loader->FollowRedirect({}, {}, {}, base::nullopt);
3863 // MockNetworkServiceClient gives away the private key when it invokes
3864 // ContinueWithCertificate, so we have to give it the key again.
3865 network_context_client.set_private_key(private_key);
3866 client()->RunUntilComplete();
3867 delete_run_loop.Run();
3868
3869 EXPECT_EQ(net::OK, client()->completion_status().error_code);
3870 EXPECT_EQ(2, network_context_client.on_certificate_requested_counter());
3871 EXPECT_EQ(2, private_key->sign_count());
3872 }
3873
TEST_F(URLLoaderTest,ClientAuthDestroyResponder)3874 TEST_F(URLLoaderTest, ClientAuthDestroyResponder) {
3875 // When URLLoader receives no message from the ClientCertificateResponder and
3876 // its connection errors out, we expect the request to be canceled rather than
3877 // just hang.
3878 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
3879 net::SSLServerConfig ssl_config;
3880 ssl_config.client_cert_type =
3881 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
3882 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
3883 test_server.AddDefaultHandlers(
3884 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
3885 ASSERT_TRUE(test_server.Start());
3886
3887 MockNetworkServiceClient network_service_client;
3888 MockNetworkContextClient network_context_client;
3889 network_context_client.set_certificate_response(
3890 MockNetworkContextClient::CertificateResponse::
3891 DESTROY_CLIENT_CERT_RESPONDER);
3892
3893 ResourceRequest request =
3894 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
3895 base::RunLoop delete_run_loop;
3896 mojo::Remote<mojom::URLLoader> loader;
3897 mojom::URLLoaderFactoryParams params;
3898 params.process_id = kProcessId;
3899 params.is_corb_enabled = false;
3900 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3901 context(), &network_service_client, &network_context_client,
3902 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3903 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
3904 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
3905 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
3906 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3907 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3908 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3909 mojo::NullRemote() /* cookie_observer */);
3910 network_context_client.set_url_loader_remote(&loader);
3911
3912 RunUntilIdle();
3913 ASSERT_TRUE(url_loader);
3914
3915 client()->RunUntilComplete();
3916
3917 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
3918 client()->completion_status().error_code);
3919 }
3920
TEST_F(URLLoaderTest,ClientAuthCancelConnection)3921 TEST_F(URLLoaderTest, ClientAuthCancelConnection) {
3922 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
3923 net::SSLServerConfig ssl_config;
3924 ssl_config.client_cert_type =
3925 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
3926 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
3927 test_server.AddDefaultHandlers(
3928 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
3929 ASSERT_TRUE(test_server.Start());
3930
3931 MockNetworkServiceClient network_service_client;
3932 MockNetworkContextClient network_context_client;
3933 network_context_client.set_certificate_response(
3934 MockNetworkContextClient::CertificateResponse::
3935 URL_LOADER_REQUEST_CANCELLED);
3936
3937 ResourceRequest request =
3938 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
3939 base::RunLoop delete_run_loop;
3940 mojo::Remote<mojom::URLLoader> loader;
3941 mojom::URLLoaderFactoryParams params;
3942 params.process_id = kProcessId;
3943 params.is_corb_enabled = false;
3944 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3945 context(), &network_service_client, &network_context_client,
3946 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3947 loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
3948 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
3949 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
3950 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3951 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3952 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3953 mojo::NullRemote() /* cookie_observer */);
3954 network_context_client.set_url_loader_remote(&loader);
3955
3956 RunUntilIdle();
3957 ASSERT_TRUE(url_loader);
3958
3959 client()->RunUntilComplete();
3960
3961 EXPECT_EQ(net::ERR_FAILED, client()->completion_status().error_code);
3962 }
3963
TEST_F(URLLoaderTest,ClientAuthCancelCertificateSelection)3964 TEST_F(URLLoaderTest, ClientAuthCancelCertificateSelection) {
3965 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
3966 net::SSLServerConfig ssl_config;
3967 ssl_config.client_cert_type =
3968 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
3969 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
3970 test_server.AddDefaultHandlers(
3971 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
3972 ASSERT_TRUE(test_server.Start());
3973
3974 MockNetworkServiceClient network_service_client;
3975 MockNetworkContextClient network_context_client;
3976 network_context_client.set_certificate_response(
3977 MockNetworkContextClient::CertificateResponse::
3978 CANCEL_CERTIFICATE_SELECTION);
3979
3980 ResourceRequest request =
3981 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
3982 base::RunLoop delete_run_loop;
3983 mojo::PendingRemote<mojom::URLLoader> loader;
3984 mojom::URLLoaderFactoryParams params;
3985 params.process_id = kProcessId;
3986 params.is_corb_enabled = false;
3987 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
3988 context(), &network_service_client, &network_context_client,
3989 DeleteLoaderCallback(&delete_run_loop, &url_loader),
3990 loader.InitWithNewPipeAndPassReceiver(), 0, request,
3991 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
3992 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
3993 /*coep_reporter=*/nullptr, 0 /* request_id */,
3994 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
3995 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
3996 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
3997 mojo::NullRemote() /* cookie_observer */);
3998
3999 RunUntilIdle();
4000 ASSERT_TRUE(url_loader);
4001
4002 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4003
4004 client()->RunUntilComplete();
4005
4006 EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
4007 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
4008 client()->completion_status().error_code);
4009 }
4010
TEST_F(URLLoaderTest,ClientAuthNoCertificate)4011 TEST_F(URLLoaderTest, ClientAuthNoCertificate) {
4012 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4013 net::SSLServerConfig ssl_config;
4014 ssl_config.client_cert_type =
4015 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
4016
4017 // TLS 1.3 client auth errors show up post-handshake, resulting in a read
4018 // error which on Windows causes the socket to shutdown immediately before the
4019 // error is read.
4020 // TODO(crbug.com/906668): Add support for testing this in TLS 1.3.
4021 ssl_config.version_max = net::SSL_PROTOCOL_VERSION_TLS1_2;
4022
4023 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4024 test_server.AddDefaultHandlers(
4025 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4026 ASSERT_TRUE(test_server.Start());
4027
4028 MockNetworkServiceClient network_service_client;
4029 MockNetworkContextClient network_context_client;
4030 network_context_client.set_certificate_response(
4031 MockNetworkContextClient::CertificateResponse::NULL_CERTIFICATE);
4032
4033 ResourceRequest request =
4034 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
4035 base::RunLoop delete_run_loop;
4036 mojo::PendingRemote<mojom::URLLoader> loader;
4037 mojom::URLLoaderFactoryParams params;
4038 params.process_id = kProcessId;
4039 params.is_corb_enabled = false;
4040 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4041 context(), &network_service_client, &network_context_client,
4042 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4043 loader.InitWithNewPipeAndPassReceiver(), 0, request,
4044 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4045 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4046 /*coep_reporter=*/nullptr, 0 /* request_id */,
4047 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4048 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4049 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4050 mojo::NullRemote() /* cookie_observer */);
4051
4052 RunUntilIdle();
4053 ASSERT_TRUE(url_loader);
4054
4055 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4056
4057 client()->RunUntilComplete();
4058
4059 EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
4060 EXPECT_EQ(net::ERR_BAD_SSL_CLIENT_AUTH_CERT,
4061 client()->completion_status().error_code);
4062 }
4063
TEST_F(URLLoaderTest,ClientAuthCertificateWithValidSignature)4064 TEST_F(URLLoaderTest, ClientAuthCertificateWithValidSignature) {
4065 std::unique_ptr<net::FakeClientCertIdentity> identity =
4066 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
4067 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
4068 ASSERT_TRUE(identity);
4069 scoped_refptr<TestSSLPrivateKey> private_key =
4070 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
4071
4072 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4073 net::SSLServerConfig ssl_config;
4074 ssl_config.client_cert_type =
4075 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
4076 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4077 test_server.AddDefaultHandlers(
4078 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4079 ASSERT_TRUE(test_server.Start());
4080
4081 MockNetworkServiceClient network_service_client;
4082 MockNetworkContextClient network_context_client;
4083 network_context_client.set_certificate_response(
4084 MockNetworkContextClient::CertificateResponse::
4085 VALID_CERTIFICATE_SIGNATURE);
4086 network_context_client.set_private_key(private_key);
4087 scoped_refptr<net::X509Certificate> certificate =
4088 test_server.GetCertificate();
4089 network_context_client.set_certificate(std::move(certificate));
4090
4091 ResourceRequest request =
4092 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
4093 base::RunLoop delete_run_loop;
4094 mojo::PendingRemote<mojom::URLLoader> loader;
4095 mojom::URLLoaderFactoryParams params;
4096 params.process_id = kProcessId;
4097 params.is_corb_enabled = false;
4098 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4099 context(), &network_service_client, &network_context_client,
4100 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4101 loader.InitWithNewPipeAndPassReceiver(), 0, request,
4102 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4103 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4104 /*coep_reporter=*/nullptr, 0 /* request_id */,
4105 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4106 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4107 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4108 mojo::NullRemote() /* cookie_observer */);
4109
4110 RunUntilIdle();
4111 ASSERT_TRUE(url_loader);
4112
4113 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4114 EXPECT_EQ(0, private_key->sign_count());
4115
4116 client()->RunUntilComplete();
4117
4118 EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
4119 // The private key should have been used.
4120 EXPECT_EQ(1, private_key->sign_count());
4121 }
4122
TEST_F(URLLoaderTest,ClientAuthCertificateWithInvalidSignature)4123 TEST_F(URLLoaderTest, ClientAuthCertificateWithInvalidSignature) {
4124 std::unique_ptr<net::FakeClientCertIdentity> identity =
4125 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
4126 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
4127 ASSERT_TRUE(identity);
4128 scoped_refptr<TestSSLPrivateKey> private_key =
4129 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
4130 private_key->set_fail_signing(true);
4131
4132 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4133 net::SSLServerConfig ssl_config;
4134 ssl_config.client_cert_type =
4135 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
4136 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4137 test_server.AddDefaultHandlers(
4138 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4139 ASSERT_TRUE(test_server.Start());
4140
4141 MockNetworkServiceClient network_service_client;
4142 MockNetworkContextClient network_context_client;
4143 network_context_client.set_certificate_response(
4144 MockNetworkContextClient::CertificateResponse::
4145 VALID_CERTIFICATE_SIGNATURE);
4146 network_context_client.set_private_key(private_key);
4147 scoped_refptr<net::X509Certificate> certificate =
4148 test_server.GetCertificate();
4149 network_context_client.set_certificate(std::move(certificate));
4150
4151 ResourceRequest request =
4152 CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
4153 base::RunLoop delete_run_loop;
4154 mojo::PendingRemote<mojom::URLLoader> loader;
4155 mojom::URLLoaderFactoryParams params;
4156 params.process_id = kProcessId;
4157 params.is_corb_enabled = false;
4158 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4159 context(), &network_service_client, &network_context_client,
4160 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4161 loader.InitWithNewPipeAndPassReceiver(), 0, request,
4162 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4163 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4164 /*coep_reporter=*/nullptr, 0 /* request_id */,
4165 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4166 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4167 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4168 mojo::NullRemote() /* cookie_observer */);
4169
4170 RunUntilIdle();
4171 ASSERT_TRUE(url_loader);
4172
4173 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4174 EXPECT_EQ(0, private_key->sign_count());
4175
4176 client()->RunUntilComplete();
4177
4178 EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
4179 // The private key should have been used.
4180 EXPECT_EQ(1, private_key->sign_count());
4181 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED,
4182 client()->completion_status().error_code);
4183 }
4184
TEST_F(URLLoaderTest,BlockAllCookies)4185 TEST_F(URLLoaderTest, BlockAllCookies) {
4186 MockNetworkServiceClient network_service_client;
4187
4188 GURL first_party_url("http://www.example.com.test/");
4189 net::SiteForCookies site_for_cookies =
4190 net::SiteForCookies::FromUrl(first_party_url);
4191 GURL third_party_url("http://www.some.other.origin.test/");
4192
4193 ResourceRequest request = CreateResourceRequest("GET", first_party_url);
4194 base::RunLoop delete_run_loop;
4195 mojo::PendingRemote<mojom::URLLoader> loader;
4196 mojom::URLLoaderFactoryParams params;
4197 params.process_id = kProcessId;
4198 params.is_corb_enabled = false;
4199 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4200 context(), &network_service_client, nullptr /* network_context_client */,
4201 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4202 loader.InitWithNewPipeAndPassReceiver(),
4203 mojom::kURLLoadOptionBlockAllCookies, request, client()->CreateRemote(),
4204 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
4205 ¶ms, /*coep_reporter=*/nullptr, 0 /* request_id */,
4206 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4207 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4208 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4209 mojo::NullRemote() /* cookie_observer */);
4210
4211 EXPECT_FALSE(url_loader->AllowCookies(first_party_url, site_for_cookies));
4212 EXPECT_FALSE(url_loader->AllowCookies(third_party_url, site_for_cookies));
4213 }
4214
TEST_F(URLLoaderTest,BlockOnlyThirdPartyCookies)4215 TEST_F(URLLoaderTest, BlockOnlyThirdPartyCookies) {
4216 MockNetworkServiceClient network_service_client;
4217
4218 GURL first_party_url("http://www.example.com.test/");
4219 net::SiteForCookies site_for_cookies =
4220 net::SiteForCookies::FromUrl(first_party_url);
4221 GURL third_party_url("http://www.some.other.origin.test/");
4222
4223 ResourceRequest request = CreateResourceRequest("GET", first_party_url);
4224 base::RunLoop delete_run_loop;
4225 mojo::PendingRemote<mojom::URLLoader> loader;
4226 mojom::URLLoaderFactoryParams params;
4227 params.process_id = kProcessId;
4228 params.is_corb_enabled = false;
4229 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4230 context(), &network_service_client, nullptr /* network_context_client */,
4231 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4232 loader.InitWithNewPipeAndPassReceiver(),
4233 mojom::kURLLoadOptionBlockThirdPartyCookies, request,
4234 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4235 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4236 /*coep_reporter=*/nullptr, 0 /* request_id */,
4237 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4238 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4239 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4240 mojo::NullRemote() /* cookie_observer */);
4241
4242 EXPECT_TRUE(url_loader->AllowCookies(first_party_url, site_for_cookies));
4243 EXPECT_FALSE(url_loader->AllowCookies(third_party_url, site_for_cookies));
4244 }
4245
TEST_F(URLLoaderTest,AllowAllCookies)4246 TEST_F(URLLoaderTest, AllowAllCookies) {
4247 MockNetworkServiceClient network_service_client;
4248
4249 GURL first_party_url("http://www.example.com.test/");
4250 net::SiteForCookies site_for_cookies =
4251 net::SiteForCookies::FromUrl(first_party_url);
4252 GURL third_party_url("http://www.some.other.origin.test/");
4253
4254 ResourceRequest request = CreateResourceRequest("GET", first_party_url);
4255 base::RunLoop delete_run_loop;
4256 mojo::PendingRemote<mojom::URLLoader> loader;
4257 mojom::URLLoaderFactoryParams params;
4258 params.process_id = kProcessId;
4259 params.is_corb_enabled = false;
4260 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4261 context(), &network_service_client, nullptr /* network_context_client */,
4262 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4263 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4264 request, client()->CreateRemote(),
4265 /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
4266 ¶ms,
4267 /*coep_reporter=*/nullptr, 0 /* request_id */,
4268 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4269 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4270 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4271 mojo::NullRemote() /* cookie_observer */);
4272
4273 EXPECT_TRUE(url_loader->AllowCookies(first_party_url, site_for_cookies));
4274 EXPECT_TRUE(url_loader->AllowCookies(third_party_url, site_for_cookies));
4275 }
4276
4277 // Tests that a request with CredentialsMode::kOmit still sends client
4278 // certificates. This should be removed when crbug.com/775438 is fixed.
TEST_F(URLLoaderTest,CredentialsModeOmit)4279 TEST_F(URLLoaderTest, CredentialsModeOmit) {
4280 // Set up a server that requires certificates.
4281 net::SSLServerConfig ssl_config;
4282 ssl_config.client_cert_type =
4283 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
4284 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4285 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4286 test_server.AddDefaultHandlers(
4287 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4288 ASSERT_TRUE(test_server.Start());
4289
4290 // Make sure the client has valid certificates.
4291 std::unique_ptr<net::FakeClientCertIdentity> identity =
4292 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
4293 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
4294 ASSERT_TRUE(identity);
4295 scoped_refptr<TestSSLPrivateKey> private_key =
4296 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
4297
4298 MockNetworkServiceClient network_service_client;
4299 MockNetworkContextClient network_context_client;
4300 network_context_client.set_certificate_response(
4301 MockNetworkContextClient::CertificateResponse::
4302 VALID_CERTIFICATE_SIGNATURE);
4303 network_context_client.set_private_key(private_key);
4304 network_context_client.set_certificate(identity->certificate());
4305
4306 ResourceRequest request =
4307 CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
4308 request.credentials_mode = mojom::CredentialsMode::kOmit;
4309
4310 base::RunLoop delete_run_loop;
4311 mojo::Remote<mojom::URLLoader> loader;
4312 std::unique_ptr<URLLoader> url_loader;
4313 mojom::URLLoaderFactoryParams params;
4314 params.process_id = kProcessId;
4315 params.is_corb_enabled = false;
4316 url_loader = std::make_unique<URLLoader>(
4317 context(), &network_service_client, &network_context_client,
4318 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4319 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4320 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4321 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4322 /*coep_reporter=*/nullptr, 0 /* request_id */,
4323 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4324 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4325 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4326 mojo::NullRemote() /* cookie_observer */);
4327
4328 client()->RunUntilComplete();
4329 delete_run_loop.Run();
4330
4331 EXPECT_EQ(net::OK, client()->completion_status().error_code);
4332 }
4333
4334 // Tests that a request with CredentialsMode::kOmitBug_775438_Workaround
4335 // doesn't send client certificates.
TEST_F(URLLoaderTest,CredentialsModeOmitWorkaround)4336 TEST_F(URLLoaderTest, CredentialsModeOmitWorkaround) {
4337 // Set up a server that requires certificates.
4338 net::SSLServerConfig ssl_config;
4339 ssl_config.client_cert_type =
4340 net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
4341 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4342 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4343 test_server.AddDefaultHandlers(
4344 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4345 ASSERT_TRUE(test_server.Start());
4346
4347 // Make sure the client has valid certificates.
4348 std::unique_ptr<net::FakeClientCertIdentity> identity =
4349 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
4350 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
4351 ASSERT_TRUE(identity);
4352 scoped_refptr<TestSSLPrivateKey> private_key =
4353 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
4354
4355 MockNetworkServiceClient network_service_client;
4356 MockNetworkContextClient network_context_client;
4357 network_context_client.set_certificate_response(
4358 MockNetworkContextClient::CertificateResponse::
4359 VALID_CERTIFICATE_SIGNATURE);
4360 network_context_client.set_private_key(private_key);
4361 network_context_client.set_certificate(identity->certificate());
4362
4363 ResourceRequest request =
4364 CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
4365 request.credentials_mode = mojom::CredentialsMode::kOmitBug_775438_Workaround;
4366
4367 base::RunLoop delete_run_loop;
4368 mojo::Remote<mojom::URLLoader> loader;
4369 std::unique_ptr<URLLoader> url_loader;
4370 mojom::URLLoaderFactoryParams params;
4371 params.process_id = kProcessId;
4372 params.is_corb_enabled = false;
4373 url_loader = std::make_unique<URLLoader>(
4374 context(), &network_service_client, &network_context_client,
4375 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4376 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4377 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4378 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4379 /*coep_reporter=*/nullptr, 0 /* request_id */,
4380 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4381 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4382 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4383 mojo::NullRemote() /* cookie_observer */);
4384
4385 client()->RunUntilComplete();
4386 delete_run_loop.Run();
4387
4388 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4389 EXPECT_NE(net::OK, client()->completion_status().error_code);
4390 }
4391
4392 // Tests that a request with CredentialsMode::kOmitBug_775438_Workaround
4393 // doesn't send client certificates with a server that optionally requires
4394 // certificates.
TEST_F(URLLoaderTest,CredentialsModeOmitWorkaroundWithOptionalCerts)4395 TEST_F(URLLoaderTest, CredentialsModeOmitWorkaroundWithOptionalCerts) {
4396 // Set up a server that requires certificates.
4397 net::SSLServerConfig ssl_config;
4398 ssl_config.client_cert_type =
4399 net::SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT;
4400 net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
4401 test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
4402 test_server.AddDefaultHandlers(
4403 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
4404 ASSERT_TRUE(test_server.Start());
4405
4406 // Make sure the client has valid certificates.
4407 std::unique_ptr<net::FakeClientCertIdentity> identity =
4408 net::FakeClientCertIdentity::CreateFromCertAndKeyFiles(
4409 net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
4410 ASSERT_TRUE(identity);
4411 scoped_refptr<TestSSLPrivateKey> private_key =
4412 base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
4413
4414 MockNetworkServiceClient network_service_client;
4415 MockNetworkContextClient network_context_client;
4416 network_context_client.set_certificate_response(
4417 MockNetworkContextClient::CertificateResponse::
4418 VALID_CERTIFICATE_SIGNATURE);
4419 network_context_client.set_private_key(private_key);
4420 network_context_client.set_certificate(identity->certificate());
4421
4422 ResourceRequest request =
4423 CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
4424 request.credentials_mode = mojom::CredentialsMode::kOmitBug_775438_Workaround;
4425
4426 base::RunLoop delete_run_loop;
4427 mojo::Remote<mojom::URLLoader> loader;
4428 std::unique_ptr<URLLoader> url_loader;
4429 mojom::URLLoaderFactoryParams params;
4430 params.process_id = kProcessId;
4431 params.is_corb_enabled = false;
4432 url_loader = std::make_unique<URLLoader>(
4433 context(), &network_service_client, &network_context_client,
4434 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4435 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4436 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4437 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4438 /*coep_reporter=*/nullptr, 0 /* request_id */,
4439 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4440 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4441 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4442 mojo::NullRemote() /* cookie_observer */);
4443
4444 client()->RunUntilComplete();
4445 delete_run_loop.Run();
4446
4447 EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
4448 EXPECT_EQ(net::OK, client()->completion_status().error_code);
4449 }
4450 #endif // !defined(OS_IOS)
4451
TEST_F(URLLoaderTest,CookieReporting)4452 TEST_F(URLLoaderTest, CookieReporting) {
4453 MockNetworkServiceClient network_service_client;
4454 MockNetworkContextClient network_context_client;
4455
4456 {
4457 TestURLLoaderClient loader_client;
4458 ResourceRequest request =
4459 CreateResourceRequest("GET", test_server()->GetURL("/set-cookie?a=b"));
4460
4461 MockCookieObserver cookie_observer;
4462 base::RunLoop delete_run_loop;
4463 mojo::PendingRemote<mojom::URLLoader> loader;
4464 mojom::URLLoaderFactoryParams params;
4465 params.process_id = kProcessId;
4466 params.is_corb_enabled = false;
4467 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4468 context(), &network_service_client, &network_context_client,
4469 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4470 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4471 request, loader_client.CreateRemote(),
4472 /*reponse_body_use_tracker=*/base::nullopt,
4473 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4474 0 /* request_id */, 0 /* keepalive_request_size */,
4475 resource_scheduler_client(), nullptr,
4476 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4477 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4478 cookie_observer.GetRemote());
4479
4480 delete_run_loop.Run();
4481 loader_client.RunUntilComplete();
4482 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4483
4484 cookie_observer.WaitForCookies(1u);
4485 EXPECT_THAT(cookie_observer.observed_cookies(),
4486 testing::ElementsAre(MockCookieObserver::CookieDetails{
4487 CookieAccessType::kChange, "a", "b", true}));
4488 }
4489
4490 {
4491 TestURLLoaderClient loader_client;
4492 ResourceRequest request =
4493 CreateResourceRequest("GET", test_server()->GetURL("/nocontent"));
4494
4495 MockCookieObserver cookie_observer;
4496 base::RunLoop delete_run_loop;
4497 mojo::PendingRemote<mojom::URLLoader> loader;
4498 mojom::URLLoaderFactoryParams params;
4499 params.process_id = kProcessId;
4500 params.is_corb_enabled = false;
4501 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4502 context(), &network_service_client, &network_context_client,
4503 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4504 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4505 request, loader_client.CreateRemote(),
4506 /*reponse_body_use_tracker=*/base::nullopt,
4507 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4508 0 /* request_id */, 0 /* keepalive_request_size */,
4509 resource_scheduler_client(), nullptr,
4510 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4511 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4512 cookie_observer.GetRemote());
4513
4514 delete_run_loop.Run();
4515 loader_client.RunUntilComplete();
4516 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4517
4518 cookie_observer.WaitForCookies(1u);
4519 EXPECT_THAT(cookie_observer.observed_cookies(),
4520 testing::ElementsAre(MockCookieObserver::CookieDetails{
4521 CookieAccessType::kRead, "a", "b", true}));
4522 }
4523 }
4524
TEST_F(URLLoaderTest,CookieReportingRedirect)4525 TEST_F(URLLoaderTest, CookieReportingRedirect) {
4526 MockNetworkServiceClient network_service_client;
4527 MockNetworkContextClient network_context_client;
4528 MockCookieObserver cookie_observer(CookieAccessType::kChange);
4529
4530 GURL dest_url = test_server()->GetURL("/nocontent");
4531 GURL redirecting_url =
4532 test_server()->GetURL("/server-redirect-with-cookie?" + dest_url.spec());
4533
4534 TestURLLoaderClient loader_client;
4535 ResourceRequest request = CreateResourceRequest("GET", redirecting_url);
4536
4537 base::RunLoop delete_run_loop;
4538 mojo::Remote<mojom::URLLoader> loader;
4539 mojom::URLLoaderFactoryParams params;
4540 params.process_id = kProcessId;
4541 params.is_corb_enabled = false;
4542 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4543 context(), &network_service_client, &network_context_client,
4544 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4545 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4546 loader_client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
4547 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4548 /*coep_reporter=*/nullptr, 0 /* request_id */,
4549 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4550 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4551 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4552 cookie_observer.GetRemote());
4553
4554 loader_client.RunUntilRedirectReceived();
4555 loader->FollowRedirect({}, {}, {}, base::nullopt);
4556 loader_client.RunUntilComplete();
4557 delete_run_loop.Run();
4558 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4559
4560 cookie_observer.WaitForCookies(1u);
4561 EXPECT_THAT(cookie_observer.observed_cookies(),
4562 testing::ElementsAre(MockCookieObserver::CookieDetails{
4563 CookieAccessType::kChange, "server-redirect", "true", true}));
4564 // Make sure that this has the pre-redirect URL, not the post-redirect one.
4565 EXPECT_EQ(redirecting_url, cookie_observer.observed_cookies()[0].url);
4566 }
4567
TEST_F(URLLoaderTest,CookieReportingAuth)4568 TEST_F(URLLoaderTest, CookieReportingAuth) {
4569 for (auto mode :
4570 {MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS,
4571 MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS}) {
4572 MockNetworkServiceClient network_service_client;
4573 MockNetworkContextClient network_context_client;
4574 MockCookieObserver cookie_observer(CookieAccessType::kChange);
4575 network_context_client.set_credentials_response(mode);
4576
4577 GURL url = test_server()->GetURL(
4578 "/auth-basic?set-cookie-if-challenged&password=PASS");
4579 TestURLLoaderClient loader_client;
4580 ResourceRequest request = CreateResourceRequest("GET", url);
4581
4582 base::RunLoop delete_run_loop;
4583 mojo::PendingRemote<mojom::URLLoader> loader;
4584 mojom::URLLoaderFactoryParams params;
4585 params.process_id = kProcessId;
4586 params.is_corb_enabled = false;
4587 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4588 context(), &network_service_client, &network_context_client,
4589 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4590 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4591 request, loader_client.CreateRemote(),
4592 /*reponse_body_use_tracker=*/base::nullopt,
4593 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4594 0 /* request_id */, 0 /* keepalive_request_size */,
4595 resource_scheduler_client(), nullptr,
4596 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4597 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4598 cookie_observer.GetRemote());
4599
4600 loader_client.RunUntilComplete();
4601 delete_run_loop.Run();
4602 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4603
4604 cookie_observer.WaitForCookies(1u);
4605 EXPECT_THAT(
4606 cookie_observer.observed_cookies(),
4607 testing::ElementsAre(MockCookieObserver::CookieDetails{
4608 CookieAccessType::kChange, "got_challenged", "true", true}));
4609 }
4610 }
4611
TEST_F(URLLoaderTest,RawRequestCookies)4612 TEST_F(URLLoaderTest, RawRequestCookies) {
4613 MockNetworkServiceClient network_service_client;
4614 MockNetworkContextClient network_context_client;
4615 {
4616 TestURLLoaderClient loader_client;
4617 ResourceRequest request = CreateResourceRequest(
4618 "GET", test_server()->GetURL("/echoheader?cookie"));
4619 // Set the devtools id to trigger the RawResponse call
4620 request.devtools_request_id = "TEST";
4621
4622 GURL cookie_url = test_server()->GetURL("/");
4623 auto cookie = net::CanonicalCookie::Create(
4624 cookie_url, "a=b", base::Time::Now(), base::nullopt /* server_time */);
4625 context()->cookie_store()->SetCanonicalCookieAsync(
4626 std::move(cookie), cookie_url, net::CookieOptions::MakeAllInclusive(),
4627 base::DoNothing());
4628
4629 base::RunLoop delete_run_loop;
4630 mojo::PendingRemote<mojom::URLLoader> loader;
4631 mojom::URLLoaderFactoryParams params;
4632 params.process_id = kProcessId;
4633 params.is_corb_enabled = false;
4634 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4635 context(), &network_service_client, &network_context_client,
4636 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4637 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4638 request, loader_client.CreateRemote(),
4639 /*reponse_body_use_tracker=*/base::nullopt,
4640 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4641 0 /* request_id */, 0 /* keepalive_request_size */,
4642 resource_scheduler_client(), nullptr,
4643 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4644 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4645 mojo::NullRemote() /* cookie_observer */);
4646
4647 delete_run_loop.Run();
4648 loader_client.RunUntilComplete();
4649 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4650
4651 network_service_client.WaitUntilRawRequest(1u);
4652 EXPECT_EQ("a",
4653 network_service_client.raw_request_cookies()[0].cookie.Name());
4654 EXPECT_EQ("b",
4655 network_service_client.raw_request_cookies()[0].cookie.Value());
4656 EXPECT_TRUE(network_service_client.raw_request_cookies()[0]
4657 .access_result.status.IsInclude());
4658
4659 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4660 }
4661 }
4662
TEST_F(URLLoaderTest,RawRequestCookiesFlagged)4663 TEST_F(URLLoaderTest, RawRequestCookiesFlagged) {
4664 MockNetworkServiceClient network_service_client;
4665 MockNetworkContextClient network_context_client;
4666 {
4667 TestURLLoaderClient loader_client;
4668 ResourceRequest request = CreateResourceRequest(
4669 "GET", test_server()->GetURL("/echoheader?cookie"));
4670 // Set the devtools id to trigger the RawResponse call
4671 request.devtools_request_id = "TEST";
4672
4673 // Set the path to an irrelevant url to block the cookie from sending
4674 GURL cookie_url = test_server()->GetURL("/");
4675 auto cookie = net::CanonicalCookie::Create(
4676 cookie_url, "a=b;Path=/something-else", base::Time::Now(),
4677 base::nullopt /* server_time */);
4678 context()->cookie_store()->SetCanonicalCookieAsync(
4679 std::move(cookie), cookie_url, net::CookieOptions::MakeAllInclusive(),
4680 base::DoNothing());
4681
4682 base::RunLoop delete_run_loop;
4683 mojo::PendingRemote<mojom::URLLoader> loader;
4684 mojom::URLLoaderFactoryParams params;
4685 params.process_id = kProcessId;
4686 params.is_corb_enabled = false;
4687 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4688 context(), &network_service_client, &network_context_client,
4689 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4690 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4691 request, loader_client.CreateRemote(),
4692 /*reponse_body_use_tracker=*/base::nullopt,
4693 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4694 0 /* request_id */, 0 /* keepalive_request_size */,
4695 resource_scheduler_client(), nullptr,
4696 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4697 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4698 mojo::NullRemote() /* cookie_observer */);
4699
4700 delete_run_loop.Run();
4701 loader_client.RunUntilComplete();
4702 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4703
4704 network_service_client.WaitUntilRawRequest(1u);
4705 EXPECT_EQ("a",
4706 network_service_client.raw_request_cookies()[0].cookie.Name());
4707 EXPECT_EQ("b",
4708 network_service_client.raw_request_cookies()[0].cookie.Value());
4709 EXPECT_TRUE(network_service_client.raw_request_cookies()[0]
4710 .access_result.status.HasExactlyExclusionReasonsForTesting(
4711 {net::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
4712
4713 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4714 }
4715 }
4716
TEST_F(URLLoaderTest,RawResponseCookies)4717 TEST_F(URLLoaderTest, RawResponseCookies) {
4718 MockNetworkServiceClient network_service_client;
4719 MockNetworkContextClient network_context_client;
4720 {
4721 TestURLLoaderClient loader_client;
4722 ResourceRequest request =
4723 CreateResourceRequest("GET", test_server()->GetURL("/set-cookie?a=b"));
4724 // Set the devtools id to trigger the RawResponse call
4725 request.devtools_request_id = "TEST";
4726
4727 base::RunLoop delete_run_loop;
4728 mojo::PendingRemote<mojom::URLLoader> loader;
4729 mojom::URLLoaderFactoryParams params;
4730 params.process_id = kProcessId;
4731 params.is_corb_enabled = false;
4732 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4733 context(), &network_service_client, &network_context_client,
4734 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4735 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4736 request, loader_client.CreateRemote(),
4737 /*reponse_body_use_tracker=*/base::nullopt,
4738 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4739 0 /* request_id */, 0 /* keepalive_request_size */,
4740 resource_scheduler_client(), nullptr,
4741 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4742 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4743 mojo::NullRemote() /* cookie_observer */);
4744
4745 delete_run_loop.Run();
4746 loader_client.RunUntilComplete();
4747 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4748
4749 network_service_client.WaitUntilRawResponse(1u);
4750 EXPECT_EQ("a",
4751 network_service_client.raw_response_cookies()[0].cookie->Name());
4752 EXPECT_EQ("b",
4753 network_service_client.raw_response_cookies()[0].cookie->Value());
4754 EXPECT_TRUE(network_service_client.raw_response_cookies()[0]
4755 .access_result.status.IsInclude());
4756
4757 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4758
4759 ASSERT_TRUE(network_service_client.raw_response_headers());
4760 EXPECT_NE(
4761 network_service_client.raw_response_headers()->find("Set-Cookie: a=b"),
4762 std::string::npos);
4763 }
4764 }
4765
TEST_F(URLLoaderTest,RawResponseCookiesInvalid)4766 TEST_F(URLLoaderTest, RawResponseCookiesInvalid) {
4767 MockNetworkServiceClient network_service_client;
4768 MockNetworkContextClient network_context_client;
4769 {
4770 TestURLLoaderClient loader_client;
4771 ResourceRequest request = CreateResourceRequest(
4772 "GET", test_server()->GetURL("/set-invalid-cookie"));
4773 // Set the devtools id to trigger the RawResponse call
4774 request.devtools_request_id = "TEST";
4775
4776 base::RunLoop delete_run_loop;
4777 mojo::PendingRemote<mojom::URLLoader> loader;
4778 mojom::URLLoaderFactoryParams params;
4779 params.process_id = kProcessId;
4780 params.is_corb_enabled = false;
4781 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4782 context(), &network_service_client, &network_context_client,
4783 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4784 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4785 request, loader_client.CreateRemote(),
4786 /*reponse_body_use_tracker=*/base::nullopt,
4787 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4788 0 /* request_id */, 0 /* keepalive_request_size */,
4789 resource_scheduler_client(), nullptr,
4790 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4791 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4792 mojo::NullRemote() /* cookie_observer */);
4793
4794 delete_run_loop.Run();
4795 loader_client.RunUntilComplete();
4796 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4797
4798 network_service_client.WaitUntilRawResponse(1u);
4799 // On these failures the cookie object is not created
4800 EXPECT_FALSE(network_service_client.raw_response_cookies()[0].cookie);
4801 EXPECT_TRUE(
4802 network_service_client.raw_response_cookies()[0]
4803 .access_result.status.HasExactlyExclusionReasonsForTesting(
4804 {net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
4805
4806 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4807 }
4808 }
4809
TEST_F(URLLoaderTest,RawResponseCookiesRedirect)4810 TEST_F(URLLoaderTest, RawResponseCookiesRedirect) {
4811 // Check a valid cookie
4812 {
4813 MockNetworkServiceClient network_service_client;
4814 MockNetworkContextClient network_context_client;
4815 GURL dest_url = test_server()->GetURL("/nocontent");
4816 GURL redirecting_url = test_server()->GetURL(
4817 "/server-redirect-with-cookie?" + dest_url.spec());
4818
4819 TestURLLoaderClient loader_client;
4820 ResourceRequest request = CreateResourceRequest("GET", redirecting_url);
4821 // Set the devtools id to trigger the RawResponse call
4822 request.devtools_request_id = "TEST";
4823
4824 base::RunLoop delete_run_loop;
4825 mojo::Remote<mojom::URLLoader> loader;
4826 mojom::URLLoaderFactoryParams params;
4827 params.process_id = kProcessId;
4828 params.is_corb_enabled = false;
4829 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4830 context(), &network_service_client, &network_context_client,
4831 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4832 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4833 loader_client.CreateRemote(),
4834 /*reponse_body_use_tracker=*/base::nullopt,
4835 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4836 /*coep_reporter=*/nullptr, 0 /* request_id */,
4837 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4838 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4839 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4840 mojo::NullRemote() /* cookie_observer */);
4841
4842 loader_client.RunUntilRedirectReceived();
4843
4844 ASSERT_TRUE(network_service_client.raw_response_headers());
4845 EXPECT_NE(network_service_client.raw_response_headers()->find(
4846 "Set-Cookie: server-redirect=true"),
4847 std::string::npos);
4848
4849 loader->FollowRedirect({}, {}, {}, base::nullopt);
4850 loader_client.RunUntilComplete();
4851 delete_run_loop.Run();
4852 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4853
4854 network_service_client.WaitUntilRawResponse(1u);
4855 EXPECT_EQ("server-redirect",
4856 network_service_client.raw_response_cookies()[0].cookie->Name());
4857 EXPECT_EQ("true",
4858 network_service_client.raw_response_cookies()[0].cookie->Value());
4859 EXPECT_TRUE(network_service_client.raw_response_cookies()[0]
4860 .access_result.status.IsInclude());
4861
4862 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4863 }
4864
4865 // Check a flagged cookie (secure cookie over an insecure connection)
4866 {
4867 MockNetworkServiceClient network_service_client;
4868 MockNetworkContextClient network_context_client;
4869 GURL dest_url = test_server()->GetURL("/nocontent");
4870 GURL redirecting_url = test_server()->GetURL(
4871 "/server-redirect-with-secure-cookie?" + dest_url.spec());
4872
4873 TestURLLoaderClient loader_client;
4874 ResourceRequest request = CreateResourceRequest("GET", redirecting_url);
4875 // Set the devtools id to trigger the RawResponse call
4876 request.devtools_request_id = "TEST";
4877
4878 base::RunLoop delete_run_loop;
4879 mojo::Remote<mojom::URLLoader> loader;
4880 mojom::URLLoaderFactoryParams params;
4881 params.process_id = kProcessId;
4882 params.is_corb_enabled = false;
4883 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4884 context(), &network_service_client, &network_context_client,
4885 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4886 loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
4887 loader_client.CreateRemote(),
4888 /*reponse_body_use_tracker=*/base::nullopt,
4889 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
4890 /*coep_reporter=*/nullptr, 0 /* request_id */,
4891 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
4892 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4893 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4894 mojo::NullRemote() /* cookie_observer */);
4895
4896 loader_client.RunUntilRedirectReceived();
4897 loader->FollowRedirect({}, {}, {}, base::nullopt);
4898 loader_client.RunUntilComplete();
4899 delete_run_loop.Run();
4900 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4901
4902 network_service_client.WaitUntilRawResponse(1u);
4903 // On these failures the cookie object is created but not included.
4904 EXPECT_TRUE(
4905 network_service_client.raw_response_cookies()[0].cookie->IsSecure());
4906 EXPECT_TRUE(network_service_client.raw_response_cookies()[0]
4907 .access_result.status.HasExactlyExclusionReasonsForTesting(
4908 {net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
4909 }
4910 }
4911
TEST_F(URLLoaderTest,RawResponseCookiesAuth)4912 TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
4913 // Check a valid cookie
4914 {
4915 MockNetworkServiceClient network_service_client;
4916 MockNetworkContextClient network_context_client;
4917 network_context_client.set_credentials_response(
4918 MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
4919
4920 GURL url = test_server()->GetURL(
4921 "/auth-basic?set-cookie-if-challenged&password=PASS");
4922 TestURLLoaderClient loader_client;
4923 ResourceRequest request = CreateResourceRequest("GET", url);
4924 // Set the devtools id to trigger the RawResponse call
4925 request.devtools_request_id = "TEST";
4926
4927 base::RunLoop delete_run_loop;
4928 mojo::PendingRemote<mojom::URLLoader> loader;
4929 mojom::URLLoaderFactoryParams params;
4930 params.process_id = kProcessId;
4931 params.is_corb_enabled = false;
4932 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4933 context(), &network_service_client, &network_context_client,
4934 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4935 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4936 request, loader_client.CreateRemote(),
4937 /*reponse_body_use_tracker=*/base::nullopt,
4938 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4939 0 /* request_id */, 0 /* keepalive_request_size */,
4940 resource_scheduler_client(), nullptr,
4941 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4942 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4943 mojo::NullRemote() /* cookie_observer */);
4944
4945 loader_client.RunUntilComplete();
4946 delete_run_loop.Run();
4947 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4948
4949 network_service_client.WaitUntilRawResponse(1u);
4950 EXPECT_EQ("got_challenged",
4951 network_service_client.raw_response_cookies()[0].cookie->Name());
4952 EXPECT_EQ("true",
4953 network_service_client.raw_response_cookies()[0].cookie->Value());
4954 EXPECT_TRUE(network_service_client.raw_response_cookies()[0]
4955 .access_result.status.IsInclude());
4956
4957 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
4958 }
4959
4960 // Check a flagged cookie (secure cookie from insecure connection)
4961 {
4962 MockNetworkServiceClient network_service_client;
4963 MockNetworkContextClient network_context_client;
4964 network_context_client.set_credentials_response(
4965 MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
4966
4967 GURL url = test_server()->GetURL(
4968 "/auth-basic?set-secure-cookie-if-challenged&password=PASS");
4969 TestURLLoaderClient loader_client;
4970 ResourceRequest request = CreateResourceRequest("GET", url);
4971 // Set the devtools id to trigger the RawResponse call
4972 request.devtools_request_id = "TEST";
4973
4974 base::RunLoop delete_run_loop;
4975 mojo::PendingRemote<mojom::URLLoader> loader;
4976 mojom::URLLoaderFactoryParams params;
4977 params.process_id = kProcessId;
4978 params.is_corb_enabled = false;
4979 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
4980 context(), &network_service_client, &network_context_client,
4981 DeleteLoaderCallback(&delete_run_loop, &url_loader),
4982 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
4983 request, loader_client.CreateRemote(),
4984 /*reponse_body_use_tracker=*/base::nullopt,
4985 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
4986 0 /* request_id */, 0 /* keepalive_request_size */,
4987 resource_scheduler_client(), nullptr,
4988 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
4989 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
4990 mojo::NullRemote() /* cookie_observer */);
4991
4992 loader_client.RunUntilComplete();
4993 delete_run_loop.Run();
4994 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
4995 network_service_client.WaitUntilRawResponse(1u);
4996 // On these failures the cookie object is created but not included.
4997 EXPECT_TRUE(
4998 network_service_client.raw_response_cookies()[0].cookie->IsSecure());
4999 EXPECT_TRUE(network_service_client.raw_response_cookies()[0]
5000 .access_result.status.HasExactlyExclusionReasonsForTesting(
5001 {net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
5002
5003 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
5004 }
5005 }
5006
TEST_F(URLLoaderTest,RawResponseQUIC)5007 TEST_F(URLLoaderTest, RawResponseQUIC) {
5008 MockNetworkServiceClient network_service_client;
5009 MockNetworkContextClient network_context_client;
5010 {
5011 TestURLLoaderClient loader_client;
5012 ResourceRequest request =
5013 CreateResourceRequest("GET", net::QuicSimpleTestServer::GetFileURL(""));
5014
5015 // Set the devtools id to trigger the RawResponse call
5016 request.devtools_request_id = "TEST";
5017
5018 base::RunLoop delete_run_loop;
5019 mojo::PendingRemote<mojom::URLLoader> loader;
5020 mojom::URLLoaderFactoryParams params;
5021 params.process_id = kProcessId;
5022 params.is_corb_enabled = false;
5023 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
5024 context(), &network_service_client, &network_context_client,
5025 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5026 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
5027 request, loader_client.CreateRemote(),
5028 /*reponse_body_use_tracker=*/base::nullopt,
5029 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
5030 0 /* request_id */, 0 /* keepalive_request_size */,
5031 resource_scheduler_client(), nullptr,
5032 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5033 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
5034 mojo::NullRemote() /* cookie_observer */);
5035
5036 delete_run_loop.Run();
5037 loader_client.RunUntilComplete();
5038 ASSERT_EQ(net::OK, loader_client.completion_status().error_code);
5039
5040 network_service_client.WaitUntilRawResponse(0u);
5041 EXPECT_EQ("TEST", network_service_client.devtools_request_id());
5042
5043 // QUIC responses don't have raw header text, so there shouldn't be any here
5044 EXPECT_FALSE(network_service_client.raw_response_headers());
5045 }
5046 }
5047
TEST_F(URLLoaderTest,CookieReportingCategories)5048 TEST_F(URLLoaderTest, CookieReportingCategories) {
5049 MockNetworkServiceClient network_service_client;
5050
5051 net::test_server::EmbeddedTestServer https_server(
5052 net::test_server::EmbeddedTestServer::TYPE_HTTPS);
5053 https_server.AddDefaultHandlers(
5054 base::FilePath(FILE_PATH_LITERAL("services/test/data")));
5055 ASSERT_TRUE(https_server.Start());
5056
5057 // Upcoming deprecation warning.
5058 {
5059 MockCookieObserver cookie_observer;
5060 MockNetworkContextClient network_context_client;
5061 TestURLLoaderClient loader_client;
5062 ResourceRequest request = CreateResourceRequest(
5063 "GET", https_server.GetURL("/set-cookie?a=b;Secure"));
5064 // Make this a third-party request.
5065 url::Origin third_party_origin =
5066 url::Origin::Create(GURL("http://www.example.com"));
5067 request.site_for_cookies =
5068 net::SiteForCookies::FromOrigin(third_party_origin);
5069 request.trusted_params->isolation_info =
5070 net::IsolationInfo::CreateForInternalRequest(third_party_origin);
5071
5072 base::RunLoop delete_run_loop;
5073 mojo::PendingRemote<mojom::URLLoader> loader;
5074 mojom::URLLoaderFactoryParams params;
5075 params.process_id = kProcessId;
5076 params.is_corb_enabled = false;
5077 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
5078 context(), &network_service_client, &network_context_client,
5079 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5080 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
5081 request, loader_client.CreateRemote(),
5082 /*reponse_body_use_tracker=*/base::nullopt,
5083 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
5084 0 /* request_id */, 0 /* keepalive_request_size */,
5085 resource_scheduler_client(), nullptr,
5086 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5087 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
5088 cookie_observer.GetRemote());
5089
5090 delete_run_loop.Run();
5091 loader_client.RunUntilComplete();
5092 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
5093
5094 cookie_observer.WaitForCookies(1u);
5095 EXPECT_THAT(cookie_observer.observed_cookies(),
5096 testing::ElementsAre(MockCookieObserver::CookieDetails{
5097 CookieAccessType::kChange, "a", "b",
5098 !net::cookie_util::IsSameSiteByDefaultCookiesEnabled()}));
5099 // This is either included or rejected as implicitly-cross-site, depending
5100 // on flags.
5101 if (net::cookie_util::IsSameSiteByDefaultCookiesEnabled()) {
5102 EXPECT_TRUE(cookie_observer.observed_cookies()[0]
5103 .status.HasExactlyExclusionReasonsForTesting(
5104 {net::CookieInclusionStatus::
5105 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
5106 }
5107 EXPECT_TRUE(cookie_observer.observed_cookies()[0].status.HasWarningReason(
5108 net::CookieInclusionStatus::WarningReason::
5109 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT));
5110 }
5111
5112 // Blocked.
5113 {
5114 MockCookieObserver cookie_observer(CookieAccessType::kChange);
5115 MockNetworkContextClient network_context_client;
5116 TestURLLoaderClient loader_client;
5117 test_network_delegate()->set_cookie_options(
5118 net::TestNetworkDelegate::NO_SET_COOKIE);
5119 ResourceRequest request = CreateResourceRequest(
5120 "GET", https_server.GetURL("/set-cookie?a=b;Secure"));
5121 // Make this a third-party request.
5122 url::Origin third_party_origin =
5123 url::Origin::Create(GURL("http://www.example.com"));
5124 request.site_for_cookies =
5125 net::SiteForCookies::FromOrigin(third_party_origin);
5126 request.trusted_params->isolation_info =
5127 net::IsolationInfo::CreateForInternalRequest(third_party_origin);
5128
5129 base::RunLoop delete_run_loop;
5130 mojo::PendingRemote<mojom::URLLoader> loader;
5131 mojom::URLLoaderFactoryParams params;
5132 params.process_id = kProcessId;
5133 params.is_corb_enabled = false;
5134 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
5135 context(), &network_service_client, &network_context_client,
5136 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5137 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
5138 request, loader_client.CreateRemote(),
5139 /*reponse_body_use_tracker=*/base::nullopt,
5140 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
5141 0 /* request_id */, 0 /* keepalive_request_size */,
5142 resource_scheduler_client(), nullptr,
5143 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5144 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
5145 cookie_observer.GetRemote());
5146
5147 delete_run_loop.Run();
5148 loader_client.RunUntilComplete();
5149 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
5150
5151 cookie_observer.WaitForCookies(1u);
5152 EXPECT_THAT(cookie_observer.observed_cookies(),
5153 testing::ElementsAre(MockCookieObserver::CookieDetails{
5154 CookieAccessType::kChange, "a", "b", false}));
5155 EXPECT_TRUE(
5156 cookie_observer.observed_cookies()[0]
5157 .status.HasExactlyExclusionReasonsForTesting(
5158 {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}));
5159
5160 test_network_delegate()->set_cookie_options(0);
5161 }
5162
5163 // Not permitted by cookie rules, but not the sort of thing that's reported
5164 // to NetworkContextClient. Note: this uses HTTP, not HTTPS, unlike others;
5165 // and is in 1st-party context.
5166 {
5167 MockCookieObserver cookie_observer;
5168 MockNetworkContextClient network_context_client;
5169 TestURLLoaderClient loader_client;
5170 ResourceRequest request = CreateResourceRequest(
5171 "GET", test_server()->GetURL("/set-cookie?a=b;Secure&d=e"));
5172
5173 base::RunLoop delete_run_loop;
5174 mojo::PendingRemote<mojom::URLLoader> loader;
5175 mojom::URLLoaderFactoryParams params;
5176 params.process_id = kProcessId;
5177 params.is_corb_enabled = false;
5178 std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
5179 context(), &network_service_client, &network_context_client,
5180 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5181 loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
5182 request, loader_client.CreateRemote(),
5183 /*reponse_body_use_tracker=*/base::nullopt,
5184 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, /*coep_reporter=*/nullptr,
5185 0 /* request_id */, 0 /* keepalive_request_size */,
5186 resource_scheduler_client(), nullptr,
5187 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5188 nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
5189 cookie_observer.GetRemote());
5190
5191 delete_run_loop.Run();
5192 loader_client.RunUntilComplete();
5193 EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
5194
5195 cookie_observer.WaitForCookies(1u);
5196 EXPECT_THAT(cookie_observer.observed_cookies(),
5197 testing::ElementsAre(MockCookieObserver::CookieDetails{
5198 CookieAccessType::kChange, "d", "e", true}));
5199 }
5200 }
5201
5202 class MockOriginPolicyManager : public mojom::OriginPolicyManager {
5203 public:
RetrieveOriginPolicy(const url::Origin & origin,const net::IsolationInfo & isolation_info,const base::Optional<std::string> & header,RetrieveOriginPolicyCallback callback)5204 void RetrieveOriginPolicy(const url::Origin& origin,
5205 const net::IsolationInfo& isolation_info,
5206 const base::Optional<std::string>& header,
5207 RetrieveOriginPolicyCallback callback) override {
5208 retrieve_origin_policy_called_ = true;
5209 isolation_info_ = isolation_info;
5210 header_ = header;
5211 OriginPolicy result;
5212 result.state = OriginPolicyState::kLoaded;
5213 result.policy_url = origin.GetURL();
5214 base::ThreadTaskRunnerHandle::Get()->PostTask(
5215 FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
5216 }
5217
AddExceptionFor(const url::Origin & origin)5218 void AddExceptionFor(const url::Origin& origin) override {}
5219
isolation_info() const5220 const net::IsolationInfo& isolation_info() const { return isolation_info_; }
header() const5221 const base::Optional<std::string>& header() const { return header_; }
retrieve_origin_policy_called() const5222 bool retrieve_origin_policy_called() const {
5223 return retrieve_origin_policy_called_;
5224 }
5225
5226 private:
5227 net::IsolationInfo isolation_info_;
5228 base::Optional<std::string> header_ = base::nullopt;
5229 bool retrieve_origin_policy_called_ = false;
5230 };
5231
TEST_F(URLLoaderTest,OriginPolicyManagerCalled)5232 TEST_F(URLLoaderTest, OriginPolicyManagerCalled) {
5233 net::EmbeddedTestServer server;
5234 server.RegisterRequestHandler(base::BindRepeating(
5235 [](const net::test_server::HttpRequest& request)
5236 -> std::unique_ptr<net::test_server::HttpResponse> {
5237 std::unique_ptr<net::test_server::BasicHttpResponse> response =
5238 std::make_unique<net::test_server::BasicHttpResponse>();
5239 if (request.relative_url == "/with_policy")
5240 response->AddCustomHeader("Origin-Policy", "allowed=(\"policy-1\")");
5241 return response;
5242 }));
5243 ASSERT_TRUE(server.Start());
5244
5245 url::Origin test_server_origin = url::Origin::Create(server.base_url());
5246
5247 // A request that has "obey_origin_policy" set will call the origin policy
5248 // manager with the correct value of the "Sec-Origin-Policy" header from the
5249 // response.
5250 {
5251 MockOriginPolicyManager mock_origin_policy_manager;
5252 ResourceRequest request =
5253 CreateResourceRequest("GET", server.GetURL("/with_policy"));
5254 // This is what the IsolationInfo for a main frame will normally look like.
5255 request.trusted_params->isolation_info = net::IsolationInfo::Create(
5256 net::IsolationInfo::RequestType::kMainFrame,
5257 test_server_origin /* top_frame_origin */,
5258 test_server_origin /* frame_origin */,
5259 net::SiteForCookies::FromOrigin(test_server_origin));
5260 request.site_for_cookies =
5261 request.trusted_params->isolation_info.site_for_cookies();
5262 request.obey_origin_policy = true;
5263
5264 base::RunLoop delete_run_loop;
5265 mojo::PendingRemote<mojom::URLLoader> loader;
5266 std::unique_ptr<URLLoader> url_loader;
5267 mojom::URLLoaderFactoryParams params;
5268 TestURLLoaderClient loader_client;
5269 params.process_id = mojom::kBrowserProcessId;
5270
5271 url_loader = std::make_unique<URLLoader>(
5272 context(), nullptr /* network_service_client */,
5273 nullptr /* network_context_client */,
5274 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5275 loader.InitWithNewPipeAndPassReceiver(), 0, request,
5276 loader_client.CreateRemote(),
5277 /*reponse_body_use_tracker=*/base::nullopt,
5278 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5279 /*coep_reporter=*/nullptr, 0 /* request_id */,
5280 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5281 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5282 &mock_origin_policy_manager, nullptr /* trust_token_helper */,
5283 mojo::NullRemote() /* cookie_observer */);
5284
5285 loader_client.RunUntilComplete();
5286 delete_run_loop.Run();
5287
5288 EXPECT_TRUE(mock_origin_policy_manager.header().has_value());
5289 EXPECT_EQ("allowed=(\"policy-1\")",
5290 mock_origin_policy_manager.header().value());
5291 EXPECT_TRUE(mock_origin_policy_manager.retrieve_origin_policy_called());
5292 EXPECT_TRUE(loader_client.response_head()->origin_policy.has_value());
5293 EXPECT_EQ(OriginPolicyState::kLoaded,
5294 loader_client.response_head()->origin_policy.value().state);
5295 EXPECT_EQ(server.base_url(),
5296 loader_client.response_head()->origin_policy.value().policy_url);
5297
5298 // Check IsolationInfo sent to the OriginPolicyManager. Both origins should
5299 // be the same as the |isolation_info| field of
5300 // ResourceRequest::trusted_params, but the RequestType should be
5301 // kOther, and the SiteForCookies should be null.
5302 EXPECT_TRUE(
5303 net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
5304 test_server_origin /* top_frame_origin */,
5305 test_server_origin /* frame_origin */,
5306 net::SiteForCookies())
5307 .IsEqualForTesting(mock_origin_policy_manager.isolation_info()));
5308 }
5309
5310 // If the "Sec-Origin-Policy" header is not present in the response, still
5311 // call the origin policy manager with an empty header value.
5312 {
5313 MockOriginPolicyManager mock_origin_policy_manager;
5314 ResourceRequest request =
5315 CreateResourceRequest("GET", server.GetURL("/without_policy"));
5316 request.obey_origin_policy = true;
5317
5318 base::RunLoop delete_run_loop;
5319 mojo::PendingRemote<mojom::URLLoader> loader;
5320 std::unique_ptr<URLLoader> url_loader;
5321 mojom::URLLoaderFactoryParams params;
5322 TestURLLoaderClient loader_client;
5323 params.process_id = mojom::kBrowserProcessId;
5324
5325 url_loader = std::make_unique<URLLoader>(
5326 context(), nullptr /* network_service_client */,
5327 nullptr /* network_context_client */,
5328 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5329 loader.InitWithNewPipeAndPassReceiver(), 0, request,
5330 loader_client.CreateRemote(),
5331 /*reponse_body_use_tracker=*/base::nullopt,
5332 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5333 /*coep_reporter=*/nullptr, 0 /* request_id */,
5334 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5335 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5336 &mock_origin_policy_manager, nullptr /* trust_token_helper */,
5337 mojo::NullRemote() /* cookie_observer */);
5338
5339 loader_client.RunUntilComplete();
5340 delete_run_loop.Run();
5341
5342 EXPECT_FALSE(mock_origin_policy_manager.header().has_value());
5343 EXPECT_TRUE(mock_origin_policy_manager.retrieve_origin_policy_called());
5344 EXPECT_TRUE(loader_client.response_head()->origin_policy.has_value());
5345 EXPECT_EQ(OriginPolicyState::kLoaded,
5346 loader_client.response_head()->origin_policy.value().state);
5347 EXPECT_EQ(server.base_url(),
5348 loader_client.response_head()->origin_policy.value().policy_url);
5349 }
5350
5351 // If "obey_origin_policy" is not set, don't call the origin policy manager
5352 // regardless of the presence of the "Sec-Origin-Policy" header.
5353 {
5354 MockOriginPolicyManager mock_origin_policy_manager;
5355 ResourceRequest request =
5356 CreateResourceRequest("GET", server.GetURL("/with_policy"));
5357 request.obey_origin_policy = false;
5358
5359 base::RunLoop delete_run_loop;
5360 mojo::PendingRemote<mojom::URLLoader> loader;
5361 std::unique_ptr<URLLoader> url_loader;
5362 mojom::URLLoaderFactoryParams params;
5363 TestURLLoaderClient loader_client;
5364 params.process_id = mojom::kBrowserProcessId;
5365
5366 url_loader = std::make_unique<URLLoader>(
5367 context(), nullptr /* network_service_client */,
5368 nullptr /* network_context_client */,
5369 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5370 loader.InitWithNewPipeAndPassReceiver(), 0, request,
5371 loader_client.CreateRemote(),
5372 /*reponse_body_use_tracker=*/base::nullopt,
5373 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5374 /*coep_reporter=*/nullptr, 0 /* request_id */,
5375 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5376 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5377 &mock_origin_policy_manager, nullptr /* trust_token_helper */,
5378 mojo::NullRemote() /* cookie_observer */);
5379
5380 loader_client.RunUntilResponseBodyArrived();
5381 delete_run_loop.Run();
5382
5383 EXPECT_FALSE(mock_origin_policy_manager.retrieve_origin_policy_called());
5384 EXPECT_FALSE(loader_client.response_head()->origin_policy.has_value());
5385 }
5386
5387 // Check the case where OriginPolicy is fetched for a cross-site subframe -
5388 // only difference is the IsolationInfo passed in has two different origins
5389 // and a null SiteForCookies..
5390 {
5391 url::Origin top_frame_origin =
5392 url::Origin::Create(GURL("http://top-frame.test/"));
5393
5394 MockOriginPolicyManager mock_origin_policy_manager;
5395 ResourceRequest request =
5396 CreateResourceRequest("GET", server.GetURL("/with_policy"));
5397 // IsolationInfo used for the ResourceRequest. This is what the
5398 // IsolationInfo for a cross-origin subframe will normally look like.
5399 request.trusted_params->isolation_info = net::IsolationInfo::Create(
5400 net::IsolationInfo::RequestType::kSubFrame, top_frame_origin,
5401 test_server_origin /* frame_origin */, net::SiteForCookies());
5402 request.site_for_cookies =
5403 request.trusted_params->isolation_info.site_for_cookies();
5404 request.obey_origin_policy = true;
5405
5406 base::RunLoop delete_run_loop;
5407 mojo::PendingRemote<mojom::URLLoader> loader;
5408 std::unique_ptr<URLLoader> url_loader;
5409 mojom::URLLoaderFactoryParams params;
5410 TestURLLoaderClient loader_client;
5411 params.process_id = mojom::kBrowserProcessId;
5412
5413 url_loader = std::make_unique<URLLoader>(
5414 context(), nullptr /* network_service_client */,
5415 nullptr /* network_context_client */,
5416 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5417 loader.InitWithNewPipeAndPassReceiver(), 0, request,
5418 loader_client.CreateRemote(),
5419 /*reponse_body_use_tracker=*/base::nullopt,
5420 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5421 /*coep_reporter=*/nullptr, 0 /* request_id */,
5422 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5423 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5424 &mock_origin_policy_manager, nullptr /* trust_token_helper */,
5425 mojo::NullRemote() /* cookie_observer */);
5426
5427 loader_client.RunUntilComplete();
5428 delete_run_loop.Run();
5429
5430 EXPECT_TRUE(mock_origin_policy_manager.retrieve_origin_policy_called());
5431
5432 // Check IsolationInfo sent to the OriginPolicyManager. Both origins should
5433 // be the same as the |isolation_info| field of
5434 // ResourceRequest::trusted_params, but the RequestType should be
5435 // kOther, and the SiteForCookies should be null.
5436 EXPECT_TRUE(
5437 net::IsolationInfo::Create(
5438 net::IsolationInfo::RequestType::kOther, top_frame_origin,
5439 test_server_origin /* frame_origin */, net::SiteForCookies())
5440 .IsEqualForTesting(mock_origin_policy_manager.isolation_info()));
5441 }
5442 }
5443
5444 namespace {
5445
5446 enum class SyncOrAsync { kSync, kAsync };
5447
5448 class MockTrustTokenRequestHelper : public TrustTokenRequestHelper {
5449 public:
5450 // |operation_synchrony| denotes whether to complete the |Begin|
5451 // and |Finalize| operations synchronously.
5452 //
5453 // |begin_done_flag|, if provided, will be set to true immediately before the
5454 // |Begin| operation returns.
MockTrustTokenRequestHelper(base::Optional<mojom::TrustTokenOperationStatus> on_begin,base::Optional<mojom::TrustTokenOperationStatus> on_finalize,SyncOrAsync operation_synchrony,bool * begin_done_flag=nullptr)5455 MockTrustTokenRequestHelper(
5456 base::Optional<mojom::TrustTokenOperationStatus> on_begin,
5457 base::Optional<mojom::TrustTokenOperationStatus> on_finalize,
5458 SyncOrAsync operation_synchrony,
5459 bool* begin_done_flag = nullptr)
5460 : on_begin_(on_begin),
5461 on_finalize_(on_finalize),
5462 operation_synchrony_(operation_synchrony),
5463 begin_done_flag_(begin_done_flag) {}
5464
~MockTrustTokenRequestHelper()5465 ~MockTrustTokenRequestHelper() override {
5466 DCHECK(!on_begin_.has_value())
5467 << "Begin operation was expected but not performed.";
5468 DCHECK(!on_finalize_.has_value())
5469 << "Finalize operation was expected but not performed.";
5470 }
5471
5472 MockTrustTokenRequestHelper(const MockTrustTokenRequestHelper&) = delete;
5473 MockTrustTokenRequestHelper& operator=(const MockTrustTokenRequestHelper&) =
5474 delete;
5475
5476 // TrustTokenRequestHelper:
Begin(net::URLRequest * request,base::OnceCallback<void (mojom::TrustTokenOperationStatus)> done)5477 void Begin(net::URLRequest* request,
5478 base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done)
5479 override {
5480 DCHECK(on_begin_.has_value());
5481
5482 // Clear storage to crash if the method gets called a second time.
5483 mojom::TrustTokenOperationStatus result = *on_begin_;
5484 on_begin_.reset();
5485
5486 switch (operation_synchrony_) {
5487 case SyncOrAsync::kSync: {
5488 OnDoneBeginning(base::BindOnce(std::move(done), result));
5489 return;
5490 }
5491 case SyncOrAsync::kAsync: {
5492 base::ThreadTaskRunnerHandle::Get()->PostTask(
5493 FROM_HERE,
5494 base::BindOnce(&MockTrustTokenRequestHelper::OnDoneBeginning,
5495 base::Unretained(this),
5496 base::BindOnce(std::move(done), result)));
5497 return;
5498 }
5499 }
5500 }
5501
Finalize(mojom::URLResponseHead * response,base::OnceCallback<void (mojom::TrustTokenOperationStatus)> done)5502 void Finalize(mojom::URLResponseHead* response,
5503 base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done)
5504 override {
5505 DCHECK(on_finalize_.has_value());
5506
5507 // Clear storage to crash if the method gets called a second time.
5508 mojom::TrustTokenOperationStatus result = *on_finalize_;
5509 on_finalize_.reset();
5510
5511 switch (operation_synchrony_) {
5512 case SyncOrAsync::kSync: {
5513 std::move(done).Run(result);
5514 return;
5515 }
5516 case SyncOrAsync::kAsync: {
5517 base::ThreadTaskRunnerHandle::Get()->PostTask(
5518 FROM_HERE, base::BindOnce(std::move(done), result));
5519 return;
5520 }
5521 }
5522 }
5523
5524 private:
OnDoneBeginning(base::OnceClosure done)5525 void OnDoneBeginning(base::OnceClosure done) {
5526 if (begin_done_flag_) {
5527 EXPECT_FALSE(*begin_done_flag_);
5528 *begin_done_flag_ = true;
5529 }
5530
5531 std::move(done).Run();
5532 }
5533
5534 // Store mocked function results in Optionals to hit a CHECK failure if a mock
5535 // method is called without having had a return value specified.
5536 base::Optional<mojom::TrustTokenOperationStatus> on_begin_;
5537 base::Optional<mojom::TrustTokenOperationStatus> on_finalize_;
5538
5539 SyncOrAsync operation_synchrony_;
5540
5541 bool* begin_done_flag_;
5542 };
5543
5544 class NoopTrustTokenKeyCommitmentGetter : public TrustTokenKeyCommitmentGetter {
5545 public:
5546 NoopTrustTokenKeyCommitmentGetter() = default;
Get(const url::Origin & origin,base::OnceCallback<void (mojom::TrustTokenKeyCommitmentResultPtr)> on_done) const5547 void Get(const url::Origin& origin,
5548 base::OnceCallback<void(mojom::TrustTokenKeyCommitmentResultPtr)>
5549 on_done) const override {}
5550 };
5551
5552 base::NoDestructor<NoopTrustTokenKeyCommitmentGetter>
5553 noop_key_commitment_getter{};
5554
ReturnNullNetworkContextClient()5555 mojom::NetworkContextClient* ReturnNullNetworkContextClient() {
5556 return nullptr;
5557 }
5558
5559 class MockTrustTokenRequestHelperFactory
5560 : public TrustTokenRequestHelperFactory {
5561 public:
MockTrustTokenRequestHelperFactory(mojom::TrustTokenOperationStatus creation_failure_error,SyncOrAsync sync_or_async)5562 MockTrustTokenRequestHelperFactory(
5563 mojom::TrustTokenOperationStatus creation_failure_error,
5564 SyncOrAsync sync_or_async)
5565 : TrustTokenRequestHelperFactory(
5566 nullptr,
5567 noop_key_commitment_getter.get(),
5568 base::BindRepeating(&ReturnNullNetworkContextClient),
5569 {}),
5570 sync_or_async_(sync_or_async),
5571 creation_failure_error_(creation_failure_error) {}
5572
MockTrustTokenRequestHelperFactory(base::Optional<mojom::TrustTokenOperationStatus> on_begin,base::Optional<mojom::TrustTokenOperationStatus> on_finalize,SyncOrAsync sync_or_async,bool * begin_done_flag)5573 MockTrustTokenRequestHelperFactory(
5574 base::Optional<mojom::TrustTokenOperationStatus> on_begin,
5575 base::Optional<mojom::TrustTokenOperationStatus> on_finalize,
5576 SyncOrAsync sync_or_async,
5577 bool* begin_done_flag)
5578 : TrustTokenRequestHelperFactory(
5579 nullptr,
5580 noop_key_commitment_getter.get(),
5581 base::BindRepeating(&ReturnNullNetworkContextClient),
5582 {}),
5583 sync_or_async_(sync_or_async),
5584 helper_(
5585 std::make_unique<MockTrustTokenRequestHelper>(on_begin,
5586 on_finalize,
5587 sync_or_async,
5588 begin_done_flag)) {}
5589
CreateTrustTokenHelperForRequest(const net::URLRequest & request,const mojom::TrustTokenParams & params,base::OnceCallback<void (TrustTokenStatusOrRequestHelper)> done)5590 void CreateTrustTokenHelperForRequest(
5591 const net::URLRequest& request,
5592 const mojom::TrustTokenParams& params,
5593 base::OnceCallback<void(TrustTokenStatusOrRequestHelper)> done) override {
5594 if (creation_failure_error_) {
5595 switch (sync_or_async_) {
5596 case SyncOrAsync::kSync: {
5597 std::move(done).Run(std::move(*creation_failure_error_));
5598 return;
5599 }
5600 case SyncOrAsync::kAsync:
5601 base::ThreadTaskRunnerHandle::Get()->PostTask(
5602 FROM_HERE, base::BindOnce(std::move(done),
5603 std::move(*creation_failure_error_)));
5604 return;
5605 }
5606 }
5607
5608 switch (sync_or_async_) {
5609 case SyncOrAsync::kSync: {
5610 std::move(done).Run(std::move(helper_));
5611 return;
5612 }
5613 case SyncOrAsync::kAsync:
5614 base::ThreadTaskRunnerHandle::Get()->PostTask(
5615 FROM_HERE, base::BindOnce(std::move(done), std::move(helper_)));
5616 return;
5617 }
5618
5619 NOTREACHED();
5620 }
5621
5622 private:
5623 SyncOrAsync sync_or_async_;
5624 base::Optional<mojom::TrustTokenOperationStatus> creation_failure_error_;
5625 std::unique_ptr<TrustTokenRequestHelper> helper_;
5626 };
5627
5628 } // namespace
5629
5630 class URLLoaderSyncOrAsyncTrustTokenOperationTest
5631 : public URLLoaderTest,
5632 public ::testing::WithParamInterface<SyncOrAsync> {
5633 public:
OnServerReceivedRequest(const net::test_server::HttpRequest &)5634 void OnServerReceivedRequest(const net::test_server::HttpRequest&) override {
5635 EXPECT_TRUE(outbound_trust_token_operation_was_successful_);
5636 }
5637
5638 protected:
5639 // Maintain a flag, set by the mock trust token request helper, denoting
5640 // whether we've successfully executed the outbound Trust Tokens operation.
5641 // This is used to make URLLoader does not send its main request before it
5642 // has completed the outbound part of its Trust Tokens operation (this
5643 // involves checking preconditions and potentially annotating the request with
5644 // Trust Tokens-related request headers).
5645 bool outbound_trust_token_operation_was_successful_ = false;
5646 };
5647
5648 INSTANTIATE_TEST_SUITE_P(WithSyncAndAsyncOperations,
5649 URLLoaderSyncOrAsyncTrustTokenOperationTest,
5650 ::testing::Values(SyncOrAsync::kSync,
5651 SyncOrAsync::kAsync));
5652
5653 // An otherwise-successful request with an associated Trust Tokens operation
5654 // whose Begin and Finalize steps are both successful should succeed overall.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,HandlesTrustTokenOperationSuccess)5655 TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
5656 HandlesTrustTokenOperationSuccess) {
5657 ResourceRequest request =
5658 CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
5659 request.trust_token_params =
5660 OptionalTrustTokenParams(mojom::TrustTokenParams::New());
5661
5662 base::RunLoop delete_run_loop;
5663 mojo::PendingRemote<mojom::URLLoader> loader_remote;
5664 std::unique_ptr<URLLoader> url_loader;
5665 mojom::URLLoaderFactoryParams params;
5666 params.process_id = mojom::kBrowserProcessId;
5667
5668 url_loader = std::make_unique<URLLoader>(
5669 context(), nullptr /* network_service_client */,
5670 nullptr /* network_context_client */,
5671 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5672 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
5673 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
5674 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5675 /*coep_reporter=*/nullptr, 0 /* request_id */,
5676 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5677 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5678 nullptr /* origin_policy_manager */,
5679 std::make_unique<MockTrustTokenRequestHelperFactory>(
5680 mojom::TrustTokenOperationStatus::kOk /* on_begin */,
5681 mojom::TrustTokenOperationStatus::kOk /* on_finalize */, GetParam(),
5682 &outbound_trust_token_operation_was_successful_),
5683 mojo::NullRemote() /* cookie_observer */);
5684
5685 client()->RunUntilComplete();
5686 delete_run_loop.Run();
5687
5688 EXPECT_EQ(client()->completion_status().error_code, net::OK);
5689 EXPECT_EQ(client()->completion_status().trust_token_operation_status,
5690 mojom::TrustTokenOperationStatus::kOk);
5691 // The page should still have loaded.
5692 base::FilePath file = GetTestFilePath("simple_page.html");
5693 std::string expected;
5694 if (!base::ReadFileToString(file, &expected)) {
5695 ADD_FAILURE() << "File not found: " << file.value();
5696 return;
5697 }
5698 EXPECT_EQ(ReadBody(), expected);
5699
5700 EXPECT_FALSE(client()->response_head()->headers->raw_headers().empty());
5701 }
5702
5703 // A request with an associated Trust Tokens operation whose Begin step returns
5704 // kAlreadyExists should return a success result immediately, without completing
5705 // the load.
5706 //
5707 // (This is the case exactly when the request is for token redemption, and the
5708 // Trust Tokens logic determines that there is already a cached redemption
5709 // record stored locally, obviating the need to execute a redemption
5710 // operation.)
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,HandlesTrustTokenRedemptionRecordCacheHit)5711 TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
5712 HandlesTrustTokenRedemptionRecordCacheHit) {
5713 ResourceRequest request =
5714 CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
5715 request.trust_token_params =
5716 OptionalTrustTokenParams(mojom::TrustTokenParams::New());
5717
5718 base::RunLoop delete_run_loop;
5719 mojo::PendingRemote<mojom::URLLoader> loader_remote;
5720 std::unique_ptr<URLLoader> url_loader;
5721 mojom::URLLoaderFactoryParams params;
5722 params.process_id = mojom::kBrowserProcessId;
5723
5724 url_loader = std::make_unique<URLLoader>(
5725 context(), nullptr /* network_service_client */,
5726 nullptr /* network_context_client */,
5727 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5728 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
5729 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
5730 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5731 /*coep_reporter=*/nullptr, 0 /* request_id */,
5732 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5733 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5734 nullptr /* origin_policy_manager */,
5735 std::make_unique<MockTrustTokenRequestHelperFactory>(
5736 mojom::TrustTokenOperationStatus::kAlreadyExists /* on_begin */,
5737 base::nullopt /* on_finalize */, GetParam(),
5738 &outbound_trust_token_operation_was_successful_),
5739 mojo::NullRemote() /* cookie_observer */
5740 );
5741
5742 client()->RunUntilComplete();
5743 delete_run_loop.Run();
5744
5745 EXPECT_EQ(client()->completion_status().error_code,
5746 net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT);
5747 EXPECT_EQ(client()->completion_status().trust_token_operation_status,
5748 mojom::TrustTokenOperationStatus::kAlreadyExists);
5749
5750 EXPECT_FALSE(client()->response_head());
5751 EXPECT_FALSE(client()->response_body().is_valid());
5752 }
5753
5754 // When a request's associated Trust Tokens operation's Begin step fails, the
5755 // request itself should fail immediately.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,HandlesTrustTokenBeginFailure)5756 TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
5757 HandlesTrustTokenBeginFailure) {
5758 ResourceRequest request =
5759 CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
5760 request.trust_token_params =
5761 OptionalTrustTokenParams(mojom::TrustTokenParams::New());
5762
5763 base::RunLoop delete_run_loop;
5764 mojo::PendingRemote<mojom::URLLoader> loader_remote;
5765 std::unique_ptr<URLLoader> url_loader;
5766 mojom::URLLoaderFactoryParams params;
5767 params.process_id = mojom::kBrowserProcessId;
5768
5769 url_loader = std::make_unique<URLLoader>(
5770 context(), nullptr /* network_service_client */,
5771 nullptr /* network_context_client */,
5772 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5773 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
5774 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
5775 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5776 /*coep_reporter=*/nullptr, 0 /* request_id */,
5777 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5778 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5779 nullptr /* origin_policy_manager */,
5780 std::make_unique<MockTrustTokenRequestHelperFactory>(
5781 mojom::TrustTokenOperationStatus::kFailedPrecondition /* on_begin */,
5782 base::nullopt /* on_finalize */, GetParam(),
5783 &outbound_trust_token_operation_was_successful_),
5784 mojo::NullRemote() /* cookie_observer */);
5785
5786 client()->RunUntilComplete();
5787 delete_run_loop.Run();
5788
5789 EXPECT_EQ(client()->completion_status().error_code,
5790 net::ERR_TRUST_TOKEN_OPERATION_FAILED);
5791 EXPECT_EQ(client()->completion_status().trust_token_operation_status,
5792 mojom::TrustTokenOperationStatus::kFailedPrecondition);
5793
5794 EXPECT_FALSE(client()->response_head());
5795 EXPECT_FALSE(client()->response_body().is_valid());
5796 }
5797
5798 // When a request's associated Trust Tokens operation's Begin step succeeds but
5799 // its Finalize step fails, the request itself should fail.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,HandlesTrustTokenFinalizeFailure)5800 TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
5801 HandlesTrustTokenFinalizeFailure) {
5802 ResourceRequest request =
5803 CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
5804 request.trust_token_params =
5805 OptionalTrustTokenParams(mojom::TrustTokenParams::New());
5806
5807 base::RunLoop delete_run_loop;
5808 mojo::PendingRemote<mojom::URLLoader> loader_remote;
5809 std::unique_ptr<URLLoader> url_loader;
5810 mojom::URLLoaderFactoryParams params;
5811 params.process_id = mojom::kBrowserProcessId;
5812
5813 url_loader = std::make_unique<URLLoader>(
5814 context(), nullptr /* network_service_client */,
5815 nullptr /* network_context_client */,
5816 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5817 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
5818 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
5819 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5820 /*coep_reporter=*/nullptr, 0 /* request_id */,
5821 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5822 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5823 nullptr /* origin_policy_manager */,
5824 std::make_unique<MockTrustTokenRequestHelperFactory>(
5825 mojom::TrustTokenOperationStatus::kOk /* on_begin */,
5826 mojom::TrustTokenOperationStatus::kBadResponse /* on_finalize */,
5827 GetParam(), &outbound_trust_token_operation_was_successful_),
5828 mojo::NullRemote() /* cookie_observer */);
5829
5830 client()->RunUntilComplete();
5831 delete_run_loop.Run();
5832
5833 EXPECT_EQ(client()->completion_status().error_code,
5834 net::ERR_TRUST_TOKEN_OPERATION_FAILED);
5835 EXPECT_EQ(client()->completion_status().trust_token_operation_status,
5836 mojom::TrustTokenOperationStatus::kBadResponse);
5837 }
5838
5839 // When URLLoader receives a request parameterized to perform a Trust Tokens
5840 // operation but fails to create a trust token request helper (because a
5841 // universal Trust Tokens precondition is violated, for instance), the request
5842 // should fail entirely.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,HandlesTrustTokenRequestHelperCreationFailure)5843 TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
5844 HandlesTrustTokenRequestHelperCreationFailure) {
5845 ResourceRequest request =
5846 CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
5847 request.trust_token_params =
5848 OptionalTrustTokenParams(mojom::TrustTokenParams::New());
5849
5850 base::RunLoop delete_run_loop;
5851 mojo::PendingRemote<mojom::URLLoader> loader_remote;
5852 std::unique_ptr<URLLoader> url_loader;
5853 mojom::URLLoaderFactoryParams params;
5854 params.process_id = mojom::kBrowserProcessId;
5855
5856 url_loader = std::make_unique<URLLoader>(
5857 context(), nullptr /* network_service_client */,
5858 nullptr /* network_context_client */,
5859 DeleteLoaderCallback(&delete_run_loop, &url_loader),
5860 loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
5861 client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
5862 TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms,
5863 /*coep_reporter=*/nullptr, 0 /* request_id */,
5864 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
5865 nullptr /* network_usage_accumulator */, nullptr /* header_client */,
5866 nullptr /* origin_policy_manager */,
5867 std::make_unique<MockTrustTokenRequestHelperFactory>(
5868 mojom::TrustTokenOperationStatus::
5869 kInternalError /* helper_creation_error */,
5870 GetParam()),
5871 mojo::NullRemote() /* cookie_observer */);
5872
5873 client()->RunUntilComplete();
5874 delete_run_loop.Run();
5875
5876 EXPECT_EQ(client()->completion_status().error_code,
5877 net::ERR_TRUST_TOKEN_OPERATION_FAILED);
5878 EXPECT_EQ(client()->completion_status().trust_token_operation_status,
5879 mojom::TrustTokenOperationStatus::kInternalError);
5880 }
5881
5882 } // namespace network
5883