summaryrefslogtreecommitdiffstats
path: root/content/browser/loader/detachable_resource_handler.cc
diff options
context:
space:
mode:
authordavidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-20 03:59:18 +0000
committerdavidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-20 03:59:18 +0000
commit146b8b276bc5388c25482c78d270e7fa773e3cc5 (patch)
treefa6608a7bbb88a7b71e146b6cfa642be51493d92 /content/browser/loader/detachable_resource_handler.cc
parentf967658e63c06a3fe1b505375d14bead8b35eb0b (diff)
downloadchromium_src-146b8b276bc5388c25482c78d270e7fa773e3cc5.zip
chromium_src-146b8b276bc5388c25482c78d270e7fa773e3cc5.tar.gz
chromium_src-146b8b276bc5388c25482c78d270e7fa773e3cc5.tar.bz2
Allow prefetches to outlive their owning RenderViewHost.
This is a rework of r231910. Instead of putting the detachable logic in AsyncResourceHandler, move it to a wrapper DetachableResourceHandler. On detach, it simulates a cancel to the ResourceHandler it wraps and then continues to drain the request itself. This should have fewer buffering complications. BUG=286186 TEST=ResourceDispatcherHostTest.Cancel, ResourceDispatcherHostTest.DetachedResourceTimesOut, ResourceDispatcherHostTest.DeletedFilterDetached, ResourceDispatcherHostTest.DeletedFilterDetachedRedirect, ResourceDispatcherHostTest.DetachWhileStartIsDeferred ResourceDispatcherHostTest.TestProcessCancelDetachedTimeout, ResourceDispatcherHostTest.CancelRequestsForContextDetached, ResourceDispatcherHostTest.DataSentBeforeDetach Review URL: https://codereview.chromium.org/59783003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236132 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/loader/detachable_resource_handler.cc')
-rw-r--r--content/browser/loader/detachable_resource_handler.cc209
1 files changed, 209 insertions, 0 deletions
diff --git a/content/browser/loader/detachable_resource_handler.cc b/content/browser/loader/detachable_resource_handler.cc
new file mode 100644
index 0000000..7cc7b09
--- /dev/null
+++ b/content/browser/loader/detachable_resource_handler.cc
@@ -0,0 +1,209 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/detachable_resource_handler.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request_status.h"
+
+namespace {
+// This matches the maximum allocation size of AsyncResourceHandler.
+const int kReadBufSize = 32 * 1024;
+}
+
+namespace content {
+
+DetachableResourceHandler::DetachableResourceHandler(
+ net::URLRequest* request,
+ base::TimeDelta cancel_delay,
+ scoped_ptr<ResourceHandler> next_handler)
+ : ResourceHandler(request),
+ next_handler_(next_handler.Pass()),
+ cancel_delay_(cancel_delay),
+ is_deferred_(false),
+ is_finished_(false) {
+ GetRequestInfo()->set_detachable_handler(this);
+}
+
+DetachableResourceHandler::~DetachableResourceHandler() {
+ // Cleanup back-pointer stored on the request info.
+ GetRequestInfo()->set_detachable_handler(NULL);
+}
+
+void DetachableResourceHandler::Detach() {
+ if (is_detached())
+ return;
+
+ if (!is_finished_) {
+ // Simulate a cancel on the next handler before destroying it.
+ net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
+ net::ERR_ABORTED);
+ bool defer_ignored = false;
+ next_handler_->OnResponseCompleted(GetRequestID(), status, std::string(),
+ &defer_ignored);
+ DCHECK(!defer_ignored);
+ // If |next_handler_| were to defer its shutdown in OnResponseCompleted,
+ // this would destroy it anyway. Fortunately, AsyncResourceHandler never
+ // does this anyway, so DCHECK it. BufferedResourceHandler and RVH shutdown
+ // already ignore deferred ResourceHandler shutdown, but
+ // DetachableResourceHandler and the detach-on-renderer-cancel logic
+ // introduces a case where this occurs when the renderer cancels a resource.
+ }
+ // A OnWillRead / OnReadCompleted pair may still be in progress, but
+ // OnWillRead passes back a scoped_refptr, so downstream handler's buffer will
+ // survive long enough to complete that read. From there, future reads will
+ // drain into |read_buffer_|. (If |next_handler_| is an AsyncResourceHandler,
+ // the net::IOBuffer takes a reference to the ResourceBuffer which owns the
+ // shared memory.)
+ next_handler_.reset();
+
+ // Time the request out if it takes too long.
+ detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>());
+ detached_timer_->Start(
+ FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel);
+
+ // Resume if necessary. The request may have been deferred, say, waiting on a
+ // full buffer in AsyncResourceHandler. Now that it has been detached, resume
+ // and drain it.
+ if (is_deferred_)
+ Resume();
+}
+
+void DetachableResourceHandler::SetController(ResourceController* controller) {
+ ResourceHandler::SetController(controller);
+
+ // Intercept the ResourceController for downstream handlers to keep track of
+ // whether the request is deferred.
+ if (next_handler_)
+ next_handler_->SetController(this);
+}
+
+bool DetachableResourceHandler::OnUploadProgress(int request_id,
+ uint64 position,
+ uint64 size) {
+ if (!next_handler_)
+ return true;
+
+ return next_handler_->OnUploadProgress(request_id, position, size);
+}
+
+bool DetachableResourceHandler::OnRequestRedirected(int request_id,
+ const GURL& url,
+ ResourceResponse* response,
+ bool* defer) {
+ DCHECK(!is_deferred_);
+
+ if (!next_handler_)
+ return true;
+
+ bool ret = next_handler_->OnRequestRedirected(request_id, url, response,
+ &is_deferred_);
+ *defer = is_deferred_;
+ return ret;
+}
+
+bool DetachableResourceHandler::OnResponseStarted(int request_id,
+ ResourceResponse* response,
+ bool* defer) {
+ DCHECK(!is_deferred_);
+
+ if (!next_handler_)
+ return true;
+
+ bool ret =
+ next_handler_->OnResponseStarted(request_id, response, &is_deferred_);
+ *defer = is_deferred_;
+ return ret;
+}
+
+bool DetachableResourceHandler::OnWillStart(int request_id, const GURL& url,
+ bool* defer) {
+ DCHECK(!is_deferred_);
+
+ if (!next_handler_)
+ return true;
+
+ bool ret = next_handler_->OnWillStart(request_id, url, &is_deferred_);
+ *defer = is_deferred_;
+ return ret;
+}
+
+bool DetachableResourceHandler::OnWillRead(int request_id,
+ scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) {
+ if (!next_handler_) {
+ DCHECK_EQ(-1, min_size);
+ if (!read_buffer_)
+ read_buffer_ = new net::IOBuffer(kReadBufSize);
+ *buf = read_buffer_;
+ *buf_size = kReadBufSize;
+ return true;
+ }
+
+ return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
+}
+
+bool DetachableResourceHandler::OnReadCompleted(int request_id, int bytes_read,
+ bool* defer) {
+ DCHECK(!is_deferred_);
+
+ if (!next_handler_)
+ return true;
+
+ bool ret =
+ next_handler_->OnReadCompleted(request_id, bytes_read, &is_deferred_);
+ *defer = is_deferred_;
+ return ret;
+}
+
+void DetachableResourceHandler::OnResponseCompleted(
+ int request_id,
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) {
+ // No DCHECK(!is_deferred_) as the request may have been cancelled while
+ // deferred.
+
+ if (!next_handler_)
+ return;
+
+ is_finished_ = true;
+
+ next_handler_->OnResponseCompleted(request_id, status, security_info,
+ &is_deferred_);
+ *defer = is_deferred_;
+}
+
+void DetachableResourceHandler::OnDataDownloaded(int request_id,
+ int bytes_downloaded) {
+ if (!next_handler_)
+ return;
+
+ next_handler_->OnDataDownloaded(request_id, bytes_downloaded);
+}
+
+void DetachableResourceHandler::Resume() {
+ DCHECK(is_deferred_);
+ is_deferred_ = false;
+ controller()->Resume();
+}
+
+void DetachableResourceHandler::Cancel() {
+ controller()->Cancel();
+}
+
+void DetachableResourceHandler::CancelAndIgnore() {
+ controller()->CancelAndIgnore();
+}
+
+void DetachableResourceHandler::CancelWithError(int error_code) {
+ controller()->CancelWithError(error_code);
+}
+
+} // namespace content