| Index: content/browser/loader/resource_loader.cc
|
| diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
|
| index bb77021ac8fa20c3d369154da1b6f0adcd0df945..fd20fbc45e0f898be983462cda4f100ee023ba5c 100644
|
| --- a/content/browser/loader/resource_loader.cc
|
| +++ b/content/browser/loader/resource_loader.cc
|
| @@ -9,6 +9,7 @@
|
| #include "base/callback_helpers.h"
|
| #include "base/command_line.h"
|
| #include "base/location.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/profiler/scoped_tracker.h"
|
| #include "base/single_thread_task_runner.h"
|
| @@ -17,6 +18,7 @@
|
| #include "content/browser/appcache/appcache_interceptor.h"
|
| #include "content/browser/child_process_security_policy_impl.h"
|
| #include "content/browser/loader/detachable_resource_handler.h"
|
| +#include "content/browser/loader/resource_controller.h"
|
| #include "content/browser/loader/resource_handler.h"
|
| #include "content/browser/loader/resource_loader_delegate.h"
|
| #include "content/browser/loader/resource_request_info_impl.h"
|
| @@ -130,6 +132,76 @@ void PopulateResourceResponse(ResourceRequestInfoImpl* info,
|
|
|
| } // namespace
|
|
|
| +class ResourceLoader::Controller : public ResourceController {
|
| + public:
|
| + explicit Controller(ResourceLoader* resource_loader)
|
| + : resource_loader_(resource_loader){};
|
| +
|
| + ~Controller() override {}
|
| +
|
| + // ResourceController implementation:
|
| + void Resume() override {
|
| + DCHECK(!done_);
|
| + done_ = true;
|
| + resource_loader_->Resume(true);
|
| + }
|
| +
|
| + void Cancel() override {
|
| + DCHECK(!done_);
|
| + done_ = true;
|
| + resource_loader_->Cancel();
|
| + }
|
| +
|
| + void CancelAndIgnore() override {
|
| + DCHECK(!done_);
|
| + done_ = true;
|
| + resource_loader_->CancelAndIgnore();
|
| + }
|
| +
|
| + void CancelWithError(int error_code) override {
|
| + DCHECK(!done_);
|
| + done_ = true;
|
| + resource_loader_->CancelWithError(error_code);
|
| + }
|
| +
|
| + private:
|
| + ResourceLoader* const resource_loader_;
|
| +
|
| + // Set to true once one of the ResourceContoller methods has been invoked.
|
| + bool done_ = false;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Controller);
|
| +};
|
| +
|
| +// Helper class. Sets the stage of a ResourceLoader to DEFERRED_SYNC on
|
| +// construction, and on destruction does one of the following:
|
| +// 1) If the ResourceLoader has a deferred stage of DEFERRED_NONE, sets the
|
| +// ResourceLoader's stage to the stage specified on construction and resumes it.
|
| +// 2) If the ResourceLoader still has a deferred stage of DEFERRED_SYNC, sets
|
| +// the ResourceLoader's stage to the stage specified on construction. The
|
| +// ResourceLoader will be resumed at some point in the future.
|
| +class ResourceLoader::ScopedDeferral {
|
| + public:
|
| + ScopedDeferral(ResourceLoader* resource_loader,
|
| + ResourceLoader::DeferredStage deferred_stage)
|
| + : resource_loader_(resource_loader), deferred_stage_(deferred_stage) {
|
| + resource_loader_->deferred_stage_ = DEFERRED_SYNC;
|
| + }
|
| +
|
| + ~ScopedDeferral() {
|
| + DeferredStage old_deferred_stage = resource_loader_->deferred_stage_;
|
| + resource_loader_->deferred_stage_ = deferred_stage_;
|
| + if (old_deferred_stage == DEFERRED_NONE)
|
| + resource_loader_->Resume(false);
|
| + }
|
| +
|
| + private:
|
| + ResourceLoader* const resource_loader_;
|
| + const DeferredStage deferred_stage_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ScopedDeferral);
|
| +};
|
| +
|
| ResourceLoader::ResourceLoader(std::unique_ptr<net::URLRequest> request,
|
| std::unique_ptr<ResourceHandler> handler,
|
| ResourceLoaderDelegate* delegate)
|
| @@ -143,7 +215,7 @@ ResourceLoader::ResourceLoader(std::unique_ptr<net::URLRequest> request,
|
| times_cancelled_after_request_start_(0),
|
| weak_ptr_factory_(this) {
|
| request_->set_delegate(this);
|
| - handler_->SetController(this);
|
| + handler_->SetDelegate(this);
|
| }
|
|
|
| ResourceLoader::~ResourceLoader() {
|
| @@ -162,20 +234,8 @@ void ResourceLoader::StartRequest() {
|
| return;
|
| }
|
|
|
| - // Give the handler a chance to delay the URLRequest from being started.
|
| - bool defer_start = false;
|
| - if (!handler_->OnWillStart(request_->url(), &defer_start)) {
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::StartRequest", this,
|
| - TRACE_EVENT_FLAG_FLOW_OUT);
|
| - if (defer_start) {
|
| - deferred_stage_ = DEFERRED_START;
|
| - } else {
|
| - StartRequestInternal();
|
| - }
|
| + ScopedDeferral scoped_deferral(this, DEFERRED_START);
|
| + handler_->OnWillStart(request_->url(), base::MakeUnique<Controller>(this));
|
| }
|
|
|
| void ResourceLoader::CancelRequest(bool from_renderer) {
|
| @@ -244,6 +304,10 @@ void ResourceLoader::ClearLoginDelegate() {
|
| login_delegate_ = NULL;
|
| }
|
|
|
| +void ResourceLoader::OutOfBandCancel(int error_code, bool tell_renderer) {
|
| + CancelRequestInternal(error_code, !tell_renderer);
|
| +}
|
| +
|
| void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
|
| const net::RedirectInfo& redirect_info,
|
| bool* defer) {
|
| @@ -282,11 +346,19 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
|
| scoped_refptr<ResourceResponse> response = new ResourceResponse();
|
| PopulateResourceResponse(info, request_.get(), response.get());
|
| delegate_->DidReceiveRedirect(this, redirect_info.new_url, response.get());
|
| - if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
|
| - Cancel();
|
| - } else if (*defer) {
|
| - deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
|
| +
|
| + // Can't used ScopedDeferral here, because on sync completion, need to set
|
| + // |defer| to false instead of calling back into the URLRequest.
|
| + deferred_stage_ = DEFERRED_SYNC;
|
| + handler_->OnRequestRedirected(redirect_info, response.get(),
|
| + base::MakeUnique<Controller>(this));
|
| + if (!is_deferred()) {
|
| + *defer = false;
|
| + return;
|
| }
|
| +
|
| + *defer = true;
|
| + deferred_stage_ = DEFERRED_REDIRECT;
|
| }
|
|
|
| void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
|
| @@ -349,14 +421,6 @@ void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
|
| }
|
|
|
| CompleteResponseStarted();
|
| -
|
| - // If the handler deferred the request, it will resume the request later. If
|
| - // the request was cancelled, the request will call back into |this| with a
|
| - // bogus read completed error.
|
| - if (is_deferred() || !request_->status().is_success())
|
| - return;
|
| -
|
| - ReadMore(false); // Read the first chunk.
|
| }
|
|
|
| void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
|
| @@ -373,25 +437,6 @@ void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
|
| }
|
|
|
| CompleteRead(bytes_read);
|
| -
|
| - // If the handler cancelled or deferred the request, do not continue
|
| - // processing the read. If canceled, either the request will call into |this|
|
| - // with a bogus read error, or, if the request was completed, a task posted
|
| - // from ResourceLoader::CancelREquestInternal will run OnResponseCompleted.
|
| - if (is_deferred() || !request_->status().is_success())
|
| - return;
|
| -
|
| - if (bytes_read > 0) {
|
| - ReadMore(true); // Read the next chunk.
|
| - } else {
|
| - // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
|
| -
|
| - // URLRequest reported an EOF. Call ResponseCompleted.
|
| - DCHECK_EQ(0, bytes_read);
|
| - ResponseCompleted();
|
| - }
|
| }
|
|
|
| void ResourceLoader::CancelSSLRequest(int error,
|
| @@ -437,7 +482,7 @@ void ResourceLoader::CancelCertificateSelection() {
|
| request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
|
| }
|
|
|
| -void ResourceLoader::Resume() {
|
| +void ResourceLoader::Resume(bool called_from_resource_controller) {
|
| DCHECK(!is_transferring_);
|
|
|
| DeferredStage stage = deferred_stage_;
|
| @@ -446,27 +491,44 @@ void ResourceLoader::Resume() {
|
| case DEFERRED_NONE:
|
| NOTREACHED();
|
| break;
|
| + case DEFERRED_SYNC:
|
| + DCHECK(called_from_resource_controller);
|
| + // Request will be resumed when the stack unwinds.
|
| + break;
|
| case DEFERRED_START:
|
| + // Starting requests completes asynchronously, so starting the request now
|
| StartRequestInternal();
|
| break;
|
| case DEFERRED_REDIRECT:
|
| request_->FollowDeferredRedirect();
|
| break;
|
| case DEFERRED_READ:
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| + if (!called_from_resource_controller) {
|
| + ReadMore(called_from_resource_controller);
|
| + } else {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| break;
|
| case DEFERRED_RESPONSE_COMPLETE:
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| + if (!called_from_resource_controller) {
|
| + ResponseCompleted();
|
| + } else {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| break;
|
| case DEFERRED_FINISH:
|
| - // Delay self-destruction since we don't know how we were reached.
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| + if (!called_from_resource_controller) {
|
| + CallDidFinishLoading();
|
| + } else {
|
| + // Delay self-destruction since we don't know how we were reached.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| break;
|
| }
|
| }
|
| @@ -545,16 +607,13 @@ void ResourceLoader::CompleteResponseStarted() {
|
| tracked_objects::ScopedTracker tracking_profile(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
|
|
|
| - bool defer = false;
|
| - if (!handler_->OnResponseStarted(response.get(), &defer)) {
|
| - Cancel();
|
| - } else if (defer) {
|
| - read_deferral_start_time_ = base::TimeTicks::Now();
|
| - deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
|
| - }
|
| + read_deferral_start_time_ = base::TimeTicks::Now();
|
| + ScopedDeferral scoped_deferral(this, DEFERRED_READ);
|
| + handler_->OnResponseStarted(response.get(),
|
| + base::MakeUnique<Controller>(this));
|
| }
|
|
|
| -void ResourceLoader::ReadMore(bool is_continuation) {
|
| +void ResourceLoader::ReadMore(bool called_from_resource_controller) {
|
| TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ReadMore", this,
|
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
|
| DCHECK(!is_deferred());
|
| @@ -585,7 +644,7 @@ void ResourceLoader::ReadMore(bool is_continuation) {
|
| if (result == net::ERR_IO_PENDING)
|
| return;
|
|
|
| - if (!is_continuation || result <= 0) {
|
| + if (!called_from_resource_controller || result <= 0) {
|
| OnReadCompleted(request_.get(), result);
|
| } else {
|
| // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
|
| @@ -623,18 +682,9 @@ void ResourceLoader::CompleteRead(int bytes_read) {
|
| tracked_objects::ScopedTracker tracking_profile(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
|
|
|
| - bool defer = false;
|
| - if (!handler_->OnReadCompleted(bytes_read, &defer)) {
|
| - Cancel();
|
| - } else if (defer) {
|
| - deferred_stage_ =
|
| - bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
|
| - }
|
| -
|
| - // Note: the request may still have been cancelled while OnReadCompleted
|
| - // returns true if OnReadCompleted caused request to get cancelled
|
| - // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
|
| - // instance.)
|
| + ScopedDeferral scoped_deferral(
|
| + this, bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE);
|
| + handler_->OnReadCompleted(bytes_read, base::MakeUnique<Controller>(this));
|
| }
|
|
|
| void ResourceLoader::ResponseCompleted() {
|
| @@ -644,22 +694,13 @@ void ResourceLoader::ResponseCompleted() {
|
| DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
|
| RecordHistograms();
|
|
|
| - bool defer = false;
|
| - {
|
| - // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
|
| + // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
|
| + tracked_objects::ScopedTracker tracking_profile(
|
| + FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
|
|
|
| - handler_->OnResponseCompleted(request_->status(), &defer);
|
| - }
|
| - if (defer) {
|
| - // The handler is not ready to die yet. We will call DidFinishLoading when
|
| - // we resume.
|
| - deferred_stage_ = DEFERRED_FINISH;
|
| - } else {
|
| - // This will result in our destruction.
|
| - CallDidFinishLoading();
|
| - }
|
| + ScopedDeferral scoped_deferral(this, DEFERRED_FINISH);
|
| + handler_->OnResponseCompleted(request_->status(),
|
| + base::MakeUnique<Controller>(this));
|
| }
|
|
|
| void ResourceLoader::CallDidFinishLoading() {
|
|
|