Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2230)

Unified Diff: content/browser/loader/resource_loader.cc

Issue 2526983002: Refactor ResourceHandler API. (Closed)
Patch Set: Silly merge Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/loader/resource_loader.cc
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 241727bad07cb3e69264224a4116031ba0ebb952..2415efd966835e3f7d9d695145a5b1461ed88da5 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 {}
Charlie Harrison 2017/01/25 20:23:00 Can we DCHECK(done_) here? I'm nervous about peopl
mmenke 2017/01/25 22:07:59 Unfortunately not, due to out-of-band cancels. :(
+
+ // 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
Charlie Harrison 2017/01/25 20:23:00 Can the ResourceLoader have deferred stage apart f
mmenke 2017/01/25 22:07:59 Good idea, done. Wonder if it would be cleaner to
+// 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() {
@@ -157,20 +229,11 @@ ResourceLoader::~ResourceLoader() {
}
void ResourceLoader::StartRequest() {
- // 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) {
@@ -239,6 +302,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) {
@@ -271,17 +338,22 @@ 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.
- DCHECK(deferred_redirect_url_.is_empty());
- deferred_redirect_url_ = redirect_info.new_url;
- } else if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
- // The request is complete so we can remove it.
- CancelAndIgnore();
+
+ // 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()) {
Charlie Harrison 2017/01/25 20:23:00 optional: I don't think early-return is a more rea
mmenke 2017/01/25 22:08:00 Done.
+ *defer = false;
+ if (delegate_->HandleExternalProtocol(this, redirect_info.new_url))
+ CancelAndIgnore();
return;
}
+
+ *defer = true;
+ deferred_redirect_url_ = redirect_info.new_url;
+ deferred_stage_ = DEFERRED_REDIRECT;
}
void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
@@ -344,14 +416,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) {
@@ -368,25 +432,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,
@@ -432,7 +477,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_;
@@ -441,27 +486,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
Charlie Harrison 2017/01/25 20:23:00 nit: "so start the request now"? The sentence conf
mmenke 2017/01/25 22:08:00 Done.
StartRequestInternal();
break;
case DEFERRED_REDIRECT:
FollowDeferredRedirectInternal();
break;
case DEFERRED_READ:
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
- weak_ptr_factory_.GetWeakPtr()));
+ if (!called_from_resource_controller) {
Charlie Harrison 2017/01/25 20:23:00 nit: I would prefer the conditional to be reversed
mmenke 2017/01/25 22:07:59 Done.
+ 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;
}
}
@@ -558,16 +620,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());
@@ -598,7 +657,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);
Charlie Harrison 2017/01/25 20:23:00 Isn't it breaking the contract to call OnReadCompl
mmenke 2017/01/25 22:07:59 Great catch! I was keeping old behavior here, but
mmenke 2017/01/25 22:38:04 One other thing I noticed - the old code mentions
Charlie Harrison 2017/01/26 00:25:50 Acknowledged
mmenke 2017/01/27 19:14:29 Ok, I looked into this: The reason why I couldn't
} else {
// Else, trigger OnReadCompleted asynchronously to avoid starving the IO
@@ -636,18 +695,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() {
@@ -657,22 +707,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() {

Powered by Google App Engine
This is Rietveld 408576698