Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/predictors/resource_prefetch_predictor.h" | 5 #include "chrome/browser/predictors/resource_prefetch_predictor.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 #include <array> | |
| 7 #include <map> | 9 #include <map> |
| 8 #include <set> | 10 #include <set> |
| 9 #include <utility> | 11 #include <utility> |
| 10 | 12 |
| 11 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 12 #include "base/macros.h" | 14 #include "base/macros.h" |
| 13 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 14 #include "base/metrics/sparse_histogram.h" | 16 #include "base/metrics/sparse_histogram.h" |
| 15 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 38 | 40 |
| 39 using content::BrowserThread; | 41 using content::BrowserThread; |
| 40 | 42 |
| 41 namespace { | 43 namespace { |
| 42 | 44 |
| 43 // For reporting whether a subresource is handled or not, and for what reasons. | 45 // For reporting whether a subresource is handled or not, and for what reasons. |
| 44 enum ResourceStatus { | 46 enum ResourceStatus { |
| 45 RESOURCE_STATUS_HANDLED = 0, | 47 RESOURCE_STATUS_HANDLED = 0, |
| 46 RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_PAGE = 1, | 48 RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_PAGE = 1, |
| 47 RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_RESOURCE = 2, | 49 RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_RESOURCE = 2, |
| 48 RESOURCE_STATUS_UNSUPPORTED_MIME_TYPE = 4, | 50 RESOURCE_STATUS_UNSUPPORTED_RESOURCE_TYPE = 4, |
| 49 RESOURCE_STATUS_NOT_GET = 8, | 51 RESOURCE_STATUS_NOT_GET = 8, |
| 50 RESOURCE_STATUS_URL_TOO_LONG = 16, | 52 RESOURCE_STATUS_URL_TOO_LONG = 16, |
| 51 RESOURCE_STATUS_NOT_CACHEABLE = 32, | 53 RESOURCE_STATUS_NOT_CACHEABLE = 32, |
| 52 RESOURCE_STATUS_HEADERS_MISSING = 64, | 54 RESOURCE_STATUS_HEADERS_MISSING = 64, |
| 53 RESOURCE_STATUS_MAX = 128, | 55 RESOURCE_STATUS_MAX = 128, |
| 54 }; | 56 }; |
| 55 | 57 |
| 56 // For reporting various interesting events that occur during the loading of a | 58 // For reporting various interesting events that occur during the loading of a |
| 57 // single main frame. | 59 // single main frame. |
| 58 enum NavigationEvent { | 60 enum NavigationEvent { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 bool ResourcePrefetchPredictor::ShouldRecordResponse( | 206 bool ResourcePrefetchPredictor::ShouldRecordResponse( |
| 205 net::URLRequest* response) { | 207 net::URLRequest* response) { |
| 206 const content::ResourceRequestInfo* request_info = | 208 const content::ResourceRequestInfo* request_info = |
| 207 content::ResourceRequestInfo::ForRequest(response); | 209 content::ResourceRequestInfo::ForRequest(response); |
| 208 if (!request_info) | 210 if (!request_info) |
| 209 return false; | 211 return false; |
| 210 | 212 |
| 211 if (!request_info->IsMainFrame()) | 213 if (!request_info->IsMainFrame()) |
| 212 return false; | 214 return false; |
| 213 | 215 |
| 214 return request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME ? | 216 content::ResourceType resource_type = request_info->GetResourceType(); |
| 215 IsHandledMainPage(response) : IsHandledSubresource(response); | 217 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME |
| 218 ? IsHandledMainPage(response) | |
| 219 : IsHandledSubresource(response, resource_type); | |
| 216 } | 220 } |
| 217 | 221 |
| 218 // static | 222 // static |
| 219 bool ResourcePrefetchPredictor::ShouldRecordRedirect( | 223 bool ResourcePrefetchPredictor::ShouldRecordRedirect( |
| 220 net::URLRequest* response) { | 224 net::URLRequest* response) { |
| 221 const content::ResourceRequestInfo* request_info = | 225 const content::ResourceRequestInfo* request_info = |
| 222 content::ResourceRequestInfo::ForRequest(response); | 226 content::ResourceRequestInfo::ForRequest(response); |
| 223 if (!request_info) | 227 if (!request_info) |
| 224 return false; | 228 return false; |
| 225 | 229 |
| 226 if (!request_info->IsMainFrame()) | 230 if (!request_info->IsMainFrame()) |
| 227 return false; | 231 return false; |
| 228 | 232 |
| 229 return request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME && | 233 return request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME && |
| 230 IsHandledMainPage(response); | 234 IsHandledMainPage(response); |
| 231 } | 235 } |
| 232 | 236 |
| 233 // static | 237 // static |
| 234 bool ResourcePrefetchPredictor::IsHandledMainPage(net::URLRequest* request) { | 238 bool ResourcePrefetchPredictor::IsHandledMainPage(net::URLRequest* request) { |
| 235 return request->url().SchemeIsHTTPOrHTTPS(); | 239 return request->url().SchemeIsHTTPOrHTTPS(); |
| 236 } | 240 } |
| 237 | 241 |
| 238 // static | 242 // static |
| 239 bool ResourcePrefetchPredictor::IsHandledSubresource( | 243 bool ResourcePrefetchPredictor::IsHandledSubresource( |
| 240 net::URLRequest* response) { | 244 net::URLRequest* response, |
| 245 content::ResourceType resource_type) { | |
| 241 int resource_status = 0; | 246 int resource_status = 0; |
| 242 | 247 |
| 243 if (!response->first_party_for_cookies().SchemeIsHTTPOrHTTPS()) | 248 if (!response->first_party_for_cookies().SchemeIsHTTPOrHTTPS()) |
| 244 resource_status |= RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_PAGE; | 249 resource_status |= RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_PAGE; |
| 245 | 250 |
| 246 if (!response->url().SchemeIsHTTPOrHTTPS()) | 251 if (!response->url().SchemeIsHTTPOrHTTPS()) |
| 247 resource_status |= RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_RESOURCE; | 252 resource_status |= RESOURCE_STATUS_NOT_HTTP_OR_HTTPS_RESOURCE; |
| 248 | 253 |
| 249 std::string mime_type; | 254 std::string mime_type; |
| 250 response->GetMimeType(&mime_type); | 255 response->GetMimeType(&mime_type); |
| 251 if (!mime_type.empty() && !mime_util::IsSupportedImageMimeType(mime_type) && | 256 if (!IsHandledResourceType(resource_type, mime_type)) |
| 252 !mime_util::IsSupportedJavascriptMimeType(mime_type) && | 257 resource_status |= RESOURCE_STATUS_UNSUPPORTED_RESOURCE_TYPE; |
| 253 !net::MatchesMimeType("text/css", mime_type)) { | |
| 254 resource_status |= RESOURCE_STATUS_UNSUPPORTED_MIME_TYPE; | |
| 255 } | |
| 256 | 258 |
| 257 if (response->method() != "GET") | 259 if (response->method() != "GET") |
| 258 resource_status |= RESOURCE_STATUS_NOT_GET; | 260 resource_status |= RESOURCE_STATUS_NOT_GET; |
| 259 | 261 |
| 260 if (response->original_url().spec().length() > | 262 if (response->original_url().spec().length() > |
| 261 ResourcePrefetchPredictorTables::kMaxStringLength) { | 263 ResourcePrefetchPredictorTables::kMaxStringLength) { |
| 262 resource_status |= RESOURCE_STATUS_URL_TOO_LONG; | 264 resource_status |= RESOURCE_STATUS_URL_TOO_LONG; |
| 263 } | 265 } |
| 264 | 266 |
| 265 if (!response->response_info().headers.get()) | 267 if (!response->response_info().headers.get()) |
| 266 resource_status |= RESOURCE_STATUS_HEADERS_MISSING; | 268 resource_status |= RESOURCE_STATUS_HEADERS_MISSING; |
| 267 | 269 |
| 268 if (!IsCacheable(response)) | 270 if (!IsCacheable(response)) |
| 269 resource_status |= RESOURCE_STATUS_NOT_CACHEABLE; | 271 resource_status |= RESOURCE_STATUS_NOT_CACHEABLE; |
| 270 | 272 |
| 271 UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.ResourceStatus", | 273 UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.ResourceStatus", |
| 272 resource_status, | 274 resource_status, |
| 273 RESOURCE_STATUS_MAX); | 275 RESOURCE_STATUS_MAX); |
| 274 | 276 |
| 275 return resource_status == 0; | 277 return resource_status == 0; |
| 276 } | 278 } |
| 277 | 279 |
| 278 // static | 280 // static |
| 281 bool ResourcePrefetchPredictor::IsHandledResourceType( | |
| 282 content::ResourceType resource_type, | |
| 283 const std::string& mime_type) { | |
| 284 bool handled = resource_type == content::RESOURCE_TYPE_STYLESHEET || | |
| 285 resource_type == content::RESOURCE_TYPE_SCRIPT || | |
| 286 resource_type == content::RESOURCE_TYPE_IMAGE || | |
| 287 resource_type == content::RESOURCE_TYPE_FONT_RESOURCE; | |
| 288 // Need this because content::RESOURCE_TYPE_{PREFETCH,SUB_RESOURCE} can be | |
| 289 // anything. | |
|
pasko
2016/07/28 18:42:57
This would be an easier to read comment:
// Restr
Benoit L
2016/07/29 08:56:27
Done.
| |
| 290 if (!handled && (resource_type == content::RESOURCE_TYPE_PREFETCH || | |
|
pasko
2016/07/28 18:42:57
one of these values for resource_type implies (!ha
Benoit L
2016/07/29 08:56:27
Done.
| |
| 291 resource_type == content::RESOURCE_TYPE_SUB_RESOURCE)) { | |
| 292 content::ResourceType resource_type_from_mime = GetResourceTypeFromMimeType( | |
| 293 mime_type, content::RESOURCE_TYPE_LAST_TYPE); | |
| 294 handled = resource_type_from_mime != content::RESOURCE_TYPE_LAST_TYPE; | |
| 295 } | |
| 296 return handled; | |
| 297 } | |
| 298 | |
| 299 // static | |
| 279 bool ResourcePrefetchPredictor::IsCacheable(const net::URLRequest* response) { | 300 bool ResourcePrefetchPredictor::IsCacheable(const net::URLRequest* response) { |
| 280 if (response->was_cached()) | 301 if (response->was_cached()) |
| 281 return true; | 302 return true; |
| 282 | 303 |
| 283 // For non cached responses, we will ensure that the freshness lifetime is | 304 // For non cached responses, we will ensure that the freshness lifetime is |
| 284 // some sane value. | 305 // some sane value. |
| 285 const net::HttpResponseInfo& response_info = response->response_info(); | 306 const net::HttpResponseInfo& response_info = response->response_info(); |
| 286 if (!response_info.headers.get()) | 307 if (!response_info.headers.get()) |
| 287 return false; | 308 return false; |
| 288 base::Time response_time(response_info.response_time); | 309 base::Time response_time(response_info.response_time); |
| 289 response_time += base::TimeDelta::FromSeconds(1); | 310 response_time += base::TimeDelta::FromSeconds(1); |
| 290 base::TimeDelta freshness = | 311 base::TimeDelta freshness = |
| 291 response_info.headers->GetFreshnessLifetimes(response_time).freshness; | 312 response_info.headers->GetFreshnessLifetimes(response_time).freshness; |
| 292 return freshness > base::TimeDelta(); | 313 return freshness > base::TimeDelta(); |
| 293 } | 314 } |
| 294 | 315 |
| 295 // static | 316 // static |
| 296 content::ResourceType ResourcePrefetchPredictor::GetResourceTypeFromMimeType( | 317 content::ResourceType ResourcePrefetchPredictor::GetResourceTypeFromMimeType( |
| 297 const std::string& mime_type, | 318 const std::string& mime_type, |
| 298 content::ResourceType fallback) { | 319 content::ResourceType fallback) { |
| 299 if (mime_util::IsSupportedImageMimeType(mime_type)) | 320 // Sorted by decreasing likelihood according to HTTP archive. |
| 321 static const std::array<std::string, 12> font_mime_types = { | |
|
pasko
2016/07/28 18:42:57
nit: it would be less error prone to avoid indicat
Benoit L
2016/07/29 08:56:27
Done.
| |
| 322 "font/woff2", | |
| 323 "application/x-font-woff", | |
| 324 "application/font-woff", | |
| 325 "application/font-woff2", | |
| 326 "font/x-woff", | |
| 327 "application/x-font-ttf", | |
| 328 "font/woff", | |
| 329 "font/ttf", | |
| 330 "application/x-font-otf", | |
| 331 "x-font/woff", | |
| 332 "application/font-sfnt", | |
| 333 "application/font-ttf"}; | |
| 334 | |
| 335 if (mime_type.empty()) { | |
| 336 return fallback; | |
| 337 } else if (mime_util::IsSupportedImageMimeType(mime_type)) { | |
| 300 return content::RESOURCE_TYPE_IMAGE; | 338 return content::RESOURCE_TYPE_IMAGE; |
| 301 else if (mime_util::IsSupportedJavascriptMimeType(mime_type)) | 339 } else if (mime_util::IsSupportedJavascriptMimeType(mime_type)) { |
| 302 return content::RESOURCE_TYPE_SCRIPT; | 340 return content::RESOURCE_TYPE_SCRIPT; |
| 303 else if (net::MatchesMimeType("text/css", mime_type)) | 341 } else if (net::MatchesMimeType("text/css", mime_type)) { |
| 304 return content::RESOURCE_TYPE_STYLESHEET; | 342 return content::RESOURCE_TYPE_STYLESHEET; |
| 305 else | 343 } else if (std::any_of(font_mime_types.begin(), font_mime_types.end(), |
| 306 return fallback; | 344 [&mime_type](const std::string& mime) { |
| 345 return net::MatchesMimeType(mime, mime_type); | |
| 346 })) { | |
|
pasko
2016/07/28 18:42:57
is it the way git cl format prefers this?
Benoit L
2016/07/29 08:56:27
Yes.
| |
| 347 return content::RESOURCE_TYPE_FONT_RESOURCE; | |
| 348 } | |
| 349 return fallback; | |
| 307 } | 350 } |
| 308 | 351 |
| 309 //////////////////////////////////////////////////////////////////////////////// | 352 //////////////////////////////////////////////////////////////////////////////// |
| 310 // ResourcePrefetchPredictor structs. | 353 // ResourcePrefetchPredictor structs. |
| 311 | 354 |
| 312 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() | 355 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() |
| 313 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), | 356 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), |
| 314 was_cached(false) { | 357 was_cached(false) { |
| 315 } | 358 } |
| 316 | 359 |
| (...skipping 1018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1335 // HistoryService is already loaded. Continue with Initialization. | 1378 // HistoryService is already loaded. Continue with Initialization. |
| 1336 OnHistoryAndCacheLoaded(); | 1379 OnHistoryAndCacheLoaded(); |
| 1337 return; | 1380 return; |
| 1338 } | 1381 } |
| 1339 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1382 DCHECK(!history_service_observer_.IsObserving(history_service)); |
| 1340 history_service_observer_.Add(history_service); | 1383 history_service_observer_.Add(history_service); |
| 1341 return; | 1384 return; |
| 1342 } | 1385 } |
| 1343 | 1386 |
| 1344 } // namespace predictors | 1387 } // namespace predictors |
| OLD | NEW |