summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorestark <estark@chromium.org>2015-08-12 10:29:37 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-12 17:30:12 +0000
commita7140bc381590def065f0ecf9c4b9ba202c501a1 (patch)
treecf57a6d3f2eb56f59921c565eafd7afe325b2a95
parent6c2056bb263ef96c935e0f8fc2d93f1ac54a20e5 (diff)
downloadchromium_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.cc84
-rw-r--r--content/browser/loader/resource_loader_unittest.cc98
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