diff options
author | japhet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-04 18:30:09 +0000 |
---|---|---|
committer | japhet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-04 18:30:09 +0000 |
commit | 85cc78c5489a2925214a02aef4baf716d74bb1cc (patch) | |
tree | a9945e2369606d83d2977e94636fa35a8f45a765 /webkit/glue/site_isolation_metrics.cc | |
parent | ae90f252d04c941f8ff9e7a7cfdd20b64c98cd83 (diff) | |
download | chromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.zip chromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.tar.gz chromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.tar.bz2 |
Site isolation metrics: Sniff the actual type of cross origin text/html
responses, and take access control headers into account.
Also, moved the actual logic of site isolation metrics into a separate file.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/1699028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46370 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/site_isolation_metrics.cc')
-rw-r--r-- | webkit/glue/site_isolation_metrics.cc | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/webkit/glue/site_isolation_metrics.cc b/webkit/glue/site_isolation_metrics.cc new file mode 100644 index 0000000..a97bb96 --- /dev/null +++ b/webkit/glue/site_isolation_metrics.cc @@ -0,0 +1,176 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/glue/site_isolation_metrics.h" + +#include <set> + +#include "base/hash_tables.h" +#include "base/histogram.h" +#include "net/base/mime_sniffer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" + +using WebKit::WebFrame; +using WebKit::WebSecurityOrigin; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; + +namespace webkit_glue { + +typedef base::hash_map<unsigned, WebURLRequest::TargetType> TargetTypeMap; +typedef base::hash_map<std::string, int> MimeTypeMap; +typedef std::set<std::string> CrossOriginTextHtmlResponseSet; + +static TargetTypeMap* GetTargetTypeMap() { + static TargetTypeMap target_type_map_; + return &target_type_map_; +} + +// Copied from net/base/mime_util.cc, supported_non_image_types[] +static const char* const kCrossOriginMimeTypesToLog[] = { + "text/cache-manifest", + "text/html", + "text/xml", + "text/xsl", + "text/plain", + "text/vnd.chromium.ftp-dir", + "text/", + "text/css", + "image/svg+xml", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml", + "application/json", + "application/x-x509-user-cert", + "multipart/x-mixed-replace" +}; + +static MimeTypeMap* GetMimeTypeMap() { + static MimeTypeMap mime_type_map_; + if (!mime_type_map_.size()) { + for (size_t i = 0; i < arraysize(kCrossOriginMimeTypesToLog); ++i) + mime_type_map_[kCrossOriginMimeTypesToLog[i]] = i; + } + return &mime_type_map_; +} + +// This is set is used to keep track of the response urls that we want to +// sniff, since we will have to wait for the payload to arrive. +static CrossOriginTextHtmlResponseSet* GetCrossOriginTextHtmlResponseSet() { + static CrossOriginTextHtmlResponseSet cross_origin_text_html_response_set_; + return &cross_origin_text_html_response_set_; +} + +static void LogVerifiedTextHtmlResponse() { + UMA_HISTOGRAM_COUNTS( + "SiteIsolation.CrossSiteNonFrameResponse_verified_texthtml", 1); +} + +static void LogMislabeledTextHtmlResponse() { + UMA_HISTOGRAM_COUNTS( + "SiteIsolation.CrossSiteNonFrameResponse_mislabeled_texthtml", 1); +} + +void SiteIsolationMetrics::AddRequest(unsigned identifier, + WebURLRequest::TargetType target_type) { + TargetTypeMap& target_type_map = *GetTargetTypeMap(); + target_type_map[identifier] = target_type; +} + +void SiteIsolationMetrics::LogMimeTypeForCrossOriginRequest( + WebFrame* frame, unsigned identifier, const WebURLResponse& response) { + TargetTypeMap& target_type_map = *GetTargetTypeMap(); + TargetTypeMap::iterator iter = target_type_map.find(identifier); + if (iter != target_type_map.end()) { + WebURLRequest::TargetType target_type = iter->second; + target_type_map.erase(iter); + // We want to log any cross-site request that we don't think a renderer + // should be allowed to make. We can safely ignore frame requests (since + // we'd like those to be in a separate renderer) and plugin requests, even + // if they are cross-origin. + if (target_type != WebURLRequest::TargetIsMainFrame && + target_type != WebURLRequest::TargetIsSubFrame && + target_type != WebURLRequest::TargetIsObject && + !frame->securityOrigin().canAccess( + WebSecurityOrigin::create(response.url()))) { + std::string mime_type = response.mimeType().utf8(); + MimeTypeMap mime_type_map = *GetMimeTypeMap(); + MimeTypeMap::iterator mime_type_iter = mime_type_map.find(mime_type); + if (mime_type_iter != mime_type_map.end()) { + UMA_HISTOGRAM_ENUMERATION( + "SiteIsolation.CrossSiteNonFrameResponse_MIME_Type", + mime_type_iter->second, + arraysize(kCrossOriginMimeTypesToLog)); + + // We also should check access control headers, in case this + // cross-origin request has been explicitly permitted. + // This is basically a copy of the logic of passesAccessControlCheck() + // in WebCore/loader/CrossOriginAccessControl.cpp. + WebString access_control_origin = response.httpHeaderField( + WebString::fromUTF8("Access-Control-Allow-Origin")); + if (access_control_origin != WebString::fromUTF8("*") + && !frame->securityOrigin().canAccess( + WebSecurityOrigin::createFromString(access_control_origin))) { + UMA_HISTOGRAM_ENUMERATION( + "SiteIsolation.CrossSiteNonFrameResponse_With_CORS_MIME_Type", + mime_type_iter->second, + arraysize(kCrossOriginMimeTypesToLog)); + } + + // Sometimes resources are mislabeled as text/html. Once we have some + // of the payload, we want to determine if this was actually text/html. + if (mime_type == "text/html") + GetCrossOriginTextHtmlResponseSet()->insert(response.url().spec()); + } + } + } +} + +void SiteIsolationMetrics::SniffCrossOriginHTML(const WebURL& response_url, + const char* data, + int len) { + if (!response_url.isValid()) + return; + + CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set = + *GetCrossOriginTextHtmlResponseSet(); + CrossOriginTextHtmlResponseSet::iterator request_iter = + cross_origin_text_html_response_set.find(response_url.spec()); + if (request_iter != cross_origin_text_html_response_set.end()) { + std::string sniffed_mime_type; + bool successful = net::SniffMimeType(data, len, response_url, + "", &sniffed_mime_type); + if (successful && sniffed_mime_type == "text/html") + LogVerifiedTextHtmlResponse(); + else + LogMislabeledTextHtmlResponse(); + cross_origin_text_html_response_set.erase(request_iter); + } +} + +void SiteIsolationMetrics::RemoveCompletedResponse( + const WebURL& response_url) { + if (!response_url.isValid()) + return; + + // Ensure we don't leave responses in the set after they've completed. + CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set = + *GetCrossOriginTextHtmlResponseSet(); + CrossOriginTextHtmlResponseSet::iterator request_iter = + cross_origin_text_html_response_set.find(response_url.spec()); + if (request_iter != cross_origin_text_html_response_set.end()) { + LogMislabeledTextHtmlResponse(); + cross_origin_text_html_response_set.erase(request_iter); + } +} + +} // namespace webkit_glue |