| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/browser/loader/resource_loader.h" | 5 #include "content/browser/loader/resource_loader.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 // as the ResourceHandler may want to inspect the URLRequest and other state. | 156 // as the ResourceHandler may want to inspect the URLRequest and other state. |
| 157 handler_.reset(); | 157 handler_.reset(); |
| 158 } | 158 } |
| 159 | 159 |
| 160 void ResourceLoader::StartRequest() { | 160 void ResourceLoader::StartRequest() { |
| 161 if (delegate_->HandleExternalProtocol(this, request_->url())) { | 161 if (delegate_->HandleExternalProtocol(this, request_->url())) { |
| 162 CancelAndIgnore(); | 162 CancelAndIgnore(); |
| 163 return; | 163 return; |
| 164 } | 164 } |
| 165 | 165 |
| 166 // Give the handler a chance to delay the URLRequest from being started. | |
| 167 bool defer_start = false; | |
| 168 if (!handler_->OnWillStart(request_->url(), &defer_start)) { | |
| 169 Cancel(); | |
| 170 return; | |
| 171 } | |
| 172 | |
| 173 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::StartRequest", this, | 166 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::StartRequest", this, |
| 174 TRACE_EVENT_FLAG_FLOW_OUT); | 167 TRACE_EVENT_FLAG_FLOW_OUT); |
| 175 if (defer_start) { | 168 |
| 169 // Give the handler a chance to delay the URLRequest from being started. |
| 170 bool defer_or_cancel = false; |
| 171 handler_->OnWillStart(request_->url(), &defer_or_cancel); |
| 172 if (defer_or_cancel) { |
| 176 deferred_stage_ = DEFERRED_START; | 173 deferred_stage_ = DEFERRED_START; |
| 177 } else { | 174 } else { |
| 178 StartRequestInternal(); | 175 StartRequestInternal(); |
| 179 } | 176 } |
| 180 } | 177 } |
| 181 | 178 |
| 182 void ResourceLoader::CancelRequest(bool from_renderer) { | 179 void ResourceLoader::CancelRequest(bool from_renderer) { |
| 183 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelRequest", this, | 180 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelRequest", this, |
| 184 TRACE_EVENT_FLAG_FLOW_IN); | 181 TRACE_EVENT_FLAG_FLOW_IN); |
| 185 CancelRequestInternal(net::ERR_ABORTED, from_renderer); | 182 CancelRequestInternal(net::ERR_ABORTED, from_renderer, false); |
| 186 } | |
| 187 | |
| 188 void ResourceLoader::CancelAndIgnore() { | |
| 189 ResourceRequestInfoImpl* info = GetRequestInfo(); | |
| 190 info->set_was_ignored_by_handler(true); | |
| 191 CancelRequest(false); | |
| 192 } | |
| 193 | |
| 194 void ResourceLoader::CancelWithError(int error_code) { | |
| 195 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelWithError", this, | |
| 196 TRACE_EVENT_FLAG_FLOW_IN); | |
| 197 CancelRequestInternal(error_code, false); | |
| 198 } | 183 } |
| 199 | 184 |
| 200 void ResourceLoader::MarkAsTransferring( | 185 void ResourceLoader::MarkAsTransferring( |
| 201 const base::Closure& on_transfer_complete_callback) { | 186 const base::Closure& on_transfer_complete_callback) { |
| 202 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType())) | 187 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType())) |
| 203 << "Can only transfer for navigations"; | 188 << "Can only transfer for navigations"; |
| 204 is_transferring_ = true; | 189 is_transferring_ = true; |
| 205 on_transfer_complete_callback_ = on_transfer_complete_callback; | 190 on_transfer_complete_callback_ = on_transfer_complete_callback; |
| 206 | 191 |
| 207 int child_id = GetRequestInfo()->GetChildID(); | 192 int child_id = GetRequestInfo()->GetChildID(); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 | 261 |
| 277 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) { | 262 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) { |
| 278 // The request is complete so we can remove it. | 263 // The request is complete so we can remove it. |
| 279 CancelAndIgnore(); | 264 CancelAndIgnore(); |
| 280 return; | 265 return; |
| 281 } | 266 } |
| 282 | 267 |
| 283 scoped_refptr<ResourceResponse> response = new ResourceResponse(); | 268 scoped_refptr<ResourceResponse> response = new ResourceResponse(); |
| 284 PopulateResourceResponse(info, request_.get(), response.get()); | 269 PopulateResourceResponse(info, request_.get(), response.get()); |
| 285 delegate_->DidReceiveRedirect(this, redirect_info.new_url, response.get()); | 270 delegate_->DidReceiveRedirect(this, redirect_info.new_url, response.get()); |
| 286 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) { | 271 |
| 287 Cancel(); | 272 // Cancellations are treated much like defers, so ignore the difference. |
| 288 } else if (*defer) { | 273 handler_->OnRequestRedirected(redirect_info, response.get(), defer); |
| 274 if (*defer) |
| 289 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed. | 275 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed. |
| 290 } | |
| 291 } | 276 } |
| 292 | 277 |
| 293 void ResourceLoader::OnAuthRequired(net::URLRequest* unused, | 278 void ResourceLoader::OnAuthRequired(net::URLRequest* unused, |
| 294 net::AuthChallengeInfo* auth_info) { | 279 net::AuthChallengeInfo* auth_info) { |
| 295 DCHECK_EQ(request_.get(), unused); | 280 DCHECK_EQ(request_.get(), unused); |
| 296 | 281 |
| 297 ResourceRequestInfoImpl* info = GetRequestInfo(); | 282 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 298 if (info->do_not_prompt_for_login()) { | 283 if (info->do_not_prompt_for_login()) { |
| 299 request_->CancelAuth(); | 284 request_->CancelAuth(); |
| 300 return; | 285 return; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 case DEFERRED_FINISH: | 454 case DEFERRED_FINISH: |
| 470 // Delay self-destruction since we don't know how we were reached. | 455 // Delay self-destruction since we don't know how we were reached. |
| 471 base::ThreadTaskRunnerHandle::Get()->PostTask( | 456 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 472 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading, | 457 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading, |
| 473 weak_ptr_factory_.GetWeakPtr())); | 458 weak_ptr_factory_.GetWeakPtr())); |
| 474 break; | 459 break; |
| 475 } | 460 } |
| 476 } | 461 } |
| 477 | 462 |
| 478 void ResourceLoader::Cancel() { | 463 void ResourceLoader::Cancel() { |
| 479 CancelRequest(false); | 464 CancelWithError(net::ERR_ABORTED); |
| 465 } |
| 466 |
| 467 void ResourceLoader::CancelAndIgnore() { |
| 468 CancelRequestInternal(net::ERR_ABORTED, false, true); |
| 469 } |
| 470 |
| 471 void ResourceLoader::CancelWithError(int error_code) { |
| 472 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelWithError", this, |
| 473 TRACE_EVENT_FLAG_FLOW_IN); |
| 474 CancelRequestInternal(error_code, false, false); |
| 480 } | 475 } |
| 481 | 476 |
| 482 void ResourceLoader::StartRequestInternal() { | 477 void ResourceLoader::StartRequestInternal() { |
| 483 DCHECK(!request_->is_pending()); | 478 DCHECK(!request_->is_pending()); |
| 484 | 479 |
| 485 if (!request_->status().is_success()) { | 480 if (!request_->status().is_success()) { |
| 486 return; | 481 return; |
| 487 } | 482 } |
| 488 | 483 |
| 489 started_request_ = true; | 484 started_request_ = true; |
| 490 request_->Start(); | 485 request_->Start(); |
| 491 | 486 |
| 492 delegate_->DidStartRequest(this); | 487 delegate_->DidStartRequest(this); |
| 493 } | 488 } |
| 494 | 489 |
| 495 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) { | 490 void ResourceLoader::CancelRequestInternal(int error, |
| 491 bool from_renderer, |
| 492 bool ignore) { |
| 496 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec(); | 493 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec(); |
| 497 | 494 |
| 498 ResourceRequestInfoImpl* info = GetRequestInfo(); | 495 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 496 if (ignore) |
| 497 info->set_was_ignored_by_handler(true); |
| 499 | 498 |
| 500 // WebKit will send us a cancel for downloads since it no longer handles | 499 // WebKit will send us a cancel for downloads since it no longer handles |
| 501 // them. In this case, ignore the cancel since we handle downloads in the | 500 // them. In this case, ignore the cancel since we handle downloads in the |
| 502 // browser. | 501 // browser. |
| 503 if (from_renderer && (info->IsDownload() || info->is_stream())) | 502 if (from_renderer && (info->IsDownload() || info->is_stream())) |
| 504 return; | 503 return; |
| 505 | 504 |
| 506 if (from_renderer && info->detachable_handler()) { | 505 if (from_renderer && info->detachable_handler()) { |
| 507 // TODO(davidben): Fix Blink handling of prefetches so they are not | 506 // TODO(davidben): Fix Blink handling of prefetches so they are not |
| 508 // cancelled on navigate away and end up in the local cache. | 507 // cancelled on navigate away and end up in the local cache. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 ResourceRequestInfoImpl* info = GetRequestInfo(); | 541 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 543 scoped_refptr<ResourceResponse> response = new ResourceResponse(); | 542 scoped_refptr<ResourceResponse> response = new ResourceResponse(); |
| 544 PopulateResourceResponse(info, request_.get(), response.get()); | 543 PopulateResourceResponse(info, request_.get(), response.get()); |
| 545 | 544 |
| 546 delegate_->DidReceiveResponse(this); | 545 delegate_->DidReceiveResponse(this); |
| 547 | 546 |
| 548 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. | 547 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. |
| 549 tracked_objects::ScopedTracker tracking_profile( | 548 tracked_objects::ScopedTracker tracking_profile( |
| 550 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()")); | 549 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()")); |
| 551 | 550 |
| 552 bool defer = false; | 551 bool defer_or_cancel = false; |
| 553 if (!handler_->OnResponseStarted(response.get(), &defer)) { | 552 handler_->OnResponseStarted(response.get(), &defer_or_cancel); |
| 554 Cancel(); | 553 if (defer_or_cancel) { |
| 555 } else if (defer) { | |
| 556 read_deferral_start_time_ = base::TimeTicks::Now(); | 554 read_deferral_start_time_ = base::TimeTicks::Now(); |
| 557 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed. | 555 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed. |
| 558 } | 556 } |
| 559 } | 557 } |
| 560 | 558 |
| 561 void ResourceLoader::StartReading(bool is_continuation) { | 559 void ResourceLoader::StartReading(bool is_continuation) { |
| 560 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::StartReading", this, |
| 561 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| 562 DCHECK(!is_deferred()); |
| 562 int bytes_read = 0; | 563 int bytes_read = 0; |
| 563 ReadMore(&bytes_read); | 564 |
| 565 // Make sure we track the buffer in at least one place. This ensures it gets |
| 566 // deleted even in the case the request has already finished its job and |
| 567 // doesn't use the buffer. |
| 568 scoped_refptr<net::IOBuffer> buf; |
| 569 int buf_size; |
| 570 { |
| 571 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. |
| 572 tracked_objects::ScopedTracker tracking_profile2( |
| 573 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()")); |
| 574 |
| 575 if (!handler_->OnWillRead(&buf, &buf_size, -1)) { |
| 576 Cancel(); |
| 577 return; |
| 578 } |
| 579 } |
| 580 |
| 581 DCHECK(buf.get()); |
| 582 DCHECK(buf_size > 0); |
| 583 |
| 584 // No need to check the return value here. Instead, detect errors below by |
| 585 // inspecting the URLRequest's status. |
| 586 request_->Read(buf.get(), buf_size, &bytes_read); |
| 564 | 587 |
| 565 // If IO is pending, wait for the URLRequest to call OnReadCompleted. | 588 // If IO is pending, wait for the URLRequest to call OnReadCompleted. |
| 566 if (request_->status().is_io_pending()) | 589 if (request_->status().is_io_pending()) |
| 567 return; | 590 return; |
| 568 | 591 |
| 569 if (!is_continuation || bytes_read <= 0) { | 592 if (!is_continuation || bytes_read <= 0) { |
| 570 OnReadCompleted(request_.get(), bytes_read); | 593 OnReadCompleted(request_.get(), bytes_read); |
| 571 } else { | 594 } else { |
| 572 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO | 595 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO |
| 573 // thread in case the URLRequest can provide data synchronously. | 596 // thread in case the URLRequest can provide data synchronously. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 586 base::TimeTicks::Now() - read_deferral_start_time_); | 609 base::TimeTicks::Now() - read_deferral_start_time_); |
| 587 read_deferral_start_time_ = base::TimeTicks(); | 610 read_deferral_start_time_ = base::TimeTicks(); |
| 588 } | 611 } |
| 589 if (request_->status().is_success()) { | 612 if (request_->status().is_success()) { |
| 590 StartReading(false); // Read the next chunk (OK to complete synchronously). | 613 StartReading(false); // Read the next chunk (OK to complete synchronously). |
| 591 } else { | 614 } else { |
| 592 ResponseCompleted(); | 615 ResponseCompleted(); |
| 593 } | 616 } |
| 594 } | 617 } |
| 595 | 618 |
| 596 void ResourceLoader::ReadMore(int* bytes_read) { | |
| 597 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ReadMore", this, | |
| 598 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); | |
| 599 DCHECK(!is_deferred()); | |
| 600 | |
| 601 // Make sure we track the buffer in at least one place. This ensures it gets | |
| 602 // deleted even in the case the request has already finished its job and | |
| 603 // doesn't use the buffer. | |
| 604 scoped_refptr<net::IOBuffer> buf; | |
| 605 int buf_size; | |
| 606 { | |
| 607 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. | |
| 608 tracked_objects::ScopedTracker tracking_profile2( | |
| 609 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()")); | |
| 610 | |
| 611 if (!handler_->OnWillRead(&buf, &buf_size, -1)) { | |
| 612 Cancel(); | |
| 613 return; | |
| 614 } | |
| 615 } | |
| 616 | |
| 617 DCHECK(buf.get()); | |
| 618 DCHECK(buf_size > 0); | |
| 619 | |
| 620 request_->Read(buf.get(), buf_size, bytes_read); | |
| 621 | |
| 622 // No need to check the return value here as we'll detect errors by | |
| 623 // inspecting the URLRequest's status. | |
| 624 } | |
| 625 | |
| 626 void ResourceLoader::CompleteRead(int bytes_read) { | 619 void ResourceLoader::CompleteRead(int bytes_read) { |
| 627 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CompleteRead", this, | 620 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CompleteRead", this, |
| 628 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); | 621 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| 629 | 622 |
| 630 DCHECK(bytes_read >= 0); | 623 DCHECK(bytes_read >= 0); |
| 631 DCHECK(request_->status().is_success()); | 624 DCHECK(request_->status().is_success()); |
| 632 | 625 |
| 633 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. | 626 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. |
| 634 tracked_objects::ScopedTracker tracking_profile( | 627 tracked_objects::ScopedTracker tracking_profile( |
| 635 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()")); | 628 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()")); |
| 636 | 629 |
| 637 bool defer = false; | 630 bool defer_or_cancel = false; |
| 638 if (!handler_->OnReadCompleted(bytes_read, &defer)) { | 631 handler_->OnReadCompleted(bytes_read, &defer_or_cancel); |
| 639 Cancel(); | 632 if (defer_or_cancel) { |
| 640 } else if (defer) { | |
| 641 deferred_stage_ = | 633 deferred_stage_ = |
| 642 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE; | 634 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE; |
| 643 } | 635 } |
| 644 | 636 |
| 645 // Note: the request may still have been cancelled while OnReadCompleted | 637 // Note: the request may still have been cancelled while OnReadCompleted |
| 646 // returns true if OnReadCompleted caused request to get cancelled | 638 // returns true if OnReadCompleted caused request to get cancelled |
| 647 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for | 639 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for |
| 648 // instance.) | 640 // instance.) |
| 649 } | 641 } |
| 650 | 642 |
| 651 void ResourceLoader::ResponseCompleted() { | 643 void ResourceLoader::ResponseCompleted() { |
| 652 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ResponseCompleted", this, | 644 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ResponseCompleted", this, |
| 653 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); | 645 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| 654 | 646 |
| 655 DVLOG(1) << "ResponseCompleted: " << request_->url().spec(); | 647 DVLOG(1) << "ResponseCompleted: " << request_->url().spec(); |
| 656 RecordHistograms(); | 648 RecordHistograms(); |
| 657 | 649 |
| 658 bool defer = false; | 650 bool defer = false; |
| 659 { | 651 { |
| 660 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. | 652 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed. |
| 661 tracked_objects::ScopedTracker tracking_profile( | 653 tracked_objects::ScopedTracker tracking_profile( |
| 662 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()")); | 654 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()")); |
| 663 | 655 |
| 664 handler_->OnResponseCompleted(request_->status(), &defer); | 656 handler_->OnResponseCompleted(request_->status(), &defer); |
| 665 } | 657 } |
| 666 if (defer) { | 658 if (defer) { |
| 667 // The handler is not ready to die yet. We will call DidFinishLoading when | 659 // The handler is not ready to die yet. DidFinishLoading will be called on |
| 668 // we resume. | 660 // resume. |
| 669 deferred_stage_ = DEFERRED_FINISH; | 661 deferred_stage_ = DEFERRED_FINISH; |
| 670 } else { | 662 } else { |
| 671 // This will result in our destruction. | 663 // This will result in destroying |this|. |
| 672 CallDidFinishLoading(); | 664 CallDidFinishLoading(); |
| 673 } | 665 } |
| 674 } | 666 } |
| 675 | 667 |
| 676 void ResourceLoader::CallDidFinishLoading() { | 668 void ResourceLoader::CallDidFinishLoading() { |
| 677 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CallDidFinishLoading", | 669 TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CallDidFinishLoading", |
| 678 this, TRACE_EVENT_FLAG_FLOW_IN); | 670 this, TRACE_EVENT_FLAG_FLOW_IN); |
| 679 delegate_->DidFinishLoading(this); | 671 delegate_->DidFinishLoading(this); |
| 680 } | 672 } |
| 681 | 673 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 } | 713 } |
| 722 | 714 |
| 723 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX); | 715 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX); |
| 724 } else if (request_->response_info().unused_since_prefetch) { | 716 } else if (request_->response_info().unused_since_prefetch) { |
| 725 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time(); | 717 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time(); |
| 726 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentOnPrefetchHit", total_time); | 718 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentOnPrefetchHit", total_time); |
| 727 } | 719 } |
| 728 } | 720 } |
| 729 | 721 |
| 730 } // namespace content | 722 } // namespace content |
| OLD | NEW |