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, &params,
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, &params,
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, &params,
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       &params, /*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       &params, /*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       &params, /*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       &params, /*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       &params, /*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       &params, /*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       &params, /*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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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       &params,
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       &params,
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, &params,
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, &params,
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       &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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       &params,
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, &params,
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       &params, /*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       &params, /*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, &params,
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, &params,
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, &params,
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, &params,
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       &params, /*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, &params,
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       &params,
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, &params,
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, &params,
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, &params,
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, &params, /*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, &params, /*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, &params,
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, &params, /*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, &params, /*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, &params, /*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, &params, /*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, &params, /*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, &params,
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, &params,
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, &params, /*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, &params, /*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, &params, /*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, &params, /*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, &params, /*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, &params, /*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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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, &params,
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