| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/site_isolation_policy.h" | 5 #include "content/child/site_isolation_policy.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/strings/string_piece.h" | |
| 13 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 14 #include "content/child/child_thread.h" | |
| 15 #include "content/public/common/content_switches.h" | 13 #include "content/public/common/content_switches.h" |
| 16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 17 #include "net/http/http_response_headers.h" | 15 #include "net/http/http_response_headers.h" |
| 18 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" | 16 #include "webkit/common/resource_response_info.h" |
| 19 #include "third_party/WebKit/public/platform/WebString.h" | |
| 20 #include "third_party/WebKit/public/platform/WebURL.h" | |
| 21 #include "third_party/WebKit/public/platform/WebURLRequest.h" | |
| 22 #include "third_party/WebKit/public/platform/WebURLResponse.h" | |
| 23 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 24 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 25 #include "third_party/WebKit/public/web/WebFrameClient.h" | |
| 26 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" | |
| 27 | 17 |
| 28 using base::StringPiece; | 18 using base::StringPiece; |
| 29 using blink::WebDocument; | |
| 30 using blink::WebString; | |
| 31 using blink::WebURL; | |
| 32 using blink::WebURLResponse; | |
| 33 using blink::WebURLRequest; | |
| 34 | 19 |
| 35 namespace content { | 20 namespace content { |
| 36 | 21 |
| 37 namespace { | 22 namespace { |
| 38 | 23 |
| 39 // Maintain the bookkeeping data between OnReceivedResponse and | |
| 40 // OnReceivedData. The key is a request id maintained by ResourceDispatcher. | |
| 41 static base::LazyInstance<SiteIsolationPolicy::RequestIdToMetaDataMap> | |
| 42 g_metadata_map = LAZY_INSTANCE_INITIALIZER; | |
| 43 | |
| 44 // Maintain the bookkeeping data for OnReceivedData. Blocking decision is made | |
| 45 // when OnReceivedData is called for the first time for a request, and the | |
| 46 // decision will remain the same for following data. This map maintains the | |
| 47 // decision. The key is a request id maintained by ResourceDispatcher. | |
| 48 static base::LazyInstance<SiteIsolationPolicy::RequestIdToResultMap> | |
| 49 g_result_map = LAZY_INSTANCE_INITIALIZER; | |
| 50 | |
| 51 // The cross-site document blocking/UMA data collection is deactivated by | 24 // The cross-site document blocking/UMA data collection is deactivated by |
| 52 // default, and only activated in renderer processes. | 25 // default, and only activated in renderer processes. |
| 53 static bool g_policy_enabled = false; | 26 static bool g_policy_enabled = false; |
| 54 | 27 |
| 55 // MIME types | 28 // MIME types |
| 56 const char kTextHtml[] = "text/html"; | 29 const char kTextHtml[] = "text/html"; |
| 57 const char kTextXml[] = "text/xml"; | 30 const char kTextXml[] = "text/xml"; |
| 58 const char xAppRssXml[] = "application/rss+xml"; | 31 const char xAppRssXml[] = "application/rss+xml"; |
| 59 const char kAppXml[] = "application/xml"; | 32 const char kAppXml[] = "application/xml"; |
| 60 const char kAppJson[] = "application/json"; | 33 const char kAppJson[] = "application/json"; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 name, | 89 name, |
| 117 1, | 90 1, |
| 118 boundary_value, | 91 boundary_value, |
| 119 boundary_value + 1, | 92 boundary_value + 1, |
| 120 base::HistogramBase::kUmaTargetedHistogramFlag); | 93 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 121 histogram_pointer->Add(sample); | 94 histogram_pointer->Add(sample); |
| 122 } | 95 } |
| 123 | 96 |
| 124 void HistogramCountBlockedResponse( | 97 void HistogramCountBlockedResponse( |
| 125 const std::string& bucket_prefix, | 98 const std::string& bucket_prefix, |
| 126 const SiteIsolationPolicy::ResponseMetaData& resp_data, | 99 linked_ptr<SiteIsolationResponseMetaData>& resp_data, |
| 127 bool nosniff_block) { | 100 bool nosniff_block) { |
| 128 std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked"); | 101 std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked"); |
| 129 IncrementHistogramCount(bucket_prefix + block_label); | 102 IncrementHistogramCount(bucket_prefix + block_label); |
| 130 | 103 |
| 131 // The content is blocked if it is sniffed as HTML/JSON/XML. When | 104 // The content is blocked if it is sniffed as HTML/JSON/XML. When |
| 132 // the blocked response is with an error status code, it is not | 105 // the blocked response is with an error status code, it is not |
| 133 // disruptive for the following reasons : 1) the blocked content is | 106 // disruptive for the following reasons : 1) the blocked content is |
| 134 // not a binary object (such as an image) since it is sniffed as | 107 // not a binary object (such as an image) since it is sniffed as |
| 135 // text; 2) then, this blocking only breaks the renderer behavior | 108 // text; 2) then, this blocking only breaks the renderer behavior |
| 136 // only if it is either JavaScript or CSS. However, the renderer | 109 // only if it is either JavaScript or CSS. However, the renderer |
| 137 // doesn't use the contents of JS/CSS with unaffected status code | 110 // doesn't use the contents of JS/CSS with unaffected status code |
| 138 // (e.g, 404). 3) the renderer is expected not to use the cross-site | 111 // (e.g, 404). 3) the renderer is expected not to use the cross-site |
| 139 // document content for purposes other than JS/CSS (e.g, XHR). | 112 // document content for purposes other than JS/CSS (e.g, XHR). |
| 140 bool renderable_status_code = | 113 bool renderable_status_code = |
| 141 IsRenderableStatusCode(resp_data.http_status_code); | 114 IsRenderableStatusCode(resp_data->http_status_code); |
| 142 | 115 |
| 143 if (renderable_status_code) { | 116 if (renderable_status_code) { |
| 144 IncrementHistogramEnum( | 117 IncrementHistogramEnum( |
| 145 bucket_prefix + block_label + ".RenderableStatusCode", | 118 bucket_prefix + block_label + ".RenderableStatusCode", |
| 146 resp_data.resource_type, | 119 resp_data->resource_type, |
| 147 ResourceType::LAST_TYPE); | 120 ResourceType::LAST_TYPE); |
| 148 } else { | 121 } else { |
| 149 IncrementHistogramCount(bucket_prefix + block_label + | 122 IncrementHistogramCount(bucket_prefix + block_label + |
| 150 ".NonRenderableStatusCode"); | 123 ".NonRenderableStatusCode"); |
| 151 } | 124 } |
| 152 } | 125 } |
| 153 | 126 |
| 154 void HistogramCountNotBlockedResponse(const std::string& bucket_prefix, | 127 void HistogramCountNotBlockedResponse(const std::string& bucket_prefix, |
| 155 bool sniffed_as_js) { | 128 bool sniffed_as_js) { |
| 156 IncrementHistogramCount(bucket_prefix + ".NotBlocked"); | 129 IncrementHistogramCount(bucket_prefix + ".NotBlocked"); |
| 157 if (sniffed_as_js) | 130 if (sniffed_as_js) |
| 158 IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS"); | 131 IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS"); |
| 159 } | 132 } |
| 160 | 133 |
| 161 } // namespace | 134 } // namespace |
| 162 | 135 |
| 163 SiteIsolationPolicy::ResponseMetaData::ResponseMetaData() {} | 136 SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {} |
| 164 | 137 |
| 165 void SiteIsolationPolicy::SetPolicyEnabled(bool enabled) { | 138 void SiteIsolationPolicy::SetPolicyEnabled(bool enabled) { |
| 166 g_policy_enabled = enabled; | 139 g_policy_enabled = enabled; |
| 167 } | 140 } |
| 168 | 141 |
| 169 void SiteIsolationPolicy::OnReceivedResponse( | 142 linked_ptr<SiteIsolationResponseMetaData> |
| 170 int request_id, | 143 SiteIsolationPolicy::OnReceivedResponse( |
| 171 const GURL& frame_origin, | 144 const GURL& frame_origin, |
| 172 const GURL& response_url, | 145 const GURL& response_url, |
| 173 ResourceType::Type resource_type, | 146 ResourceType::Type resource_type, |
| 174 int origin_pid, | 147 int origin_pid, |
| 175 const webkit_glue::ResourceResponseInfo& info) { | 148 const webkit_glue::ResourceResponseInfo& info) { |
| 176 if (!g_policy_enabled) | 149 if (!g_policy_enabled) |
| 177 return; | 150 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 178 | 151 |
| 179 // if |origin_pid| is non-zero, it means that this response is for a plugin | 152 // if |origin_pid| is non-zero, it means that this response is for a plugin |
| 180 // spawned from this renderer process. We exclude responses for plugins for | 153 // spawned from this renderer process. We exclude responses for plugins for |
| 181 // now, but eventually, we're going to make plugin processes directly talk to | 154 // now, but eventually, we're going to make plugin processes directly talk to |
| 182 // the browser process so that we don't apply cross-site document blocking to | 155 // the browser process so that we don't apply cross-site document blocking to |
| 183 // them. | 156 // them. |
| 184 if (origin_pid) | 157 if (origin_pid) |
| 185 return; | 158 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 186 | 159 |
| 187 UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1); | 160 UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1); |
| 188 | 161 |
| 189 // See if this is for navigation. If it is, don't block it, under the | 162 // See if this is for navigation. If it is, don't block it, under the |
| 190 // assumption that we will put it in an appropriate process. | 163 // assumption that we will put it in an appropriate process. |
| 191 if (ResourceType::IsFrame(resource_type)) | 164 if (ResourceType::IsFrame(resource_type)) |
| 192 return; | 165 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 193 | 166 |
| 194 if (!IsBlockableScheme(response_url)) | 167 if (!IsBlockableScheme(response_url)) |
| 195 return; | 168 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 196 | 169 |
| 197 if (IsSameSite(frame_origin, response_url)) | 170 if (IsSameSite(frame_origin, response_url)) |
| 198 return; | 171 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 199 | 172 |
| 200 SiteIsolationPolicy::ResponseMetaData::CanonicalMimeType canonical_mime_type = | 173 SiteIsolationResponseMetaData::CanonicalMimeType canonical_mime_type = |
| 201 GetCanonicalMimeType(info.mime_type); | 174 GetCanonicalMimeType(info.mime_type); |
| 202 | 175 |
| 203 if (canonical_mime_type == SiteIsolationPolicy::ResponseMetaData::Others) | 176 if (canonical_mime_type == SiteIsolationResponseMetaData::Others) |
| 204 return; | 177 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 205 | 178 |
| 206 // Every CORS request should have the Access-Control-Allow-Origin header even | 179 // Every CORS request should have the Access-Control-Allow-Origin header even |
| 207 // if it is preceded by a pre-flight request. Therefore, if this is a CORS | 180 // if it is preceded by a pre-flight request. Therefore, if this is a CORS |
| 208 // request, it has this header. response.httpHeaderField() internally uses | 181 // request, it has this header. response.httpHeaderField() internally uses |
| 209 // case-insensitive matching for the header name. | 182 // case-insensitive matching for the header name. |
| 210 std::string access_control_origin; | 183 std::string access_control_origin; |
| 211 | 184 |
| 212 // We can use a case-insensitive header name for EnumerateHeader(). | 185 // We can use a case-insensitive header name for EnumerateHeader(). |
| 213 info.headers->EnumerateHeader( | 186 info.headers->EnumerateHeader( |
| 214 NULL, "access-control-allow-origin", &access_control_origin); | 187 NULL, "access-control-allow-origin", &access_control_origin); |
| 215 if (IsValidCorsHeaderSet(frame_origin, response_url, access_control_origin)) | 188 if (IsValidCorsHeaderSet(frame_origin, response_url, access_control_origin)) |
| 216 return; | 189 return linked_ptr<SiteIsolationResponseMetaData>(); |
| 217 | 190 |
| 218 // Real XSD data collection starts from here. | 191 // Real XSD data collection starts from here. |
| 219 std::string no_sniff; | 192 std::string no_sniff; |
| 220 info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff); | 193 info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff); |
| 221 | 194 |
| 222 ResponseMetaData resp_data; | 195 linked_ptr<SiteIsolationResponseMetaData> resp_data( |
| 223 resp_data.frame_origin = frame_origin.spec(); | 196 new SiteIsolationResponseMetaData); |
| 224 resp_data.response_url = response_url; | 197 resp_data->frame_origin = frame_origin.spec(); |
| 225 resp_data.resource_type = resource_type; | 198 resp_data->response_url = response_url; |
| 226 resp_data.canonical_mime_type = canonical_mime_type; | 199 resp_data->resource_type = resource_type; |
| 227 resp_data.http_status_code = info.headers->response_code(); | 200 resp_data->canonical_mime_type = canonical_mime_type; |
| 228 resp_data.no_sniff = LowerCaseEqualsASCII(no_sniff, "nosniff"); | 201 resp_data->http_status_code = info.headers->response_code(); |
| 202 resp_data->no_sniff = LowerCaseEqualsASCII(no_sniff, "nosniff"); |
| 229 | 203 |
| 230 (g_metadata_map.Get())[request_id] = resp_data; | 204 return resp_data; |
| 231 } | 205 } |
| 232 | 206 |
| 233 bool SiteIsolationPolicy::ShouldBlockResponse( | 207 bool SiteIsolationPolicy::ShouldBlockResponse( |
| 234 int request_id, | 208 linked_ptr<SiteIsolationResponseMetaData>& resp_data, |
| 235 const char* raw_data, | 209 const char* raw_data, |
| 236 int raw_length, | 210 int raw_length, |
| 237 std::string* alternative_data) { | 211 std::string* alternative_data) { |
| 238 if (!g_policy_enabled) | 212 if (!g_policy_enabled) |
| 239 return false; | 213 return false; |
| 240 | 214 |
| 241 RequestIdToMetaDataMap& metadata_map = g_metadata_map.Get(); | 215 DCHECK(resp_data.get()); |
| 242 RequestIdToResultMap& result_map = g_result_map.Get(); | |
| 243 | |
| 244 // If there's an entry for |request_id| in blocked_map, this request's first | |
| 245 // data packet has already been examined. We can return the result here. | |
| 246 if (result_map.count(request_id) != 0) { | |
| 247 if (result_map[request_id]) { | |
| 248 // Here, the blocking result has been set for the previous run of | |
| 249 // ShouldBlockResponse(), so we set alternative data to an empty string so | |
| 250 // that ResourceDispatcher doesn't call its peer's onReceivedData() with | |
| 251 // the alternative data. | |
| 252 alternative_data->erase(); | |
| 253 return true; | |
| 254 } | |
| 255 return false; | |
| 256 } | |
| 257 | |
| 258 // If result_map doesn't have an entry for |request_id|, we're receiving the | |
| 259 // first data packet for request_id. If request_id is not registered, this | |
| 260 // request is identified as a non-target of our policy. So we return true. | |
| 261 if (metadata_map.count(request_id) == 0) { | |
| 262 // We set request_id to true so that we always return true for this request. | |
| 263 result_map[request_id] = false; | |
| 264 return false; | |
| 265 } | |
| 266 | 216 |
| 267 StringPiece data(raw_data, raw_length); | 217 StringPiece data(raw_data, raw_length); |
| 268 | 218 |
| 269 // We now look at the first data packet received for request_id. | |
| 270 ResponseMetaData resp_data = metadata_map[request_id]; | |
| 271 metadata_map.erase(request_id); | |
| 272 | |
| 273 // Record the length of the first received network packet to see if it's | 219 // Record the length of the first received network packet to see if it's |
| 274 // enough for sniffing. | 220 // enough for sniffing. |
| 275 UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length); | 221 UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length); |
| 276 | 222 |
| 277 // Record the number of cross-site document responses with a specific mime | 223 // Record the number of cross-site document responses with a specific mime |
| 278 // type (text/html, text/xml, etc). | 224 // type (text/html, text/xml, etc). |
| 279 UMA_HISTOGRAM_ENUMERATION( | 225 UMA_HISTOGRAM_ENUMERATION( |
| 280 "SiteIsolation.XSD.MimeType", | 226 "SiteIsolation.XSD.MimeType", |
| 281 resp_data.canonical_mime_type, | 227 resp_data->canonical_mime_type, |
| 282 SiteIsolationPolicy::ResponseMetaData::MaxCanonicalMimeType); | 228 SiteIsolationResponseMetaData::MaxCanonicalMimeType); |
| 283 | 229 |
| 284 // Store the result of cross-site document blocking analysis. | 230 // Store the result of cross-site document blocking analysis. |
| 285 bool is_blocked = false; | 231 bool is_blocked = false; |
| 286 bool sniffed_as_js = SniffForJS(data); | 232 bool sniffed_as_js = SniffForJS(data); |
| 287 | 233 |
| 288 // Record the number of responses whose content is sniffed for what its mime | 234 // Record the number of responses whose content is sniffed for what its mime |
| 289 // type claims it to be. For example, we apply a HTML sniffer for a document | 235 // type claims it to be. For example, we apply a HTML sniffer for a document |
| 290 // tagged with text/html here. Whenever this check becomes true, we'll block | 236 // tagged with text/html here. Whenever this check becomes true, we'll block |
| 291 // the response. | 237 // the response. |
| 292 if (resp_data.canonical_mime_type != | 238 if (resp_data->canonical_mime_type != |
| 293 SiteIsolationPolicy::ResponseMetaData::Plain) { | 239 SiteIsolationResponseMetaData::Plain) { |
| 294 std::string bucket_prefix; | 240 std::string bucket_prefix; |
| 295 bool sniffed_as_target_document = false; | 241 bool sniffed_as_target_document = false; |
| 296 if (resp_data.canonical_mime_type == | 242 if (resp_data->canonical_mime_type == |
| 297 SiteIsolationPolicy::ResponseMetaData::HTML) { | 243 SiteIsolationResponseMetaData::HTML) { |
| 298 bucket_prefix = "SiteIsolation.XSD.HTML"; | 244 bucket_prefix = "SiteIsolation.XSD.HTML"; |
| 299 sniffed_as_target_document = SniffForHTML(data); | 245 sniffed_as_target_document = SniffForHTML(data); |
| 300 } else if (resp_data.canonical_mime_type == | 246 } else if (resp_data->canonical_mime_type == |
| 301 SiteIsolationPolicy::ResponseMetaData::XML) { | 247 SiteIsolationResponseMetaData::XML) { |
| 302 bucket_prefix = "SiteIsolation.XSD.XML"; | 248 bucket_prefix = "SiteIsolation.XSD.XML"; |
| 303 sniffed_as_target_document = SniffForXML(data); | 249 sniffed_as_target_document = SniffForXML(data); |
| 304 } else if (resp_data.canonical_mime_type == | 250 } else if (resp_data->canonical_mime_type == |
| 305 SiteIsolationPolicy::ResponseMetaData::JSON) { | 251 SiteIsolationResponseMetaData::JSON) { |
| 306 bucket_prefix = "SiteIsolation.XSD.JSON"; | 252 bucket_prefix = "SiteIsolation.XSD.JSON"; |
| 307 sniffed_as_target_document = SniffForJSON(data); | 253 sniffed_as_target_document = SniffForJSON(data); |
| 308 } else { | 254 } else { |
| 309 NOTREACHED() << "Not a blockable mime type: " | 255 NOTREACHED() << "Not a blockable mime type: " |
| 310 << resp_data.canonical_mime_type; | 256 << resp_data->canonical_mime_type; |
| 311 } | 257 } |
| 312 | 258 |
| 313 if (sniffed_as_target_document) { | 259 if (sniffed_as_target_document) { |
| 314 is_blocked = true; | 260 is_blocked = true; |
| 315 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); | 261 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); |
| 316 } else { | 262 } else { |
| 317 if (resp_data.no_sniff) { | 263 if (resp_data->no_sniff) { |
| 318 is_blocked = true; | 264 is_blocked = true; |
| 319 HistogramCountBlockedResponse(bucket_prefix, resp_data, true); | 265 HistogramCountBlockedResponse(bucket_prefix, resp_data, true); |
| 320 } else { | 266 } else { |
| 321 HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js); | 267 HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js); |
| 322 } | 268 } |
| 323 } | 269 } |
| 324 } else { | 270 } else { |
| 325 // This block is for plain text documents. We apply our HTML, XML, | 271 // This block is for plain text documents. We apply our HTML, XML, |
| 326 // and JSON sniffer to a text document in the order, and block it | 272 // and JSON sniffer to a text document in the order, and block it |
| 327 // if any of them succeeds in sniffing. | 273 // if any of them succeeds in sniffing. |
| 328 std::string bucket_prefix; | 274 std::string bucket_prefix; |
| 329 if (SniffForHTML(data)) | 275 if (SniffForHTML(data)) |
| 330 bucket_prefix = "SiteIsolation.XSD.Plain.HTML"; | 276 bucket_prefix = "SiteIsolation.XSD.Plain.HTML"; |
| 331 else if (SniffForXML(data)) | 277 else if (SniffForXML(data)) |
| 332 bucket_prefix = "SiteIsolation.XSD.Plain.XML"; | 278 bucket_prefix = "SiteIsolation.XSD.Plain.XML"; |
| 333 else if (SniffForJSON(data)) | 279 else if (SniffForJSON(data)) |
| 334 bucket_prefix = "SiteIsolation.XSD.Plain.JSON"; | 280 bucket_prefix = "SiteIsolation.XSD.Plain.JSON"; |
| 335 | 281 |
| 336 if (bucket_prefix.size() > 0) { | 282 if (bucket_prefix.size() > 0) { |
| 337 is_blocked = true; | 283 is_blocked = true; |
| 338 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); | 284 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); |
| 339 } else if (resp_data.no_sniff) { | 285 } else if (resp_data->no_sniff) { |
| 340 is_blocked = true; | 286 is_blocked = true; |
| 341 HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true); | 287 HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true); |
| 342 } else { | 288 } else { |
| 343 HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain", | 289 HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain", |
| 344 sniffed_as_js); | 290 sniffed_as_js); |
| 345 } | 291 } |
| 346 } | 292 } |
| 347 | 293 |
| 348 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 294 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 349 switches::kBlockCrossSiteDocuments)) | 295 switches::kBlockCrossSiteDocuments)) |
| 350 is_blocked = false; | 296 is_blocked = false; |
| 351 result_map[request_id] = is_blocked; | |
| 352 | 297 |
| 353 if (is_blocked) { | 298 if (is_blocked) { |
| 354 alternative_data->erase(); | 299 alternative_data->erase(); |
| 355 alternative_data->insert(0, " "); | 300 alternative_data->insert(0, " "); |
| 356 LOG(ERROR) << resp_data.response_url | 301 LOG(ERROR) << resp_data->response_url |
| 357 << " is blocked as an illegal cross-site document from " | 302 << " is blocked as an illegal cross-site document from " |
| 358 << resp_data.frame_origin; | 303 << resp_data->frame_origin; |
| 359 } | 304 } |
| 360 return is_blocked; | 305 return is_blocked; |
| 361 } | 306 } |
| 362 | 307 |
| 363 void SiteIsolationPolicy::OnRequestComplete(int request_id) { | 308 SiteIsolationResponseMetaData::CanonicalMimeType |
| 364 if (!g_policy_enabled) | |
| 365 return; | |
| 366 g_metadata_map.Get().erase(request_id); | |
| 367 g_result_map.Get().erase(request_id); | |
| 368 } | |
| 369 | |
| 370 SiteIsolationPolicy::ResponseMetaData::CanonicalMimeType | |
| 371 SiteIsolationPolicy::GetCanonicalMimeType(const std::string& mime_type) { | 309 SiteIsolationPolicy::GetCanonicalMimeType(const std::string& mime_type) { |
| 372 if (LowerCaseEqualsASCII(mime_type, kTextHtml)) { | 310 if (LowerCaseEqualsASCII(mime_type, kTextHtml)) { |
| 373 return SiteIsolationPolicy::ResponseMetaData::HTML; | 311 return SiteIsolationResponseMetaData::HTML; |
| 374 } | 312 } |
| 375 | 313 |
| 376 if (LowerCaseEqualsASCII(mime_type, kTextPlain)) { | 314 if (LowerCaseEqualsASCII(mime_type, kTextPlain)) { |
| 377 return SiteIsolationPolicy::ResponseMetaData::Plain; | 315 return SiteIsolationResponseMetaData::Plain; |
| 378 } | 316 } |
| 379 | 317 |
| 380 if (LowerCaseEqualsASCII(mime_type, kAppJson) || | 318 if (LowerCaseEqualsASCII(mime_type, kAppJson) || |
| 381 LowerCaseEqualsASCII(mime_type, kTextJson) || | 319 LowerCaseEqualsASCII(mime_type, kTextJson) || |
| 382 LowerCaseEqualsASCII(mime_type, kTextXjson)) { | 320 LowerCaseEqualsASCII(mime_type, kTextXjson)) { |
| 383 return SiteIsolationPolicy::ResponseMetaData::JSON; | 321 return SiteIsolationResponseMetaData::JSON; |
| 384 } | 322 } |
| 385 | 323 |
| 386 if (LowerCaseEqualsASCII(mime_type, kTextXml) || | 324 if (LowerCaseEqualsASCII(mime_type, kTextXml) || |
| 387 LowerCaseEqualsASCII(mime_type, xAppRssXml) || | 325 LowerCaseEqualsASCII(mime_type, xAppRssXml) || |
| 388 LowerCaseEqualsASCII(mime_type, kAppXml)) { | 326 LowerCaseEqualsASCII(mime_type, kAppXml)) { |
| 389 return SiteIsolationPolicy::ResponseMetaData::XML; | 327 return SiteIsolationResponseMetaData::XML; |
| 390 } | 328 } |
| 391 | 329 |
| 392 return SiteIsolationPolicy::ResponseMetaData::Others; | 330 return SiteIsolationResponseMetaData::Others; |
| 393 } | 331 } |
| 394 | 332 |
| 395 bool SiteIsolationPolicy::IsBlockableScheme(const GURL& url) { | 333 bool SiteIsolationPolicy::IsBlockableScheme(const GURL& url) { |
| 396 // We exclude ftp:// from here. FTP doesn't provide a Content-Type | 334 // We exclude ftp:// from here. FTP doesn't provide a Content-Type |
| 397 // header which our policy depends on, so we cannot protect any | 335 // header which our policy depends on, so we cannot protect any |
| 398 // document from FTP servers. | 336 // document from FTP servers. |
| 399 return url.SchemeIs("http") || url.SchemeIs("https"); | 337 return url.SchemeIs("http") || url.SchemeIs("https"); |
| 400 } | 338 } |
| 401 | 339 |
| 402 bool SiteIsolationPolicy::IsSameSite(const GURL& frame_origin, | 340 bool SiteIsolationPolicy::IsSameSite(const GURL& frame_origin, |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 // TODO(dsjang): This is a real hack. The only purpose of this function is to | 505 // TODO(dsjang): This is a real hack. The only purpose of this function is to |
| 568 // try to see if there's any possibility that this data can be JavaScript | 506 // try to see if there's any possibility that this data can be JavaScript |
| 569 // (superset of JS). This function will be removed once UMA stats are | 507 // (superset of JS). This function will be removed once UMA stats are |
| 570 // gathered. | 508 // gathered. |
| 571 | 509 |
| 572 // Search for "var " for JS detection. | 510 // Search for "var " for JS detection. |
| 573 return data.find("var ") != base::StringPiece::npos; | 511 return data.find("var ") != base::StringPiece::npos; |
| 574 } | 512 } |
| 575 | 513 |
| 576 } // namespace content | 514 } // namespace content |
| OLD | NEW |