1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/site_isolation_metrics.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/hash_tables.h"
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/mime_sniffer.h"
1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebFrame;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebSecurityOrigin;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebString;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURL;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLRequest;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLResponse;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace webkit_glue {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef base::hash_map<unsigned, WebURLRequest::TargetType> TargetTypeMap;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef base::hash_map<std::string, int> MimeTypeMap;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef std::set<std::string> CrossOriginTextHtmlResponseSet;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic TargetTypeMap* GetTargetTypeMap() {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static TargetTypeMap target_type_map_;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return &target_type_map_;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copied from net/base/mime_util.cc, supported_non_image_types[]
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char* const kCrossOriginMimeTypesToLog[] = {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/cache-manifest",
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/html",
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/xml",
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/xsl",
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/plain",
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/vnd.chromium.ftp-dir",
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/",
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "text/css",
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "image/svg+xml",
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/xml",
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/xhtml+xml",
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/rss+xml",
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/atom+xml",
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/json",
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "application/x-x509-user-cert",
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "multipart/x-mixed-replace",
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "(NONE)"  // Keep track of missing MIME types as well
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic MimeTypeMap* GetMimeTypeMap() {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static MimeTypeMap mime_type_map_;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!mime_type_map_.size()) {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < arraysize(kCrossOriginMimeTypesToLog); ++i)
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mime_type_map_[kCrossOriginMimeTypesToLog[i]] = i;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return &mime_type_map_;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is set is used to keep track of the response urls that we want to
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// sniff, since we will have to wait for the payload to arrive.
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic CrossOriginTextHtmlResponseSet* GetCrossOriginTextHtmlResponseSet() {
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static CrossOriginTextHtmlResponseSet cross_origin_text_html_response_set_;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return &cross_origin_text_html_response_set_;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void LogVerifiedTextHtmlResponse() {
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS(
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SiteIsolation.CrossSiteNonFrameResponse_verified_texthtml_BLOCK", 1);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void LogMislabeledTextHtmlResponse() {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS(
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SiteIsolation.CrossSiteNonFrameResponse_mislabeled_texthtml", 1);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SiteIsolationMetrics::AddRequest(unsigned identifier,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebURLRequest::TargetType target_type) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TargetTypeMap& target_type_map = *GetTargetTypeMap();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  target_type_map[identifier] = target_type;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Check whether the given response is allowed due to access control headers.
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is basically a copy of the logic of passesAccessControlCheck() in
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// WebCore/loader/CrossOriginAccessControl.cpp.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SiteIsolationMetrics::AllowedByAccessControlHeader(
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebFrame* frame, const WebURLResponse& response) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WebString access_control_origin = response.httpHeaderField(
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebString::fromUTF8("Access-Control-Allow-Origin"));
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WebSecurityOrigin security_origin =
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebSecurityOrigin::createFromString(access_control_origin);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return access_control_origin == WebString::fromUTF8("*") ||
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         frame->securityOrigin().canAccess(security_origin);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We want to log any cross-site request that we don't think a renderer should
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// be allowed to make. We can safely ignore frame requests (since we'd like
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// those to be in a separate renderer) and plugin requests, even if they are
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cross-origin.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For comparison, we keep counts of:
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - All requests made by a renderer
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - All cross-site requests
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Then, for cross-site non-frame/plugin requests, we keep track of:
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Counts for MIME types of interest
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Counts of those MIME types that carry CORS headers
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Counts of mislabeled text/html responses (without CORS)
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// As well as those we would block:
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Counts of verified text/html responses (without CORS)
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Counts of XML/JSON responses (without CORS)
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This will let us say what percentage of requests we would end up blocking.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SiteIsolationMetrics::LogMimeTypeForCrossOriginRequest(
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("SiteIsolation.Requests", 1);
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TargetTypeMap& target_type_map = *GetTargetTypeMap();
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TargetTypeMap::iterator iter  = target_type_map.find(identifier);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter != target_type_map.end()) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebURLRequest::TargetType target_type = iter->second;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    target_type_map.erase(iter);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Focus on cross-site requests.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!frame->securityOrigin().canAccess(
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            WebSecurityOrigin::create(response.url()))) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UMA_HISTOGRAM_COUNTS("SiteIsolation.CrossSiteRequests", 1);
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Now focus on non-frame, non-plugin requests.
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (target_type != WebURLRequest::TargetIsMainFrame &&
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          target_type != WebURLRequest::TargetIsSubframe &&
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          target_type != WebURLRequest::TargetIsObject) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If it is part of a MIME type we might block, log the MIME type.
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string mime_type = response.mimeType().utf8();
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        MimeTypeMap mime_type_map = *GetMimeTypeMap();
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Also track it if it lacks a MIME type.
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // TODO(creis): 304 responses have no MIME type, so we don't handle
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // them correctly.  Can we look up their MIME type from the cache?
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (mime_type == "")
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          mime_type = "(NONE)";
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        MimeTypeMap::iterator mime_type_iter = mime_type_map.find(mime_type);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (mime_type_iter != mime_type_map.end()) {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UMA_HISTOGRAM_ENUMERATION(
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              "SiteIsolation.CrossSiteNonFrameResponse_MIME_Type",
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              mime_type_iter->second,
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              arraysize(kCrossOriginMimeTypesToLog));
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // We also check access control headers, in case this
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // cross-origin request has been explicitly permitted.
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (AllowedByAccessControlHeader(frame, response)) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            UMA_HISTOGRAM_ENUMERATION(
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                "SiteIsolation.CrossSiteNonFrameResponse_With_CORS_MIME_Type",
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                mime_type_iter->second,
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                arraysize(kCrossOriginMimeTypesToLog));
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          } else {
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // Without access control headers, we might block this request.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // Sometimes resources are mislabled as text/html, though, and we
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // should only block them if we can verify that.  To do so, we sniff
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // the content once we have some of the payload.
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            if (mime_type == "text/html") {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              // Remember the response until we can sniff its contents.
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              GetCrossOriginTextHtmlResponseSet()->insert(
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  response.url().spec());
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            } else if (mime_type == "text/xml" ||
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "text/xsl" ||
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "application/xml" ||
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "application/xhtml+xml" ||
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "application/rss+xml" ||
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "application/atom+xml" ||
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       mime_type == "application/json") {
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              // We will also block XML and JSON MIME types for cross-site
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              // non-frame requests without CORS headers.
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              UMA_HISTOGRAM_COUNTS(
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  "SiteIsolation.CrossSiteNonFrameResponse_xml_or_json_BLOCK",
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  1);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          }
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SiteIsolationMetrics::SniffCrossOriginHTML(const WebURL& response_url,
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                const char* data,
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                int len) {
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_url.isValid())
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Look up the URL to see if it is a text/html request we are tracking.
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set =
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *GetCrossOriginTextHtmlResponseSet();
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CrossOriginTextHtmlResponseSet::iterator request_iter =
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cross_origin_text_html_response_set.find(response_url.spec());
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request_iter != cross_origin_text_html_response_set.end()) {
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Log whether it actually looks like HTML.
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string sniffed_mime_type;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool successful = net::SniffMimeType(data, len, response_url,
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         "", &sniffed_mime_type);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (successful && sniffed_mime_type == "text/html")
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LogVerifiedTextHtmlResponse();
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LogMislabeledTextHtmlResponse();
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cross_origin_text_html_response_set.erase(request_iter);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SiteIsolationMetrics::RemoveCompletedResponse(
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const WebURL& response_url) {
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_url.isValid())
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ensure we don't leave responses in the set after they've completed.
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set =
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *GetCrossOriginTextHtmlResponseSet();
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CrossOriginTextHtmlResponseSet::iterator request_iter =
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cross_origin_text_html_response_set.find(response_url.spec());
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request_iter != cross_origin_text_html_response_set.end()) {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogMislabeledTextHtmlResponse();
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cross_origin_text_html_response_set.erase(request_iter);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace webkit_glue
232