summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-12 22:40:07 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-12 22:40:07 +0000
commit5862bb5ece261cb835b5677cdc6e138a071e07f9 (patch)
tree9bcb0f2e50d6fd0d6052712390a232b0a7a37ee1 /chrome/browser
parent41734542d56be130baff1327c91abd988d7b850a (diff)
downloadchromium_src-5862bb5ece261cb835b5677cdc6e138a071e07f9.zip
chromium_src-5862bb5ece261cb835b5677cdc6e138a071e07f9.tar.gz
chromium_src-5862bb5ece261cb835b5677cdc6e138a071e07f9.tar.bz2
This CL adds a way to block resource requests in the ResourceDispatcherHost for specific RenderViewHosts.
This is used by the interstitial code to prevent the original page from making network requests while the interstitial is showing. Several UI tests are still required to test this. Because of the inherent complexity of the scenarios to test this, I'm afraid these tests are going to be flakey and soon after disabled (like many of the interstitial UI tests at this point). This will be done next as part of my next effort to mock some of the WebContents stuff. TEST=Run the unit tests. Create a page that does XMLHttpRequests and log when the requests complete with the time it did. While that page is shown, switch to a malware/bad SSL page. Come back to the page, ensure no requests were processed while the interstitial was showing. BUG=None Review URL: http://codereview.chromium.org/16546 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7898 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/interstitial_page.cc147
-rw-r--r--chrome/browser/interstitial_page.h11
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc103
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h46
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc166
5 files changed, 435 insertions, 38 deletions
diff --git a/chrome/browser/interstitial_page.cc b/chrome/browser/interstitial_page.cc
index 514e822..fb69929 100644
--- a/chrome/browser/interstitial_page.cc
+++ b/chrome/browser/interstitial_page.cc
@@ -17,6 +17,55 @@
#include "chrome/views/window_delegate.h"
#include "net/base/escape.h"
+enum ResourceRequestAction {
+ BLOCK,
+ RESUME,
+ CANCEL
+};
+
+namespace {
+
+class ResourceRequestTask : public Task {
+ public:
+ ResourceRequestTask(RenderViewHost* render_view_host,
+ ResourceRequestAction action)
+ : action_(action),
+ process_id_(render_view_host->process()->host_id()),
+ render_view_host_id_(render_view_host->routing_id()),
+ resource_dispatcher_host_(
+ g_browser_process->resource_dispatcher_host()) {
+ }
+
+ virtual void Run() {
+ switch (action_) {
+ case BLOCK:
+ resource_dispatcher_host_->BlockRequestsForRenderView(
+ process_id_, render_view_host_id_);
+ break;
+ case RESUME:
+ resource_dispatcher_host_->ResumeBlockedRequestsForRenderView(
+ process_id_, render_view_host_id_);
+ break;
+ case CANCEL:
+ resource_dispatcher_host_->CancelBlockedRequestsForRenderView(
+ process_id_, render_view_host_id_);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ private:
+ ResourceRequestAction action_;
+ int process_id_;
+ int render_view_host_id_;
+ ResourceDispatcherHost* resource_dispatcher_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceRequestTask);
+};
+
+} // namespace
+
// static
InterstitialPage::InterstitialPageMap*
InterstitialPage::tab_to_interstitial_page_ = NULL;
@@ -30,7 +79,8 @@ InterstitialPage::InterstitialPage(WebContents* tab,
enabled_(true),
new_navigation_(new_navigation),
render_view_host_(NULL),
- should_revert_tab_title_(false) {
+ should_revert_tab_title_(false),
+ ui_loop_(MessageLoop::current()) {
InitInterstitialPageMap();
// It would be inconsistent to create an interstitial with no new navigation
// (which is the case when the interstitial was triggered by a sub-resource on
@@ -51,6 +101,16 @@ void InterstitialPage::Show() {
if (tab_->interstitial_page())
tab_->interstitial_page()->DontProceed();
+ // Block the resource requests for the render view host while it is hidden.
+ TakeActionOnResourceDispatcher(BLOCK);
+ // We need to be notified when the RenderViewHost is destroyed so we can
+ // cancel the blocked requests. We cannot do that on
+ // NOTIFY_TAB_CONTENTS_DESTROYED as at that point the RenderViewHost has
+ // already been destroyed.
+ notification_registrar_.Add(
+ this, NOTIFY_RENDER_WIDGET_HOST_DESTROYED,
+ Source<RenderWidgetHost>(tab_->render_view_host()));
+
// Update the tab_to_interstitial_page_ map.
InterstitialPageMap::const_iterator iter =
tab_to_interstitial_page_->find(tab_);
@@ -101,25 +161,38 @@ void InterstitialPage::Hide() {
void InterstitialPage::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NOTIFY_NAV_ENTRY_PENDING) {
- // We are navigating away from the interstitial. Make sure clicking on the
- // interstitial will have no effect.
- Disable();
- return;
- }
- DCHECK(type == NOTIFY_TAB_CONTENTS_DESTROYED ||
- type == NOTIFY_NAV_ENTRY_COMMITTED);
- if (!action_taken_) {
- // We are navigating away from the interstitial or closing a tab with an
- // interstitial. Default to DontProceed(). We don't just call Hide as
- // subclasses will almost certainly override DontProceed to do some work
- // (ex: close pending connections).
- DontProceed();
- } else {
- // User decided to proceed and either the navigation was committed or the
- // tab was closed before that.
- Hide();
- // WARNING: we are now deleted!
+ switch (type) {
+ case NOTIFY_NAV_ENTRY_PENDING:
+ // We are navigating away from the interstitial. Make sure clicking on
+ // the interstitial will have no effect.
+ Disable();
+ break;
+ case NOTIFY_RENDER_WIDGET_HOST_DESTROYED:
+ if (!action_taken_) {
+ // The RenderViewHost is being destroyed (as part of the tab being
+ // closed), make sure we clear the blocked requests.
+ DCHECK(Source<RenderViewHost>(source).ptr() ==
+ tab_->render_view_host());
+ TakeActionOnResourceDispatcher(CANCEL);
+ }
+ break;
+ case NOTIFY_TAB_CONTENTS_DESTROYED:
+ case NOTIFY_NAV_ENTRY_COMMITTED:
+ if (!action_taken_) {
+ // We are navigating away from the interstitial or closing a tab with an
+ // interstitial. Default to DontProceed(). We don't just call Hide as
+ // subclasses will almost certainly override DontProceed to do some work
+ // (ex: close pending connections).
+ DontProceed();
+ } else {
+ // User decided to proceed and either the navigation was committed or
+ // the tab was closed before that.
+ Hide();
+ // WARNING: we are now deleted!
+ }
+ break;
+ default:
+ NOTREACHED();
}
}
@@ -150,6 +223,15 @@ void InterstitialPage::Proceed() {
// Resumes the throbber.
tab_->SetIsLoading(true, NULL);
+ // If this is a new navigation, the old page is going away, so we cancel any
+ // blocked requests for it. If it is not a new navigation, then it means the
+ // interstitial was shown as a result of a resource loading in the page.
+ // Since the user wants to proceed, we'll let any blocked request go through.
+ if (new_navigation_)
+ TakeActionOnResourceDispatcher(CANCEL);
+ else
+ TakeActionOnResourceDispatcher(RESUME);
+
// No need to hide if we are a new navigation, we'll get hidden when the
// navigation is committed.
if (!new_navigation_) {
@@ -163,6 +245,16 @@ void InterstitialPage::DontProceed() {
Disable();
action_taken_ = true;
+ // If this is a new navigation, we are returning to the original page, so we
+ // resume blocked requests for it. If it is not a new navigation, then it
+ // means the interstitial was shown as a result of a resource loading in the
+ // page and we won't return to the original page, so we cancel blocked
+ // requests in that case.
+ if (new_navigation_)
+ TakeActionOnResourceDispatcher(RESUME);
+ else
+ TakeActionOnResourceDispatcher(CANCEL);
+
if (new_navigation_) {
// Since no navigation happens we have to discard the transient entry
// explicitely. Note that by calling DiscardNonCommittedEntries() we also
@@ -236,6 +328,21 @@ void InterstitialPage::Disable() {
enabled_ = false;
}
+void InterstitialPage::TakeActionOnResourceDispatcher(
+ ResourceRequestAction action) {
+ DCHECK(MessageLoop::current() == ui_loop_) <<
+ "TakeActionOnResourceDispatcher should be called on the main thread.";
+ // The tab might not have a render_view_host if it was closed (in which case,
+ // we have taken care of the blocked requests when processing
+ // NOTIFY_RENDER_WIDGET_HOST_DESTROYED.
+ // Also we need to test there is an IO thread, as when unit-tests we don't
+ // have one.
+ if (tab_->render_view_host() && g_browser_process->io_thread()) {
+ g_browser_process->io_thread()->message_loop()->PostTask(
+ FROM_HERE, new ResourceRequestTask(tab_->render_view_host(), action));
+ }
+}
+
// static
void InterstitialPage::InitInterstitialPageMap() {
if (!tab_to_interstitial_page_)
diff --git a/chrome/browser/interstitial_page.h b/chrome/browser/interstitial_page.h
index 92674c1..6c2c76f5 100644
--- a/chrome/browser/interstitial_page.h
+++ b/chrome/browser/interstitial_page.h
@@ -26,6 +26,8 @@ class WebContents;
// through a navigation, the WebContents closing them or the tab containing them
// being closed.
+enum ResourceRequestAction;
+
class InterstitialPage : public NotificationObserver,
public RenderViewHostDelegate {
public:
@@ -34,7 +36,7 @@ class InterstitialPage : public NotificationObserver,
// case a temporary navigation entry is created with the URL |url| and
// added to the navigation controller (so the interstitial page appears as a
// new navigation entry). |new_navigation| should be false when the
- // interstitial was triggered by a loading a sub-resource in a page.
+ // interstitial was triggered by a loading a sub-resource in a page.
InterstitialPage(WebContents* tab, bool new_navigation, const GURL& url);
virtual ~InterstitialPage();
@@ -117,6 +119,11 @@ class InterstitialPage : public NotificationObserver,
// - any command sent by the RenderViewHost will be ignored.
void Disable();
+ // Executes the passed action on the ResourceDispatcher (on the IO thread).
+ // Used to block/resume/cancel requests for the RenderViewHost hidden by this
+ // interstitial.
+ void TakeActionOnResourceDispatcher(ResourceRequestAction action);
+
// The tab in which we are displayed.
WebContents* tab_;
@@ -147,6 +154,8 @@ class InterstitialPage : public NotificationObserver,
// interstitial is hidden.
std::wstring original_tab_title_;
+ MessageLoop* ui_loop_;
+
// We keep a map of the various blocking pages shown as the UI tests need to
// be able to retrieve them.
typedef std::map<WebContents*,InterstitialPage*> InterstitialPageMap;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index f746429..c591ee6 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -136,6 +136,23 @@ ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop)
ResourceDispatcherHost::~ResourceDispatcherHost() {
AsyncResourceHandler::GlobalCleanup();
STLDeleteValues(&pending_requests_);
+
+ // Clear blocked requests if any left.
+ // Note that we have to do this in 2 passes as we cannot call
+ // CancelBlockedRequestsForRenderView while iterating over
+ // blocked_requests_map_, as it modifies it.
+ std::set<ProcessRendererIDs> ids;
+ for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin();
+ iter != blocked_requests_map_.end(); ++iter) {
+ std::pair<std::set<ProcessRendererIDs>::iterator, bool> result =
+ ids.insert(iter->first);
+ // We should not have duplicates.
+ DCHECK(result.second);
+ }
+ for (std::set<ProcessRendererIDs>::const_iterator iter = ids.begin();
+ iter != ids.end(); ++iter) {
+ CancelBlockedRequestsForRenderView(iter->first, iter->second);
+ }
}
void ResourceDispatcherHost::Initialize() {
@@ -611,6 +628,31 @@ void ResourceDispatcherHost::CancelRequestsForRenderView(
if (iter != pending_requests_.end())
RemovePendingRequest(iter);
}
+
+ // Now deal with blocked requests if any.
+ if (render_view_id != -1) {
+ if (blocked_requests_map_.find(std::pair<int, int>(render_process_host_id,
+ render_view_id)) !=
+ blocked_requests_map_.end()) {
+ CancelBlockedRequestsForRenderView(render_process_host_id,
+ render_view_id);
+ }
+ } else {
+ // We have to do all render views for the process |render_process_host_id|.
+ // Note that we have to do this in 2 passes as we cannot call
+ // CancelBlockedRequestsForRenderView while iterating over
+ // blocked_requests_map_, as it modifies it.
+ std::set<int> render_view_ids;
+ for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin();
+ iter != blocked_requests_map_.end(); ++iter) {
+ if (iter->first.first == render_process_host_id)
+ render_view_ids.insert(iter->first.second);
+ }
+ for (std::set<int>::const_iterator iter = render_view_ids.begin();
+ iter != render_view_ids.end(); ++iter) {
+ CancelBlockedRequestsForRenderView(render_process_host_id, *iter);
+ }
+ }
}
// Cancels the request and removes it from the list.
@@ -779,6 +821,16 @@ bool ResourceDispatcherHost::CompleteResponseStarted(URLRequest* request) {
void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request,
bool mixed_content) {
ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+ std::pair<int, int> pair_id(info->render_process_host_id,
+ info->render_view_id);
+ BlockedRequestMap::const_iterator iter = blocked_requests_map_.find(pair_id);
+ if (iter != blocked_requests_map_.end()) {
+ // The request should be blocked.
+ iter->second->push_back(BlockedRequest(request, mixed_content));
+ return;
+ }
+
GlobalRequestID global_id(info->render_process_host_id, info->request_id);
pending_requests_[global_id] = request;
if (mixed_content) {
@@ -1215,3 +1267,54 @@ void ResourceDispatcherHost::MaybeUpdateUploadProgress(ExtraRequestInfo *info,
info->last_upload_position = position;
}
}
+
+void ResourceDispatcherHost::BlockRequestsForRenderView(
+ int render_process_host_id,
+ int render_view_id) {
+ std::pair<int, int> key(render_process_host_id, render_view_id);
+ DCHECK(blocked_requests_map_.find(key) == blocked_requests_map_.end()) <<
+ "BlockRequestsForRenderView called multiple time for the same RVH";
+ blocked_requests_map_[key] = new BlockedRequestsList();
+}
+
+void ResourceDispatcherHost::ResumeBlockedRequestsForRenderView(
+ int render_process_host_id,
+ int render_view_id) {
+ ProcessBlockedRequestsForRenderView(render_process_host_id,
+ render_view_id, false);
+}
+
+void ResourceDispatcherHost::CancelBlockedRequestsForRenderView(
+ int render_process_host_id,
+ int render_view_id) {
+ ProcessBlockedRequestsForRenderView(render_process_host_id,
+ render_view_id, true);
+}
+
+void ResourceDispatcherHost::ProcessBlockedRequestsForRenderView(
+ int render_process_host_id,
+ int render_view_id,
+ bool cancel_requests) {
+ BlockedRequestMap::iterator iter =
+ blocked_requests_map_.find(std::pair<int, int>(render_process_host_id,
+ render_view_id));
+ if (iter == blocked_requests_map_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ BlockedRequestsList* requests = iter->second;
+
+ // Removing the vector from the map unblocks any subsequent requests.
+ blocked_requests_map_.erase(iter);
+
+ for (BlockedRequestsList::iterator req_iter = requests->begin();
+ req_iter != requests->end(); ++req_iter) {
+ if (cancel_requests)
+ delete req_iter->url_request;
+ else
+ BeginRequestInternal(req_iter->url_request, req_iter->mixed_content);
+ }
+
+ delete requests;
+}
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
index c0e7e931..757de44 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -14,6 +14,7 @@
#include <map>
#include <string>
+#include <vector>
#include "base/logging.h"
#include "base/observer_list.h"
@@ -202,7 +203,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
URLRequestContext* request_context,
IPC::Message* sync_result);
- // Initiate a download from the browser process (as opposed to a resource
+ // Initiates a download from the browser process (as opposed to a resource
// request from the renderer).
void BeginDownload(const GURL& url,
const GURL& referrer,
@@ -210,7 +211,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
int render_view_id,
URLRequestContext* request_context);
- // Initiate a save file from the browser process (as opposed to a resource
+ // Initiates a save file from the browser process (as opposed to a resource
// request from the renderer).
void BeginSaveFile(const GURL& url,
const GURL& referrer,
@@ -301,12 +302,12 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
return r;
}
- // Add an observer. The observer will be called on the IO thread. To
+ // Adds an observer. The observer will be called on the IO thread. To
// observe resource events on the UI thread, subscribe to the
// NOTIFY_RESOURCE_* notifications of the notification service.
void AddObserver(Observer* obs);
- // Remove an observer.
+ // Removes an observer.
void RemoveObserver(Observer* obs);
// Retrieves a URLRequest. Must be called from the IO thread.
@@ -317,16 +318,41 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
bool ShouldDownload(const std::string& mime_type,
const std::string& content_disposition);
- // Notify our observers that a request has been cancelled.
+ // Notifies our observers that a request has been cancelled.
void NotifyResponseCompleted(URLRequest* request, int render_process_host_id);
void RemovePendingRequest(int render_process_host_id, int request_id);
+ // Causes all new requests for the render view identified by
+ // |render_process_host_id| and |render_view_id| to be blocked (not being
+ // started) until ResumeBlockedRequestsForRenderView or
+ // CancelBlockedRequestsForRenderView is called.
+ void BlockRequestsForRenderView(int render_process_host_id,
+ int render_view_id);
+
+ // Resumes any blocked request for the specified RenderView.
+ void ResumeBlockedRequestsForRenderView(int render_process_host_id,
+ int render_view_id);
+
+ // Cancels any blocked request for the specified RenderView.
+ void CancelBlockedRequestsForRenderView(int render_process_host_id,
+ int render_view_id);
+
private:
+ FRIEND_TEST(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies);
class ShutdownTask;
friend class ShutdownTask;
+ struct BlockedRequest {
+ BlockedRequest(URLRequest* url_request, bool mixed_content)
+ : url_request(url_request),
+ mixed_content(mixed_content) {
+ }
+ URLRequest* url_request;
+ bool mixed_content;
+ };
+
// A shutdown helper that runs on the IO thread.
void OnShutdown();
@@ -396,6 +422,11 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
void MaybeUpdateUploadProgress(ExtraRequestInfo *info, URLRequest *request);
+ // Resumes or cancels (if |cancel_requests| is true) any blocked requests.
+ void ProcessBlockedRequestsForRenderView(int render_process_host_id,
+ int render_view_id,
+ bool cancel_requests);
+
PendingRequestList pending_requests_;
// We cache the UI message loop so we can create new UI-related objects on it.
@@ -440,6 +471,11 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// True if the resource dispatcher host has been shut down.
bool is_shutdown_;
+ typedef std::vector<BlockedRequest> BlockedRequestsList;
+ typedef std::pair<int, int> ProcessRendererIDs;
+ typedef std::map<ProcessRendererIDs, BlockedRequestsList*> BlockedRequestMap;
+ BlockedRequestMap blocked_requests_map_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHost);
};
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 8ae6e1a..d40c21b 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -51,6 +51,7 @@ class ResourceIPCAccumulator {
// This groups the messages by their request ID. The groups will be in order
// that the first message for each request ID was received, and the messages
// within the groups will be in the order that they appeared.
+ // Note that this clears messages_.
typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages;
void GetClassifiedMessages(ClassifiedMessages* msgs);
@@ -71,7 +72,7 @@ void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) {
if (id == cur_id) {
cur_requests.push_back(messages_[i]);
messages_.erase(messages_.begin() + i);
- i --;
+ i--;
}
}
messages_.erase(messages_.begin());
@@ -106,7 +107,10 @@ class ResourceDispatcherHostTest : public testing::Test,
message_loop_.RunAllPending();
}
- void MakeTestRequest(int request_id, const GURL& url);
+ void MakeTestRequest(int render_process_id,
+ int render_view_id,
+ int request_id,
+ const GURL& url);
void MakeCancelRequest(int request_id);
void EnsureTestSchemeIsAllowed() {
@@ -128,12 +132,14 @@ static void KickOffRequest() {
MessageLoop::current()->RunAllPending();
}
-void ResourceDispatcherHostTest::MakeTestRequest(int request_id,
+void ResourceDispatcherHostTest::MakeTestRequest(int render_process_id,
+ int render_view_id,
+ int request_id,
const GURL& url) {
ViewHostMsg_Resource_Request request = CreateResourceRequest("GET", url);
- host_.BeginRequest(this, GetCurrentProcess(), 0, MSG_ROUTING_NONE,
- request_id, request, NULL, NULL);
+ host_.BeginRequest(this, GetCurrentProcess(), render_process_id,
+ render_view_id, request_id, request, NULL, NULL);
KickOffRequest();
}
@@ -183,9 +189,9 @@ void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages,
// Tests whether many messages get dispatched properly.
TEST_F(ResourceDispatcherHostTest, TestMany) {
- MakeTestRequest(1, URLRequestTestJob::test_url_1());
- MakeTestRequest(2, URLRequestTestJob::test_url_2());
- MakeTestRequest(3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 0, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
// flush all the pending requests
while (URLRequestTestJob::ProcessOnePendingMessage());
@@ -207,9 +213,9 @@ TEST_F(ResourceDispatcherHostTest, TestMany) {
TEST_F(ResourceDispatcherHostTest, Cancel) {
ResourceDispatcherHost host(NULL);
- MakeTestRequest(1, URLRequestTestJob::test_url_1());
- MakeTestRequest(2, URLRequestTestJob::test_url_2());
- MakeTestRequest(3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 0, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
MakeCancelRequest(2);
// flush all the pending requests
@@ -277,7 +283,7 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
KickOffRequest();
// request 2 goes to us
- MakeTestRequest(2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 2, URLRequestTestJob::test_url_2());
// request 3 goes to the test delegate
request.url = URLRequestTestJob::test_url_3();
@@ -314,3 +320,139 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_2());
}
+// Tests blocking and resuming requests.
+TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
+ host_.BlockRequestsForRenderView(0, 1);
+ host_.BlockRequestsForRenderView(0, 2);
+ host_.BlockRequestsForRenderView(0, 3);
+
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 1, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(0, 1, 4, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 2, 5, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 3, 6, URLRequestTestJob::test_url_3());
+
+ // Flush all the pending requests
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+
+ // Sort out all the messages we saw by request
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ // All requests but the 2 for the RVH 0 should have been blocked.
+ ASSERT_EQ(2, msgs.size());
+
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_1());
+ CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
+
+ // Resume requests for RVH 1 and flush pending requests.
+ host_.ResumeBlockedRequestsForRenderView(0, 1);
+ KickOffRequest();
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+
+ msgs.clear();
+ accum_.GetClassifiedMessages(&msgs);
+ ASSERT_EQ(2, msgs.size());
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_2());
+ CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_1());
+
+ // Test that new requests are not blocked for RVH 1.
+ MakeTestRequest(0, 1, 7, URLRequestTestJob::test_url_1());
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+ msgs.clear();
+ accum_.GetClassifiedMessages(&msgs);
+ ASSERT_EQ(1, msgs.size());
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_1());
+
+ // Now resumes requests for all RVH (2 and 3).
+ host_.ResumeBlockedRequestsForRenderView(0, 2);
+ host_.ResumeBlockedRequestsForRenderView(0, 3);
+ KickOffRequest();
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+
+ msgs.clear();
+ accum_.GetClassifiedMessages(&msgs);
+ ASSERT_EQ(2, msgs.size());
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_2());
+ CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
+}
+
+// Tests blocking and canceling requests.
+TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
+ host_.BlockRequestsForRenderView(0, 1);
+
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 1, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(0, 1, 4, URLRequestTestJob::test_url_1());
+
+ // Flush all the pending requests.
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+
+ // Sort out all the messages we saw by request.
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ // The 2 requests for the RVH 0 should have been processed.
+ ASSERT_EQ(2, msgs.size());
+
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_1());
+ CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
+
+ // Cancel requests for RVH 1.
+ host_.CancelBlockedRequestsForRenderView(0, 1);
+ KickOffRequest();
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+ msgs.clear();
+ accum_.GetClassifiedMessages(&msgs);
+ ASSERT_EQ(0, msgs.size());
+}
+
+// Tests that blocked requests are canceled if their associated process dies.
+TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
+ host_.BlockRequestsForRenderView(1, 0);
+
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(1, 0, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(1, 0, 4, URLRequestTestJob::test_url_1());
+
+ // Simulate process death.
+ host_.CancelRequestsForProcess(1);
+
+ // Flush all the pending requests.
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+
+ // Sort out all the messages we saw by request.
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ // The 2 requests for the RVH 0 should have been processed.
+ ASSERT_EQ(2, msgs.size());
+
+ CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_1());
+ CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
+
+ EXPECT_TRUE(host_.blocked_requests_map_.empty());
+}
+
+// Tests that blocked requests don't leak when the ResourceDispatcherHost goes
+// away. Note that we rely on Purify for finding the leaks if any.
+// If this test turns the Purify bot red, check the ResourceDispatcherHost
+// destructor to make sure the blocked requests are deleted.
+TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
+ host_.BlockRequestsForRenderView(0, 1);
+ host_.BlockRequestsForRenderView(0, 2);
+ host_.BlockRequestsForRenderView(1, 1);
+
+ MakeTestRequest(0, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 1, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(1, 1, 4, URLRequestTestJob::test_url_1());
+ MakeTestRequest(0, 2, 5, URLRequestTestJob::test_url_2());
+ MakeTestRequest(0, 2, 6, URLRequestTestJob::test_url_3());
+
+ // Flush all the pending requests.
+ while (URLRequestTestJob::ProcessOnePendingMessage());
+}