Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 <string> | 5 #include <string> |
| 6 | 6 |
| 7 #include "chrome/browser/predictors/loading_data_collector.h" | 7 #include "chrome/browser/predictors/loading_data_collector.h" |
| 8 #include "chrome/browser/predictors/loading_stats_collector.h" | |
| 8 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
| 10 #include "components/history/core/browser/history_service.h" | |
| 9 #include "components/mime_util/mime_util.h" | 11 #include "components/mime_util/mime_util.h" |
| 10 #include "content/public/browser/resource_request_info.h" | 12 #include "content/public/browser/resource_request_info.h" |
| 11 #include "content/public/common/resource_type.h" | 13 #include "content/public/common/resource_type.h" |
| 12 #include "net/url_request/url_request.h" | 14 #include "net/url_request/url_request.h" |
| 13 | 15 |
| 16 using content::BrowserThread; | |
| 17 | |
| 14 namespace predictors { | 18 namespace predictors { |
| 15 | 19 |
| 16 namespace { | 20 namespace { |
| 17 | 21 |
| 22 using PageRequestSummary = | |
| 23 predictors::ResourcePrefetchPredictor::PageRequestSummary; | |
|
trevordixon
2017/06/14 08:04:34
Might make sense to move PageRequestSummary into l
alexilin
2017/06/14 11:41:54
I'd suggest you to move all of OriginRequestSummar
trevordixon
2017/06/16 05:11:28
Done.
| |
| 24 | |
| 18 bool g_allow_port_in_urls = false; | 25 bool g_allow_port_in_urls = false; |
| 19 | 26 |
| 27 void UpdateOrAddToOrigins( | |
| 28 std::map<GURL, ResourcePrefetchPredictor::OriginRequestSummary>* summaries, | |
| 29 const ResourcePrefetchPredictor::URLRequestSummary& request_summary) { | |
| 30 const GURL& request_url = request_summary.request_url; | |
| 31 DCHECK(request_url.is_valid()); | |
| 32 if (!request_url.is_valid()) | |
| 33 return; | |
| 34 | |
| 35 GURL origin = request_url.GetOrigin(); | |
| 36 auto it = summaries->find(origin); | |
| 37 if (it == summaries->end()) { | |
| 38 ResourcePrefetchPredictor::OriginRequestSummary summary; | |
| 39 summary.origin = origin; | |
| 40 summary.first_occurrence = summaries->size(); | |
| 41 it = summaries->insert({origin, summary}).first; | |
| 42 } | |
| 43 | |
| 44 it->second.always_access_network |= | |
| 45 request_summary.always_revalidate || request_summary.is_no_store; | |
| 46 it->second.accessed_network |= request_summary.network_accessed; | |
| 47 } | |
| 48 | |
| 20 } // namespace | 49 } // namespace |
| 21 | 50 |
| 22 // static | 51 // static |
| 23 bool LoadingDataCollector::ShouldRecordRequest( | 52 bool LoadingDataCollector::ShouldRecordRequest( |
| 24 net::URLRequest* request, | 53 net::URLRequest* request, |
| 25 content::ResourceType resource_type) { | 54 content::ResourceType resource_type) { |
| 26 const content::ResourceRequestInfo* request_info = | 55 const content::ResourceRequestInfo* request_info = |
| 27 content::ResourceRequestInfo::ForRequest(request); | 56 content::ResourceRequestInfo::ForRequest(request); |
| 28 if (!request_info) | 57 if (!request_info) |
| 29 return false; | 58 return false; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 actual_resource_type == content::RESOURCE_TYPE_SCRIPT || | 132 actual_resource_type == content::RESOURCE_TYPE_SCRIPT || |
| 104 actual_resource_type == content::RESOURCE_TYPE_IMAGE || | 133 actual_resource_type == content::RESOURCE_TYPE_IMAGE || |
| 105 actual_resource_type == content::RESOURCE_TYPE_FONT_RESOURCE; | 134 actual_resource_type == content::RESOURCE_TYPE_FONT_RESOURCE; |
| 106 } | 135 } |
| 107 | 136 |
| 108 // static | 137 // static |
| 109 void LoadingDataCollector::SetAllowPortInUrlsForTesting(bool state) { | 138 void LoadingDataCollector::SetAllowPortInUrlsForTesting(bool state) { |
| 110 g_allow_port_in_urls = state; | 139 g_allow_port_in_urls = state; |
| 111 } | 140 } |
| 112 | 141 |
| 113 LoadingDataCollector::LoadingDataCollector(ResourcePrefetchPredictor* predictor) | 142 LoadingDataCollector::LoadingDataCollector( |
| 114 : predictor_(predictor) {} | 143 ResourcePrefetchPredictor* predictor, |
| 144 predictors::LoadingStatsCollector* stats_collector, | |
| 145 const LoadingPredictorConfig& config) | |
| 146 : predictor_(predictor), | |
| 147 stats_collector_(stats_collector), | |
| 148 config_(config) {} | |
| 115 | 149 |
| 116 LoadingDataCollector::~LoadingDataCollector() {} | 150 LoadingDataCollector::~LoadingDataCollector() {} |
| 117 | 151 |
| 118 void LoadingDataCollector::RecordURLRequest( | 152 void LoadingDataCollector::RecordURLRequest( |
| 119 const ResourcePrefetchPredictor::URLRequestSummary& request) { | 153 const ResourcePrefetchPredictor::URLRequestSummary& request) { |
| 120 predictor_->RecordURLRequest(request); | 154 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 155 if (predictor_->initialization_state() != | |
| 156 ResourcePrefetchPredictor::INITIALIZED) | |
|
trevordixon
2017/06/14 08:04:34
I copied all of the initialization_state checks ov
alexilin
2017/06/14 11:41:54
Yeah, initialization is only needed for ResourcePr
trevordixon
2017/06/16 05:11:28
Done.
| |
| 157 return; | |
| 158 | |
| 159 CHECK_EQ(request.resource_type, content::RESOURCE_TYPE_MAIN_FRAME); | |
| 160 OnMainFrameRequest(request); | |
| 121 } | 161 } |
| 122 | 162 |
| 123 void LoadingDataCollector::RecordURLResponse( | 163 void LoadingDataCollector::RecordURLResponse( |
| 124 const ResourcePrefetchPredictor::URLRequestSummary& response) { | 164 const ResourcePrefetchPredictor::URLRequestSummary& response) { |
| 125 predictor_->RecordURLResponse(response); | 165 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 166 if (predictor_->initialization_state() != | |
| 167 ResourcePrefetchPredictor::INITIALIZED) | |
| 168 return; | |
| 169 | |
| 170 if (response.resource_type != content::RESOURCE_TYPE_MAIN_FRAME) | |
| 171 OnSubresourceResponse(response); | |
| 126 } | 172 } |
| 127 | 173 |
| 128 void LoadingDataCollector::RecordURLRedirect( | 174 void LoadingDataCollector::RecordURLRedirect( |
| 129 const ResourcePrefetchPredictor::URLRequestSummary& response) { | 175 const ResourcePrefetchPredictor::URLRequestSummary& response) { |
| 130 predictor_->RecordURLRedirect(response); | 176 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 177 if (predictor_->initialization_state() != | |
| 178 ResourcePrefetchPredictor::INITIALIZED) | |
| 179 return; | |
| 180 | |
| 181 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) | |
| 182 OnMainFrameRedirect(response); | |
| 183 else | |
| 184 OnSubresourceRedirect(response); | |
| 131 } | 185 } |
| 132 | 186 |
| 133 void LoadingDataCollector::RecordMainFrameLoadComplete( | 187 void LoadingDataCollector::RecordMainFrameLoadComplete( |
| 134 const NavigationID& navigation_id) { | 188 const NavigationID& navigation_id) { |
| 135 predictor_->RecordMainFrameLoadComplete(navigation_id); | 189 switch (predictor_->initialization_state()) { |
| 190 case ResourcePrefetchPredictor::NOT_INITIALIZED: | |
| 191 predictor_->StartInitialization(); | |
| 192 break; | |
| 193 case ResourcePrefetchPredictor::INITIALIZING: | |
| 194 break; | |
| 195 case ResourcePrefetchPredictor::INITIALIZED: | |
| 196 // WebContents can return an empty URL if the navigation entry | |
| 197 // corresponding to the navigation has not been created yet. | |
| 198 if (!navigation_id.main_frame_url.is_empty()) | |
| 199 OnNavigationComplete(navigation_id); | |
| 200 break; | |
| 201 default: | |
| 202 NOTREACHED() << "Unexpected initialization_state_: " | |
| 203 << predictor_->initialization_state(); | |
| 204 } | |
| 136 } | 205 } |
| 137 | 206 |
| 138 void LoadingDataCollector::RecordFirstContentfulPaint( | 207 void LoadingDataCollector::RecordFirstContentfulPaint( |
| 139 const NavigationID& navigation_id, | 208 const NavigationID& navigation_id, |
| 140 const base::TimeTicks& first_contentful_paint) { | 209 const base::TimeTicks& first_contentful_paint) { |
| 141 predictor_->RecordFirstContentfulPaint(navigation_id, first_contentful_paint); | 210 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 211 if (predictor_->initialization_state() != | |
| 212 ResourcePrefetchPredictor::INITIALIZED) | |
| 213 return; | |
| 214 | |
| 215 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); | |
| 216 if (nav_it != inflight_navigations_.end()) | |
| 217 nav_it->second->first_contentful_paint = first_contentful_paint; | |
| 218 } | |
| 219 | |
| 220 void LoadingDataCollector::OnMainFrameRequest( | |
| 221 const ResourcePrefetchPredictor::URLRequestSummary& request) { | |
| 222 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 223 DCHECK_EQ(ResourcePrefetchPredictor::INITIALIZED, | |
| 224 predictor_->initialization_state()); | |
| 225 | |
| 226 CleanupAbandonedNavigations(request.navigation_id); | |
| 227 | |
| 228 // New empty navigation entry. | |
| 229 const GURL& main_frame_url = request.navigation_id.main_frame_url; | |
| 230 inflight_navigations_.emplace( | |
| 231 request.navigation_id, | |
| 232 base::MakeUnique<PageRequestSummary>(main_frame_url)); | |
| 233 } | |
| 234 | |
| 235 void LoadingDataCollector::OnMainFrameRedirect( | |
| 236 const ResourcePrefetchPredictor::URLRequestSummary& response) { | |
| 237 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 238 DCHECK_EQ(ResourcePrefetchPredictor::INITIALIZED, | |
| 239 predictor_->initialization_state()); | |
| 240 | |
| 241 const GURL& main_frame_url = response.navigation_id.main_frame_url; | |
| 242 std::unique_ptr<PageRequestSummary> summary; | |
| 243 NavigationMap::iterator nav_it = | |
| 244 inflight_navigations_.find(response.navigation_id); | |
| 245 if (nav_it != inflight_navigations_.end()) { | |
| 246 summary = std::move(nav_it->second); | |
| 247 inflight_navigations_.erase(nav_it); | |
| 248 } | |
| 249 | |
| 250 // The redirect url may be empty if the URL was invalid. | |
| 251 if (response.redirect_url.is_empty()) | |
| 252 return; | |
| 253 | |
| 254 // If we lost the information about the first hop for some reason. | |
| 255 if (!summary) { | |
| 256 summary = base::MakeUnique<PageRequestSummary>(main_frame_url); | |
| 257 } | |
| 258 | |
| 259 // A redirect will not lead to another OnMainFrameRequest call, so record the | |
| 260 // redirect url as a new navigation id and save the initial url. | |
| 261 NavigationID navigation_id(response.navigation_id); | |
| 262 navigation_id.main_frame_url = response.redirect_url; | |
| 263 summary->main_frame_url = response.redirect_url; | |
| 264 inflight_navigations_.emplace(navigation_id, std::move(summary)); | |
| 265 } | |
| 266 | |
| 267 void LoadingDataCollector::OnSubresourceResponse( | |
| 268 const ResourcePrefetchPredictor::URLRequestSummary& response) { | |
| 269 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 270 DCHECK_EQ(ResourcePrefetchPredictor::INITIALIZED, | |
| 271 predictor_->initialization_state()); | |
| 272 | |
| 273 NavigationMap::const_iterator nav_it = | |
| 274 inflight_navigations_.find(response.navigation_id); | |
| 275 if (nav_it == inflight_navigations_.end()) | |
| 276 return; | |
| 277 auto& page_request_summary = *nav_it->second; | |
| 278 | |
| 279 if (!response.is_no_store) | |
| 280 page_request_summary.subresource_requests.push_back(response); | |
| 281 | |
| 282 if (config_.is_origin_learning_enabled) | |
| 283 UpdateOrAddToOrigins(&page_request_summary.origins, response); | |
| 284 } | |
| 285 | |
| 286 void LoadingDataCollector::OnSubresourceRedirect( | |
| 287 const ResourcePrefetchPredictor::URLRequestSummary& response) { | |
| 288 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 289 DCHECK_EQ(ResourcePrefetchPredictor::INITIALIZED, | |
| 290 predictor_->initialization_state()); | |
| 291 | |
| 292 if (!config_.is_origin_learning_enabled) | |
| 293 return; | |
| 294 | |
| 295 NavigationMap::const_iterator nav_it = | |
| 296 inflight_navigations_.find(response.navigation_id); | |
| 297 if (nav_it == inflight_navigations_.end()) | |
| 298 return; | |
| 299 auto& page_request_summary = *nav_it->second; | |
| 300 UpdateOrAddToOrigins(&page_request_summary.origins, response); | |
| 301 } | |
| 302 | |
| 303 void LoadingDataCollector::OnNavigationComplete( | |
| 304 const NavigationID& nav_id_without_timing_info) { | |
| 305 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 306 DCHECK_EQ(ResourcePrefetchPredictor::INITIALIZED, | |
| 307 predictor_->initialization_state()); | |
| 308 | |
| 309 NavigationMap::iterator nav_it = | |
| 310 inflight_navigations_.find(nav_id_without_timing_info); | |
| 311 if (nav_it == inflight_navigations_.end()) | |
| 312 return; | |
| 313 | |
| 314 // Remove the navigation from the inflight navigations. | |
| 315 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second); | |
| 316 inflight_navigations_.erase(nav_it); | |
| 317 | |
| 318 // Set before_first_contentful paint for each resource. | |
| 319 for (auto& request_summary : summary->subresource_requests) { | |
| 320 request_summary.before_first_contentful_paint = | |
| 321 request_summary.response_time < summary->first_contentful_paint; | |
| 322 } | |
| 323 | |
| 324 if (stats_collector_) | |
| 325 stats_collector_->RecordPageRequestSummary(*summary); | |
| 326 | |
| 327 predictor_->HandlePageRequestSummary(std::move(summary)); | |
| 328 } | |
| 329 | |
| 330 void LoadingDataCollector::CleanupAbandonedNavigations( | |
| 331 const NavigationID& navigation_id) { | |
| 332 if (stats_collector_) | |
| 333 stats_collector_->CleanupAbandonedStats(); | |
| 334 | |
| 335 static const base::TimeDelta max_navigation_age = | |
| 336 base::TimeDelta::FromSeconds(config_.max_navigation_lifetime_seconds); | |
| 337 | |
| 338 base::TimeTicks time_now = base::TimeTicks::Now(); | |
| 339 for (NavigationMap::iterator it = inflight_navigations_.begin(); | |
| 340 it != inflight_navigations_.end();) { | |
| 341 if ((it->first.tab_id == navigation_id.tab_id) || | |
| 342 (time_now - it->first.creation_time > max_navigation_age)) { | |
| 343 inflight_navigations_.erase(it++); | |
| 344 } else { | |
| 345 ++it; | |
| 346 } | |
| 347 } | |
| 142 } | 348 } |
| 143 | 349 |
| 144 } // namespace predictors | 350 } // namespace predictors |
| OLD | NEW |