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 "content/browser/storage_partition_impl.h"
6 
7 #include <string>
8 
9 #include "base/test/bind.h"
10 #include "build/build_config.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/client_certificate_delegate.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/content_client.h"
16 #include "content/public/test/browser_test.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/public/test/simple_url_loader_test_helper.h"
19 #include "content/public/test/url_loader_interceptor.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/shell/browser/shell_browser_context.h"
22 #include "content/test/io_thread_shared_url_loader_factory_owner.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/http/http_status_code.h"
25 #include "net/ssl/client_cert_identity.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
28 #include "services/network/public/cpp/simple_url_loader.h"
29 #include "services/network/public/mojom/network_service.mojom.h"
30 #include "services/network/public/mojom/url_loader.mojom.h"
31 #include "services/network/public/mojom/url_loader_factory.mojom.h"
32 #include "services/network/public/mojom/url_response_head.mojom.h"
33 #include "services/network/test/test_url_loader_client.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "url/gurl.h"
36 
37 namespace content {
38 
39 namespace {
40 
41 class StoragePartitionImplBrowsertest : public ContentBrowserTest {
42  public:
43   StoragePartitionImplBrowsertest() = default;
44   ~StoragePartitionImplBrowsertest() override = default;
45 
GetTestURL() const46   GURL GetTestURL() const {
47     // Use '/echoheader' instead of '/echo' to avoid a disk_cache bug.
48     // See https://crbug.com/792255.
49     return embedded_test_server()->GetURL("/echoheader");
50   }
51 
52  private:
53 };
54 
55 class ClientCertBrowserClient : public ContentBrowserClient {
56  public:
ClientCertBrowserClient(base::OnceClosure select_certificate_callback,base::OnceClosure delete_delegate_callback)57   explicit ClientCertBrowserClient(
58       base::OnceClosure select_certificate_callback,
59       base::OnceClosure delete_delegate_callback)
60       : select_certificate_callback_(std::move(select_certificate_callback)),
61         delete_delegate_callback_(std::move(delete_delegate_callback)) {}
62 
63   ~ClientCertBrowserClient() override = default;
64 
65   // Returns a cancellation callback for the imaginary client certificate
66   // dialog. The callback simulates Android's cancellation callback by deleting
67   // |delegate|.
SelectClientCertificate(WebContents * web_contents,net::SSLCertRequestInfo * cert_request_info,net::ClientCertIdentityList client_certs,std::unique_ptr<ClientCertificateDelegate> delegate)68   base::OnceClosure SelectClientCertificate(
69       WebContents* web_contents,
70       net::SSLCertRequestInfo* cert_request_info,
71       net::ClientCertIdentityList client_certs,
72       std::unique_ptr<ClientCertificateDelegate> delegate) override {
73     std::move(select_certificate_callback_).Run();  // Unblock the test.
74     return base::BindOnce(&ClientCertBrowserClient::DeleteDelegateOnCancel,
75                           base::Unretained(this), std::move(delegate));
76   }
77 
DeleteDelegateOnCancel(std::unique_ptr<ClientCertificateDelegate> delegate)78   void DeleteDelegateOnCancel(
79       std::unique_ptr<ClientCertificateDelegate> delegate) {
80     std::move(delete_delegate_callback_).Run();
81   }
82 
83  private:
84   scoped_refptr<base::SequencedTaskRunner> task_runner_;
85   base::OnceClosure select_certificate_callback_;
86   base::OnceClosure delete_delegate_callback_;
87   DISALLOW_COPY_AND_ASSIGN(ClientCertBrowserClient);
88 };
89 
90 class ClientCertBrowserTest : public ContentBrowserTest {
91  public:
ClientCertBrowserTest()92   ClientCertBrowserTest()
93       : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
94     // Configure test server to request client certificates.
95     net::SSLServerConfig ssl_server_config;
96     ssl_server_config.client_cert_type =
97         net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
98     https_test_server_.SetSSLConfig(
99         net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN, ssl_server_config);
100     https_test_server_.ServeFilesFromSourceDirectory(GetTestDataFilePath());
101   }
102 
103   ~ClientCertBrowserTest() override = default;
104 
105  protected:
SetUpOnMainThread()106   void SetUpOnMainThread() override {
107     ContentBrowserTest::SetUpOnMainThread();
108 
109     select_certificate_run_loop_ = std::make_unique<base::RunLoop>();
110     delete_delegate_run_loop_ = std::make_unique<base::RunLoop>();
111 
112     client_ = std::make_unique<ClientCertBrowserClient>(
113         select_certificate_run_loop_->QuitClosure(),
114         delete_delegate_run_loop_->QuitClosure());
115 
116     content::SetBrowserClientForTesting(client_.get());
117   }
118 
119   net::EmbeddedTestServer https_test_server_;
120   std::unique_ptr<ClientCertBrowserClient> client_;
121   std::unique_ptr<base::RunLoop> select_certificate_run_loop_;
122   std::unique_ptr<base::RunLoop> delete_delegate_run_loop_;
123 };
124 
125 // Creates a SimpleURLLoader and starts it to download |url|. Blocks until the
126 // load is complete.
DownloadUrl(const GURL & url,StoragePartition * partition)127 std::unique_ptr<network::SimpleURLLoader> DownloadUrl(
128     const GURL& url,
129     StoragePartition* partition) {
130   auto request = std::make_unique<network::ResourceRequest>();
131   request->url = url;
132   std::unique_ptr<network::SimpleURLLoader> url_loader =
133       network::SimpleURLLoader::Create(std::move(request),
134                                        TRAFFIC_ANNOTATION_FOR_TESTS);
135   SimpleURLLoaderTestHelper url_loader_helper;
136   url_loader->DownloadToString(
137       partition->GetURLLoaderFactoryForBrowserProcess().get(),
138       url_loader_helper.GetCallback(),
139       /*max_body_size=*/1024 * 1024);
140   url_loader_helper.WaitForCallback();
141   return url_loader;
142 }
143 
CheckSimpleURLLoaderState(network::SimpleURLLoader * url_loader,int net_error,net::HttpStatusCode http_status_code)144 void CheckSimpleURLLoaderState(network::SimpleURLLoader* url_loader,
145                                int net_error,
146                                net::HttpStatusCode http_status_code) {
147   EXPECT_EQ(net_error, url_loader->NetError());
148   if (net_error != net::OK)
149     return;
150   ASSERT_TRUE(url_loader->ResponseInfo());
151   ASSERT_TRUE(url_loader->ResponseInfo()->headers);
152   EXPECT_EQ(http_status_code,
153             url_loader->ResponseInfo()->headers->response_code());
154 }
155 
156 }  // namespace
157 
158 // Make sure that the NetworkContext returned by a StoragePartition works, both
159 // with the network service enabled and with it disabled, when one is created
160 // that wraps the URLRequestContext created by the BrowserContext.
IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,NetworkContext)161 IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest, NetworkContext) {
162   ASSERT_TRUE(embedded_test_server()->Start());
163 
164   network::mojom::URLLoaderFactoryParamsPtr params =
165       network::mojom::URLLoaderFactoryParams::New();
166   params->process_id = network::mojom::kBrowserProcessId;
167   params->automatically_assign_isolation_info = true;
168   params->is_corb_enabled = false;
169   mojo::Remote<network::mojom::URLLoaderFactory> loader_factory;
170   BrowserContext::GetDefaultStoragePartition(
171       shell()->web_contents()->GetBrowserContext())
172       ->GetNetworkContext()
173       ->CreateURLLoaderFactory(loader_factory.BindNewPipeAndPassReceiver(),
174                                std::move(params));
175 
176   network::ResourceRequest request;
177   network::TestURLLoaderClient client;
178   request.url = embedded_test_server()->GetURL("/set-header?foo: bar");
179   request.method = "GET";
180   mojo::PendingRemote<network::mojom::URLLoader> loader;
181   loader_factory->CreateLoaderAndStart(
182       loader.InitWithNewPipeAndPassReceiver(), 2, 1,
183       network::mojom::kURLLoadOptionNone, request, client.CreateRemote(),
184       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
185 
186   // Just wait until headers are received - if the right headers are received,
187   // no need to read the body.
188   client.RunUntilResponseBodyArrived();
189   ASSERT_TRUE(client.response_head()->headers);
190   EXPECT_EQ(200, client.response_head()->headers->response_code());
191 
192   std::string foo_header_value;
193   ASSERT_TRUE(client.response_head()->headers->GetNormalizedHeader(
194       "foo", &foo_header_value));
195   EXPECT_EQ("bar", foo_header_value);
196 }
197 
198 // Make sure the factory info returned from
199 // |StoragePartition::GetURLLoaderFactoryForBrowserProcessIOThread()| works.
IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,GetURLLoaderFactoryForBrowserProcessIOThread)200 IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,
201                        GetURLLoaderFactoryForBrowserProcessIOThread) {
202   ASSERT_TRUE(embedded_test_server()->Start());
203 
204   base::ScopedAllowBlockingForTesting allow_blocking;
205   auto pending_shared_url_loader_factory =
206       BrowserContext::GetDefaultStoragePartition(
207           shell()->web_contents()->GetBrowserContext())
208           ->GetURLLoaderFactoryForBrowserProcessIOThread();
209 
210   auto factory_owner = IOThreadSharedURLLoaderFactoryOwner::Create(
211       std::move(pending_shared_url_loader_factory));
212 
213   EXPECT_EQ(net::OK, factory_owner->LoadBasicRequestOnIOThread(GetTestURL()));
214 }
215 
216 // Make sure the factory info returned from
217 // |StoragePartition::GetURLLoaderFactoryForBrowserProcessIOThread()| doesn't
218 // crash if it's called after the StoragePartition is deleted.
IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,BrowserIOPendingFactoryAfterStoragePartitionGone)219 IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,
220                        BrowserIOPendingFactoryAfterStoragePartitionGone) {
221   ASSERT_TRUE(embedded_test_server()->Start());
222 
223   base::ScopedAllowBlockingForTesting allow_blocking;
224   std::unique_ptr<ShellBrowserContext> browser_context =
225       std::make_unique<ShellBrowserContext>(true);
226   auto* partition =
227       BrowserContext::GetDefaultStoragePartition(browser_context.get());
228   auto pending_shared_url_loader_factory =
229       partition->GetURLLoaderFactoryForBrowserProcessIOThread();
230 
231   browser_context.reset();
232 
233   auto factory_owner = IOThreadSharedURLLoaderFactoryOwner::Create(
234       std::move(pending_shared_url_loader_factory));
235 
236   EXPECT_EQ(net::ERR_FAILED,
237             factory_owner->LoadBasicRequestOnIOThread(GetTestURL()));
238 }
239 
240 // Make sure the factory constructed from
241 // |StoragePartition::GetURLLoaderFactoryForBrowserProcessIOThread()| doesn't
242 // crash if it's called after the StoragePartition is deleted.
IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,BrowserIOFactoryAfterStoragePartitionGone)243 IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,
244                        BrowserIOFactoryAfterStoragePartitionGone) {
245   ASSERT_TRUE(embedded_test_server()->Start());
246 
247   base::ScopedAllowBlockingForTesting allow_blocking;
248   std::unique_ptr<ShellBrowserContext> browser_context =
249       std::make_unique<ShellBrowserContext>(true);
250   auto* partition =
251       BrowserContext::GetDefaultStoragePartition(browser_context.get());
252   auto factory_owner = IOThreadSharedURLLoaderFactoryOwner::Create(
253       partition->GetURLLoaderFactoryForBrowserProcessIOThread());
254 
255   EXPECT_EQ(net::OK, factory_owner->LoadBasicRequestOnIOThread(GetTestURL()));
256 
257   browser_context.reset();
258 
259   EXPECT_EQ(net::ERR_FAILED,
260             factory_owner->LoadBasicRequestOnIOThread(GetTestURL()));
261 }
262 
263 // Checks that the network::URLLoaderIntercpetor works as expected with the
264 // SharedURLLoaderFactory returned by StoragePartitionImpl.
IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest,URLLoaderInterceptor)265 IN_PROC_BROWSER_TEST_F(StoragePartitionImplBrowsertest, URLLoaderInterceptor) {
266   ASSERT_TRUE(embedded_test_server()->Start());
267   const GURL kEchoUrl(embedded_test_server()->GetURL("/echo"));
268 
269   base::ScopedAllowBlockingForTesting allow_blocking;
270   std::unique_ptr<ShellBrowserContext> browser_context =
271       std::make_unique<ShellBrowserContext>(true);
272   auto* partition =
273       BrowserContext::GetDefaultStoragePartition(browser_context.get());
274 
275   // Run a request the first time without the interceptor set, as the
276   // StoragePartitionImpl lazily creates the factory and we want to make sure
277   // it will create a new one once the interceptor is set (and not simply reuse
278   // the cached one).
279   {
280     std::unique_ptr<network::SimpleURLLoader> url_loader =
281         DownloadUrl(kEchoUrl, partition);
282     CheckSimpleURLLoaderState(url_loader.get(), net::OK, net::HTTP_OK);
283   }
284 
285   // Use a URLLoaderInterceptor to simulate an error.
286   {
287     URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
288         [&](URLLoaderInterceptor::RequestParams* params) -> bool {
289           if (params->url_request.url != kEchoUrl)
290             return false;
291           params->client->OnComplete(
292               network::URLLoaderCompletionStatus(net::ERR_NOT_IMPLEMENTED));
293           return true;
294         }));
295     std::unique_ptr<network::SimpleURLLoader> url_loader =
296         DownloadUrl(kEchoUrl, partition);
297     CheckSimpleURLLoaderState(url_loader.get(), net::ERR_NOT_IMPLEMENTED,
298                               net::HTTP_OK);
299   }
300 
301   // Run one more time without the interceptor, we should be back to the
302   // original behavior.
303   {
304     std::unique_ptr<network::SimpleURLLoader> url_loader =
305         DownloadUrl(kEchoUrl, partition);
306     CheckSimpleURLLoaderState(url_loader.get(), net::OK, net::HTTP_OK);
307   }
308 }
309 
IN_PROC_BROWSER_TEST_F(ClientCertBrowserTest,InvokeClientCertCancellationCallback)310 IN_PROC_BROWSER_TEST_F(ClientCertBrowserTest,
311                        InvokeClientCertCancellationCallback) {
312   ASSERT_TRUE(https_test_server_.Start());
313 
314   // Navigate to "/echo". We expect this to get blocked on the client cert.
315   shell()->LoadURL(https_test_server_.GetURL("/echo"));
316 
317   // Wait for SelectClientCertificate() to be invoked.
318   select_certificate_run_loop_->Run();
319 
320   // Navigate away to cancel the original request, triggering the cancellation
321   // callback that was returned by SelectClientCertificate.
322   shell()->LoadURL(GURL("about:blank"));
323 
324   // Wait for DeleteDelegateOnCancel() to be invoked.
325   delete_delegate_run_loop_->Run();
326 }
327 
328 }  // namespace content
329