diff options
author | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-20 03:59:18 +0000 |
---|---|---|
committer | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-20 03:59:18 +0000 |
commit | 146b8b276bc5388c25482c78d270e7fa773e3cc5 (patch) | |
tree | fa6608a7bbb88a7b71e146b6cfa642be51493d92 /content/browser/loader/detachable_resource_handler.cc | |
parent | f967658e63c06a3fe1b505375d14bead8b35eb0b (diff) | |
download | chromium_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.cc | 209 |
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 |