diff options
author | estark <estark@chromium.org> | 2015-08-12 10:29:37 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-12 17:30:12 +0000 |
commit | a7140bc381590def065f0ecf9c4b9ba202c501a1 (patch) | |
tree | cf57a6d3f2eb56f59921c565eafd7afe325b2a95 | |
parent | 6c2056bb263ef96c935e0f8fc2d93f1ac54a20e5 (diff) | |
download | chromium_src-a7140bc381590def065f0ecf9c4b9ba202c501a1.zip chromium_src-a7140bc381590def065f0ecf9c4b9ba202c501a1.tar.gz chromium_src-a7140bc381590def065f0ecf9c4b9ba202c501a1.tar.bz2 |
Attach security info to redirect responses
The DevTools security panel should show SSL information for each
subresource on the page, including redirects. This CL attaches security
info to the ResourceResponseHead for redirect responses, so that the
security info for redirect responses can be sent to devtools when
enabled.
BUG=519120
Review URL: https://codereview.chromium.org/1275743005
Cr-Commit-Position: refs/heads/master@{#343041}
-rw-r--r-- | content/browser/loader/resource_loader.cc | 84 | ||||
-rw-r--r-- | content/browser/loader/resource_loader_unittest.cc | 98 |
2 files changed, 127 insertions, 55 deletions
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index 0339cf1..22e776c 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc @@ -47,36 +47,6 @@ namespace { // The interval for calls to ResourceLoader::ReportUploadProgress. const int kUploadProgressIntervalMsec = 100; -void PopulateResourceResponse(ResourceRequestInfoImpl* info, - net::URLRequest* request, - ResourceResponse* response) { - response->head.request_time = request->request_time(); - response->head.response_time = request->response_time(); - response->head.headers = request->response_headers(); - request->GetCharset(&response->head.charset); - response->head.content_length = request->GetExpectedContentSize(); - request->GetMimeType(&response->head.mime_type); - net::HttpResponseInfo response_info = request->response_info(); - response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy; - response->head.was_npn_negotiated = response_info.was_npn_negotiated; - response->head.npn_negotiated_protocol = - response_info.npn_negotiated_protocol; - response->head.connection_info = response_info.connection_info; - response->head.was_fetched_via_proxy = request->was_fetched_via_proxy(); - response->head.proxy_server = response_info.proxy_server; - response->head.socket_address = request->GetSocketAddress(); - if (ServiceWorkerRequestHandler* handler = - ServiceWorkerRequestHandler::GetHandler(request)) { - handler->GetExtraResponseInfo(&response->head); - } - AppCacheInterceptor::GetExtraResponseInfo( - request, - &response->head.appcache_id, - &response->head.appcache_manifest_url); - if (info->is_load_timing_enabled()) - request->GetLoadTimingInfo(&response->head.load_timing); -} - void StoreSignedCertificateTimestamps( const net::SignedCertificateTimestampAndStatusList& sct_list, int process_id, @@ -114,6 +84,47 @@ void GetSSLStatusForRequest(const GURL& url, SSLPolicy::GetSecurityStyleForResource(url, *ssl_status); } +void PopulateResourceResponse(ResourceRequestInfoImpl* info, + net::URLRequest* request, + ResourceResponse* response) { + response->head.request_time = request->request_time(); + response->head.response_time = request->response_time(); + response->head.headers = request->response_headers(); + request->GetCharset(&response->head.charset); + response->head.content_length = request->GetExpectedContentSize(); + request->GetMimeType(&response->head.mime_type); + net::HttpResponseInfo response_info = request->response_info(); + response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy; + response->head.was_npn_negotiated = response_info.was_npn_negotiated; + response->head.npn_negotiated_protocol = + response_info.npn_negotiated_protocol; + response->head.connection_info = response_info.connection_info; + response->head.was_fetched_via_proxy = request->was_fetched_via_proxy(); + response->head.proxy_server = response_info.proxy_server; + response->head.socket_address = request->GetSocketAddress(); + if (ServiceWorkerRequestHandler* handler = + ServiceWorkerRequestHandler::GetHandler(request)) { + handler->GetExtraResponseInfo(&response->head); + } + AppCacheInterceptor::GetExtraResponseInfo( + request, &response->head.appcache_id, + &response->head.appcache_manifest_url); + if (info->is_load_timing_enabled()) + request->GetLoadTimingInfo(&response->head.load_timing); + + if (request->ssl_info().cert.get()) { + SSLStatus ssl_status; + GetSSLStatusForRequest(request->url(), request->ssl_info(), + info->GetChildID(), &ssl_status); + response->head.security_info = SerializeSecurityInfo(ssl_status); + } else { + // We should not have any SSL state. + DCHECK(!request->ssl_info().cert_status && + request->ssl_info().security_bits == -1 && + !request->ssl_info().connection_status); + } +} + } // namespace ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request, @@ -587,19 +598,6 @@ void ResourceLoader::CompleteResponseStarted() { scoped_refptr<ResourceResponse> response(new ResourceResponse()); PopulateResourceResponse(info, request_.get(), response.get()); - if (request_->ssl_info().cert.get()) { - SSLStatus ssl_status; - GetSSLStatusForRequest(request_->url(), request_->ssl_info(), - info->GetChildID(), &ssl_status); - - response->head.security_info = SerializeSecurityInfo(ssl_status); - } else { - // We should not have any SSL state. - DCHECK(!request_->ssl_info().cert_status && - request_->ssl_info().security_bits == -1 && - !request_->ssl_info().connection_status); - } - delegate_->DidReceiveResponse(this); // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc index 14ee69b..0131f2f 100644 --- a/content/browser/loader/resource_loader_unittest.cc +++ b/content/browser/loader/resource_loader_unittest.cc @@ -212,19 +212,29 @@ class MockHTTPSURLRequestJob : public net::URLRequestTestJob { DISALLOW_COPY_AND_ASSIGN(MockHTTPSURLRequestJob); }; +const char kRedirectHeaders[] = + "HTTP/1.1 302 Found\0" + "Location: https://example.test\0" + "\0"; + class MockHTTPSJobURLRequestInterceptor : public net::URLRequestInterceptor { public: - MockHTTPSJobURLRequestInterceptor() {} + MockHTTPSJobURLRequestInterceptor(bool redirect) : redirect_(redirect) {} ~MockHTTPSJobURLRequestInterceptor() override {} // net::URLRequestInterceptor: net::URLRequestJob* MaybeInterceptRequest( net::URLRequest* request, net::NetworkDelegate* network_delegate) const override { - return new MockHTTPSURLRequestJob(request, network_delegate, - net::URLRequestTestJob::test_headers(), + std::string headers = + redirect_ ? std::string(kRedirectHeaders, arraysize(kRedirectHeaders)) + : net::URLRequestTestJob::test_headers(); + return new MockHTTPSURLRequestJob(request, network_delegate, headers, "dummy response", true); } + + private: + bool redirect_; }; // Arbitrary read buffer size. @@ -244,9 +254,9 @@ class ResourceHandlerStub : public ResourceHandler { received_on_will_read_(false), received_eof_(false), received_response_completed_(false), + received_request_redirected_(false), total_bytes_downloaded_(0), - upload_position_(0) { - } + upload_position_(0) {} // If true, defers the resource load in OnWillStart. void set_defer_request_on_will_start(bool defer_request_on_will_start) { @@ -267,9 +277,15 @@ class ResourceHandlerStub : public ResourceHandler { const GURL& start_url() const { return start_url_; } ResourceResponse* response() const { return response_.get(); } + ResourceResponse* redirect_response() const { + return redirect_response_.get(); + } bool received_response_completed() const { return received_response_completed_; } + bool received_request_redirected() const { + return received_request_redirected_; + } const net::URLRequestStatus& status() const { return status_; } int total_bytes_downloaded() const { return total_bytes_downloaded_; } @@ -298,7 +314,8 @@ class ResourceHandlerStub : public ResourceHandler { bool OnRequestRedirected(const net::RedirectInfo& redirect_info, ResourceResponse* response, bool* defer) override { - NOTREACHED(); + redirect_response_ = response; + received_request_redirected_ = true; return true; } @@ -378,9 +395,11 @@ class ResourceHandlerStub : public ResourceHandler { GURL start_url_; scoped_refptr<ResourceResponse> response_; + scoped_refptr<ResourceResponse> redirect_response_; bool received_on_will_read_; bool received_eof_; bool received_response_completed_; + bool received_request_redirected_; net::URLRequestStatus status_; int total_bytes_downloaded_; scoped_ptr<base::RunLoop> wait_for_progress_loop_; @@ -601,27 +620,40 @@ class ClientCertResourceLoaderTest : public ResourceLoaderTest { } }; -// A ResourceLoaderTest that intercepts https://example.test URLs and -// sets SSL info on the responses. +// A ResourceLoaderTest that intercepts https://example.test and +// https://example-redirect.test URLs and sets SSL info on the +// responses. The latter serves a Location: header in the response. class HTTPSSecurityInfoResourceLoaderTest : public ResourceLoaderTest { public: HTTPSSecurityInfoResourceLoaderTest() - : ResourceLoaderTest(), test_https_url_("https://example.test") {} + : ResourceLoaderTest(), + test_https_url_("https://example.test"), + test_https_redirect_url_("https://example-redirect.test") {} ~HTTPSSecurityInfoResourceLoaderTest() override {} - const GURL& test_https_url() { return test_https_url_; } + const GURL& test_https_url() const { return test_https_url_; } + const GURL& test_https_redirect_url() const { + return test_https_redirect_url_; + } protected: void SetUp() override { ResourceLoaderTest::SetUp(); + net::URLRequestFilter::GetInstance()->ClearHandlers(); + net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( + "https", "example.test", + scoped_ptr<net::URLRequestInterceptor>( + new MockHTTPSJobURLRequestInterceptor(false /* redirect */))); net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( - "https", "example.test", scoped_ptr<net::URLRequestInterceptor>( - new MockHTTPSJobURLRequestInterceptor)); + "https", "example-redirect.test", + scoped_ptr<net::URLRequestInterceptor>( + new MockHTTPSJobURLRequestInterceptor(true /* redirect */))); } private: const GURL test_https_url_; + const GURL test_https_redirect_url_; }; // Tests that client certificates are requested with ClientCertStore lookup. @@ -1117,4 +1149,46 @@ TEST_F(HTTPSSecurityInfoResourceLoaderTest, SecurityInfoOnHTTPSResource) { EXPECT_EQ(kTestSecurityBits, deserialized.security_bits); } +// Test that an HTTPS redirect response has the expected security info +// attached to it. +TEST_F(HTTPSSecurityInfoResourceLoaderTest, + SecurityInfoOnHTTPSRedirectResource) { + // Start the request and wait for it to finish. + scoped_ptr<net::URLRequest> request( + resource_context_.GetRequestContext()->CreateRequest( + test_https_redirect_url(), net::DEFAULT_PRIORITY, + nullptr /* delegate */)); + SetUpResourceLoader(request.Pass()); + + // Send the request and wait until it completes. + loader_->StartRequest(); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(net::URLRequestStatus::SUCCESS, + raw_ptr_to_request_->status().status()); + ASSERT_TRUE(raw_ptr_resource_handler_->received_response_completed()); + ASSERT_TRUE(raw_ptr_resource_handler_->received_request_redirected()); + + ResourceResponse* redirect_response = + raw_ptr_resource_handler_->redirect_response(); + ASSERT_TRUE(redirect_response); + + // Deserialize the security info from the redirect response and check + // that it is as expected. + SSLStatus deserialized; + ASSERT_TRUE(DeserializeSecurityInfo(redirect_response->head.security_info, + &deserialized)); + + // Expect a BROKEN security style because the cert status has errors. + EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, + deserialized.security_style); + scoped_refptr<net::X509Certificate> cert; + ASSERT_TRUE( + CertStore::GetInstance()->RetrieveCert(deserialized.cert_id, &cert)); + EXPECT_TRUE(cert->Equals(GetTestCert().get())); + + EXPECT_EQ(kTestCertError, deserialized.cert_status); + EXPECT_EQ(kTestConnectionStatus, deserialized.connection_status); + EXPECT_EQ(kTestSecurityBits, deserialized.security_bits); +} + } // namespace content |