Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(876)

Unified Diff: content/browser/loader/resource_loader_unittest.cc

Issue 859213006: Cancel client auth requests when not promptable. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@client-auth-cancel-1
Patch Set: worker_common.js was missing a license header (also a rebase) Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/loader/resource_loader.cc ('k') | content/browser/shared_worker/worker_browsertest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/loader/resource_loader_unittest.cc
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 92241b68d0beab40f4d03c6512289017c9578e5b..89f82360d5be36547be4f8fc1927fd1b09b6b08d 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -6,24 +6,31 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
#include "content/browser/loader/resource_loader_delegate.h"
+#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/resource_response.h"
#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
#include "content/test/test_content_browser_client.h"
+#include "content/test/test_web_contents.h"
#include "ipc/ipc_message.h"
#include "net/base/io_buffer.h"
#include "net/base/mock_file_stream.h"
+#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_store.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job_factory.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
@@ -53,7 +60,6 @@ class ClientCertStoreStub : public net::ClientCertStore {
int* request_count,
std::vector<std::string>* requested_authorities)
: response_(response),
- async_(false),
requested_authorities_(requested_authorities),
request_count_(request_count) {
requested_authorities_->clear();
@@ -62,9 +68,6 @@ class ClientCertStoreStub : public net::ClientCertStore {
~ClientCertStoreStub() override {}
- // Configures whether the certificates are returned asynchronously or not.
- void set_async(bool async) { async_ = async; }
-
// net::ClientCertStore:
void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
net::CertificateList* selected_certs,
@@ -73,20 +76,88 @@ class ClientCertStoreStub : public net::ClientCertStore {
++(*request_count_);
*selected_certs = response_;
- if (async_) {
- base::MessageLoop::current()->PostTask(FROM_HERE, callback);
- } else {
- callback.Run();
- }
+ callback.Run();
}
private:
const net::CertificateList response_;
- bool async_;
std::vector<std::string>* requested_authorities_;
int* request_count_;
};
+// Client certificate store which destroys its resource loader before the
+// asynchronous GetClientCerts callback is called.
+class LoaderDestroyingCertStore : public net::ClientCertStore {
+ public:
+ // Creates a client certificate store which, when looked up, posts a task to
+ // reset |loader| and then call the callback. The caller is responsible for
+ // ensuring the pointers remain valid until the process is complete.
+ explicit LoaderDestroyingCertStore(scoped_ptr<ResourceLoader>* loader)
+ : loader_(loader) {}
+
+ // net::ClientCertStore:
+ void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+ net::CertificateList* selected_certs,
+ const base::Closure& callback) override {
+ // Don't destroy |loader_| while it's on the stack.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&LoaderDestroyingCertStore::DoCallback,
+ base::Unretained(loader_), callback));
+ }
+
+ private:
+ static void DoCallback(scoped_ptr<ResourceLoader>* loader,
+ const base::Closure& callback) {
+ loader->reset();
+ callback.Run();
+ }
+
+ scoped_ptr<ResourceLoader>* loader_;
+};
+
+// A mock URLRequestJob which simulates an SSL client auth request.
+class MockClientCertURLRequestJob : public net::URLRequestTestJob {
+ public:
+ MockClientCertURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate)
+ : net::URLRequestTestJob(request, network_delegate) {}
+
+ static std::vector<std::string> test_authorities() {
+ return std::vector<std::string>(1, "dummy");
+ }
+
+ // net::URLRequestTestJob:
+ void Start() override {
+ scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
+ new net::SSLCertRequestInfo);
+ cert_request_info->cert_authorities = test_authorities();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
+ this, cert_request_info));
+ }
+
+ void ContinueWithCertificate(net::X509Certificate* cert) override {
+ net::URLRequestTestJob::Start();
+ }
+
+ private:
+ ~MockClientCertURLRequestJob() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob);
+};
+
+class MockClientCertJobProtocolHandler
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ // URLRequestJobFactory::ProtocolHandler implementation:
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return new MockClientCertURLRequestJob(request, network_delegate);
+ }
+};
+
// Arbitrary read buffer size.
const int kReadBufSize = 1024;
@@ -239,25 +310,28 @@ class SelectCertificateBrowserClient : public TestContentBrowserClient {
SelectCertificateBrowserClient() : call_count_(0) {}
void SelectClientCertificate(
- int render_process_id,
- int render_view_id,
+ WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- const base::Callback<void(net::X509Certificate*)>& callback) override {
+ scoped_ptr<ClientCertificateDelegate> delegate) override {
++call_count_;
passed_certs_ = cert_request_info->client_certs;
+ delegate_ = delegate.Pass();
}
- int call_count() {
- return call_count_;
- }
+ int call_count() { return call_count_; }
+ net::CertificateList passed_certs() { return passed_certs_; }
- net::CertificateList passed_certs() {
- return passed_certs_;
+ void ContinueWithCertificate(net::X509Certificate* cert) {
+ delegate_->ContinueWithCertificate(cert);
+ delegate_.reset();
}
+ void CancelCertificateSelection() { delegate_.reset(); }
+
private:
net::CertificateList passed_certs_;
int call_count_;
+ scoped_ptr<ClientCertificateDelegate> delegate_;
};
class ResourceContextStub : public MockResourceContext {
@@ -297,19 +371,19 @@ class ResourceLoaderTest : public testing::Test,
resource_context_(&test_url_request_context_),
raw_ptr_resource_handler_(NULL),
raw_ptr_to_request_(NULL) {
- job_factory_.SetProtocolHandler(
- "test", net::URLRequestTestJob::CreateProtocolHandler());
test_url_request_context_.set_job_factory(&job_factory_);
}
- GURL test_url() const {
- return net::URLRequestTestJob::test_url_1();
- }
+ GURL test_url() const { return net::URLRequestTestJob::test_url_1(); }
std::string test_data() const {
return net::URLRequestTestJob::test_data_1();
}
+ virtual net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() {
+ return net::URLRequestTestJob::CreateProtocolHandler();
+ }
+
virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
scoped_ptr<ResourceHandlerStub> leaf_handler,
net::URLRequest* request) {
@@ -317,8 +391,14 @@ class ResourceLoaderTest : public testing::Test,
}
void SetUp() override {
- const int kRenderProcessId = 1;
- const int kRenderViewId = 2;
+ job_factory_.SetProtocolHandler("test", CreateProtocolHandler());
+
+ browser_context_.reset(new TestBrowserContext());
+ scoped_refptr<SiteInstance> site_instance =
+ SiteInstance::Create(browser_context_.get());
+ web_contents_.reset(
+ TestWebContents::Create(browser_context_.get(), site_instance.get()));
+ RenderFrameHost* rfh = web_contents_->GetMainFrame();
scoped_ptr<net::URLRequest> request(
resource_context_.GetRequestContext()->CreateRequest(
@@ -327,16 +407,12 @@ class ResourceLoaderTest : public testing::Test,
NULL /* delegate */,
NULL /* cookie_store */));
raw_ptr_to_request_ = request.get();
- ResourceRequestInfo::AllocateForTesting(request.get(),
- RESOURCE_TYPE_MAIN_FRAME,
- &resource_context_,
- kRenderProcessId,
- kRenderViewId,
- MSG_ROUTING_NONE,
- true, // is_main_frame
- false, // parent_is_main_frame
- true, // allow_download
- false); // is_async
+ ResourceRequestInfo::AllocateForTesting(
+ request.get(), RESOURCE_TYPE_MAIN_FRAME, &resource_context_,
+ rfh->GetProcess()->GetID(), rfh->GetRenderViewHost()->GetRoutingID(),
+ rfh->GetRoutingID(), true /* is_main_frame */,
+ false /* parent_is_main_frame */, true /* allow_download */,
+ false /* is_async */);
scoped_ptr<ResourceHandlerStub> resource_handler(
new ResourceHandlerStub(request.get()));
raw_ptr_resource_handler_ = resource_handler.get();
@@ -346,6 +422,14 @@ class ResourceLoaderTest : public testing::Test,
this));
}
+ void TearDown() override {
+ // Destroy the WebContents and pump the event loop before destroying
+ // |rvh_test_enabler_| and |thread_bundle_|. This lets asynchronous cleanup
+ // tasks complete.
+ web_contents_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
// ResourceLoaderDelegate:
ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
ResourceLoader* loader,
@@ -362,11 +446,14 @@ class ResourceLoaderTest : public testing::Test,
void DidReceiveResponse(ResourceLoader* loader) override {}
void DidFinishLoading(ResourceLoader* loader) override {}
- content::TestBrowserThreadBundle thread_bundle_;
+ TestBrowserThreadBundle thread_bundle_;
+ RenderViewHostTestEnabler rvh_test_enabler_;
net::URLRequestJobFactoryImpl job_factory_;
net::TestURLRequestContext test_url_request_context_;
ResourceContextStub resource_context_;
+ scoped_ptr<TestBrowserContext> browser_context_;
+ scoped_ptr<TestWebContents> web_contents_;
// The ResourceLoader owns the URLRequest and the ResourceHandler.
ResourceHandlerStub* raw_ptr_resource_handler_;
@@ -374,11 +461,15 @@ class ResourceLoaderTest : public testing::Test,
scoped_ptr<ResourceLoader> loader_;
};
-// Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested()
-// causes client cert store to be queried for certificates and if the returned
-// certificates are correctly passed to the content browser client for
-// selection.
-TEST_F(ResourceLoaderTest, ClientCertStoreLookup) {
+class ClientCertResourceLoaderTest : public ResourceLoaderTest {
+ protected:
+ net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() override {
+ return new MockClientCertJobProtocolHandler;
+ }
+};
+
+// Tests that client certificates are requested with ClientCertStore lookup.
+TEST_F(ClientCertResourceLoaderTest, WithStoreLookup) {
// Set up the test client cert store.
int store_request_count;
std::vector<std::string> store_requested_authorities;
@@ -388,91 +479,125 @@ TEST_F(ResourceLoaderTest, ClientCertStoreLookup) {
dummy_certs, &store_request_count, &store_requested_authorities));
resource_context_.SetClientCertStore(test_store.Pass());
- // Prepare a dummy certificate request.
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
- new net::SSLCertRequestInfo());
- std::vector<std::string> dummy_authority(1, "dummy");
- cert_request_info->cert_authorities = dummy_authority;
-
// Plug in test content browser client.
SelectCertificateBrowserClient test_client;
ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
- // Everything is set up. Trigger the resource loader certificate request event
- // and run the message loop.
- loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get());
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
base::RunLoop().RunUntilIdle();
- // Restore the original content browser client.
- SetBrowserClientForTesting(old_client);
+ EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed());
// Check if the test store was queried against correct |cert_authorities|.
EXPECT_EQ(1, store_request_count);
- EXPECT_EQ(dummy_authority, store_requested_authorities);
+ EXPECT_EQ(MockClientCertURLRequestJob::test_authorities(),
+ store_requested_authorities);
// Check if the retrieved certificates were passed to the content browser
// client.
EXPECT_EQ(1, test_client.call_count());
EXPECT_EQ(dummy_certs, test_client.passed_certs());
-}
-// Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested()
-// on a platform with a NULL client cert store still calls the content browser
-// client for selection.
-TEST_F(ResourceLoaderTest, ClientCertStoreNull) {
- // Prepare a dummy certificate request.
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
- new net::SSLCertRequestInfo());
- std::vector<std::string> dummy_authority(1, "dummy");
- cert_request_info->cert_authorities = dummy_authority;
+ // Continue the request.
+ test_client.ContinueWithCertificate(dummy_certs[0].get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::OK, raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
+}
+// Tests that client certificates are requested on a platform with NULL
+// ClientCertStore.
+TEST_F(ClientCertResourceLoaderTest, WithNullStore) {
// Plug in test content browser client.
SelectCertificateBrowserClient test_client;
ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
- // Everything is set up. Trigger the resource loader certificate request event
- // and run the message loop.
- loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get());
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
base::RunLoop().RunUntilIdle();
+ // Check if the SelectClientCertificate was called on the content browser
+ // client.
+ EXPECT_EQ(1, test_client.call_count());
+ EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
+
+ // Continue the request.
+ scoped_refptr<net::X509Certificate> cert(
+ new net::X509Certificate("test", "test", base::Time(), base::Time()));
+ test_client.ContinueWithCertificate(cert.get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::OK, raw_ptr_resource_handler_->status().error());
+
// Restore the original content browser client.
SetBrowserClientForTesting(old_client);
+}
+
+// Tests that the ContentBrowserClient may cancel a certificate request.
+TEST_F(ClientCertResourceLoaderTest, CancelSelection) {
+ // Plug in test content browser client.
+ SelectCertificateBrowserClient test_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
+
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
// Check if the SelectClientCertificate was called on the content browser
// client.
EXPECT_EQ(1, test_client.call_count());
EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
+
+ // Cancel the request.
+ test_client.CancelCertificateSelection();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+ raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
}
-TEST_F(ResourceLoaderTest, ClientCertStoreAsyncCancel) {
- // Set up the test client cert store.
- int store_request_count;
- std::vector<std::string> store_requested_authorities;
- scoped_ptr<ClientCertStoreStub> test_store(
- new ClientCertStoreStub(net::CertificateList(), &store_request_count,
- &store_requested_authorities));
- test_store->set_async(true);
- EXPECT_EQ(0, store_request_count);
- resource_context_.SetClientCertStore(test_store.Pass());
+// Verifies that requests without WebContents attached abort.
+TEST_F(ClientCertResourceLoaderTest, NoWebContents) {
+ // Destroy the WebContents before starting the request.
+ web_contents_.reset();
- // Prepare a dummy certificate request.
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
- new net::SSLCertRequestInfo());
- std::vector<std::string> dummy_authority(1, "dummy");
- cert_request_info->cert_authorities = dummy_authority;
+ // Plug in test content browser client.
+ SelectCertificateBrowserClient test_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
- // Everything is set up. Trigger the resource loader certificate request
- // event.
- loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get());
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
- // Check if the test store was queried against correct |cert_authorities|.
- EXPECT_EQ(1, store_request_count);
- EXPECT_EQ(dummy_authority, store_requested_authorities);
+ // Check that SelectClientCertificate wasn't called and the request aborted.
+ EXPECT_EQ(0, test_client.call_count());
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+ raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
+}
+
+// Verifies that ClientCertStore's callback doesn't crash if called after the
+// loader is destroyed.
+TEST_F(ClientCertResourceLoaderTest, StoreAsyncCancel) {
+ scoped_ptr<LoaderDestroyingCertStore> test_store(
+ new LoaderDestroyingCertStore(&loader_));
+ resource_context_.SetClientCertStore(test_store.Pass());
- // Cancel the request before the store calls the callback.
- loader_.reset();
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(loader_);
- // Pump the event loop. There shouldn't be a crash when the callback is run.
+ // Pump the event loop to ensure nothing asynchronous crashes either.
base::RunLoop().RunUntilIdle();
}
« no previous file with comments | « content/browser/loader/resource_loader.cc ('k') | content/browser/shared_worker/worker_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698