summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-17 21:53:08 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-17 21:53:08 +0000
commit0aa5531f4cfa1a5e4fcb571201f6c39221b1260a (patch)
tree889fd0590f06fdc99d2bee143e060a2d26c8326e /chrome/renderer
parent8ef59c3b8d485227dae56a1ce4edc784be329f59 (diff)
downloadchromium_src-0aa5531f4cfa1a5e4fcb571201f6c39221b1260a.zip
chromium_src-0aa5531f4cfa1a5e4fcb571201f6c39221b1260a.tar.gz
chromium_src-0aa5531f4cfa1a5e4fcb571201f6c39221b1260a.tar.bz2
Remove throttling code from the Browser process and implement throttling in the Renderer.
The previous way of doing throttling was just calling CloseContents() on a window to reject it. But since the Browser is notified about a window opening asynchronously, by the time the CloseContents() sends a message back to the Renderer, a bunch more windows have been opened, leading to memory exhaustion. Instead, make all RenderViews created from a parent RenderView share a counter and start refusing to create RenderViews if too many RV have been created. Every RenderView (except for the first one) is assumed to be an unrequested popup, until notified by the Browser process by either a ViewMsg_DisassociateFromPopupCount message (this RenderView is a new top level page) or a ViewMsg_DisassociatePopup message (this RenderView is a requested popup and therefore shouldn't count against the count.) BUG=3382, 2632 Review URL: http://codereview.chromium.org/7388 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3568 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/render_thread.cc5
-rw-r--r--chrome/renderer/render_view.cc47
-rw-r--r--chrome/renderer/render_view.h44
3 files changed, 80 insertions, 16 deletions
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 56ed3a8..fd262de 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -205,9 +205,9 @@ void RenderThread::OnCreateNewView(HWND parent_hwnd,
int32 view_id) {
// TODO(darin): once we have a RenderThread per RenderView, this will need to
// change to assert that we are not creating more than one view.
-
RenderView::Create(
- parent_hwnd, modal_dialog_event, MSG_ROUTING_NONE, webkit_prefs, view_id);
+ parent_hwnd, modal_dialog_event, MSG_ROUTING_NONE, webkit_prefs,
+ new SharedRenderViewCounter(0), view_id);
}
void RenderThread::OnSetCacheCapacities(size_t min_dead_capacity,
@@ -238,4 +238,3 @@ void RenderThread::InformHostOfCacheStatsLater() {
&RenderThread::InformHostOfCacheStats),
kCacheStatsDelayMS);
}
-
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 48f1a4c..253a869 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -94,6 +94,9 @@ const TimeDelta kDelayForNavigationSync = TimeDelta::FromSeconds(5);
// globally unique in the renderer.
static int32 next_page_id_ = 1;
+// The maximum number of popups that can be spawned from one page.
+static const int kMaximumNumberOfUnacknowledgedPopups = 25;
+
static const char* const kUnreachableWebDataURL =
"chrome-resource://chromewebdata/";
@@ -152,6 +155,7 @@ RenderView::RenderView()
history_forward_list_count_(0),
disable_popup_blocking_(false),
has_unload_listener_(false),
+ decrement_shared_popup_at_destruction_(false),
greasemonkey_enabled_(false) {
resource_dispatcher_ = new ResourceDispatcher(this);
#ifdef CHROME_PERSONALIZATION
@@ -160,6 +164,9 @@ RenderView::RenderView()
}
RenderView::~RenderView() {
+ if (decrement_shared_popup_at_destruction_)
+ shared_popup_counter_->data--;
+
resource_dispatcher_->ClearMessageSender();
// Clear any back-pointers that might still be held by plugins.
PluginDelegateList::iterator it = plugin_delegates_.begin();
@@ -177,17 +184,20 @@ RenderView::~RenderView() {
}
/*static*/
-RenderView* RenderView::Create(HWND parent_hwnd,
- HANDLE modal_dialog_event,
- int32 opener_id,
- const WebPreferences& webkit_prefs,
- int32 routing_id) {
+RenderView* RenderView::Create(
+ HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ SharedRenderViewCounter* counter,
+ int32 routing_id) {
DCHECK(routing_id != MSG_ROUTING_NONE);
scoped_refptr<RenderView> view = new RenderView();
view->Init(parent_hwnd,
modal_dialog_event,
opener_id,
webkit_prefs,
+ counter,
routing_id); // adds reference
return view;
}
@@ -227,12 +237,22 @@ void RenderView::Init(HWND parent_hwnd,
HANDLE modal_dialog_event,
int32 opener_id,
const WebPreferences& webkit_prefs,
+ SharedRenderViewCounter* counter,
int32 routing_id) {
DCHECK(!webview());
if (opener_id != MSG_ROUTING_NONE)
opener_id_ = opener_id;
+ if (counter) {
+ shared_popup_counter_ = counter;
+ shared_popup_counter_->data++;
+ decrement_shared_popup_at_destruction_ = true;
+ } else {
+ shared_popup_counter_ = new SharedRenderViewCounter(0);
+ decrement_shared_popup_at_destruction_ = false;
+ }
+
// Avoid a leak here by not assigning, since WebView::Create addrefs for us.
WebWidget* view = WebView::Create(this, webkit_prefs);
webwidget_.swap(&view);
@@ -344,6 +364,8 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
#endif
IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
OnMessageFromExternalHost)
+ IPC_MESSAGE_HANDLER(ViewMsg_DisassociateFromPopupCount,
+ OnDisassociateFromPopupCount)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
IPC_END_MESSAGE_MAP()
@@ -1673,6 +1695,10 @@ void RenderView::DebuggerOutput(const std::wstring& out) {
}
WebView* RenderView::CreateWebView(WebView* webview, bool user_gesture) {
+ // Check to make sure we aren't overloading on popups.
+ if (shared_popup_counter_->data > kMaximumNumberOfUnacknowledgedPopups)
+ return NULL;
+
int32 routing_id = MSG_ROUTING_NONE;
HANDLE modal_dialog_event = NULL;
bool result = RenderThread::current()->Send(
@@ -1686,7 +1712,8 @@ WebView* RenderView::CreateWebView(WebView* webview, bool user_gesture) {
// The WebView holds a reference to this new RenderView
const WebPreferences& prefs = webview->GetPreferences();
RenderView* view = RenderView::Create(NULL, modal_dialog_event, routing_id_,
- prefs, routing_id);
+ prefs, shared_popup_counter_,
+ routing_id);
view->set_opened_by_user_gesture(user_gesture);
// Copy over the alternate error page URL so we can have alt error pages in
@@ -2595,6 +2622,13 @@ void RenderView::OnMessageFromExternalHost(
main_frame->LoadRequest(request.get());
}
+void RenderView::OnDisassociateFromPopupCount() {
+ if (decrement_shared_popup_at_destruction_)
+ shared_popup_counter_->data--;
+ shared_popup_counter_ = new SharedRenderViewCounter(0);
+ decrement_shared_popup_at_destruction_ = false;
+}
+
std::string RenderView::GetAltHTMLForTemplate(
const DictionaryValue& error_strings, int template_resource_id) const {
const StringPiece template_html(
@@ -2609,4 +2643,3 @@ std::string RenderView::GetAltHTMLForTemplate(
return jstemplate_builder::GetTemplateHtml(
template_html, &error_strings, "t");
}
-
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index d307e48..cba9df9 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -51,6 +51,20 @@ namespace webkit_glue {
struct FileUploadData;
}
+// We need to prevent a page from trying to create infinite popups. It is not
+// as simple as keeping a count of the number of immediate children
+// popups. Having an html file that window.open()s itself would create
+// an unlimited chain of RenderViews who only have one RenderView child.
+//
+// Therefore, each new top level RenderView creates a new counter and shares it
+// with all its children and grandchildren popup RenderViews created with
+// CreateWebView() to have a sort of global limit for the page so no more than
+// kMaximumNumberOfPopups popups are created.
+//
+// This is a RefCounted holder of an int because I can't say
+// scoped_refptr<int>.
+typedef base::RefCountedData<int> SharedRenderViewCounter;
+
//
// RenderView is an object that manages a WebView object, and provides a
// communication interface with an embedding application process
@@ -64,12 +78,15 @@ class RenderView : public RenderWidget, public WebViewDelegate,
// the renderer and plugin processes know to pump window messages. If this
// is a constrained popup or as a new tab, opener_id is the routing ID of the
// RenderView responsible for creating this RenderView (corresponding to the
- // parent_hwnd).
- static RenderView* Create(HWND parent_hwnd,
- HANDLE modal_dialog_event,
- int32 opener_id,
- const WebPreferences& webkit_prefs,
- int32 routing_id);
+ // parent_hwnd). |counter| is either a currently initialized counter, or NULL
+ // (in which case we treat this RenderView as a top level window).
+ static RenderView* Create(
+ HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ SharedRenderViewCounter* counter,
+ int32 routing_id);
// Sets the "next page id" counter.
static void SetNextPageID(int32 next_page_id);
@@ -293,6 +310,7 @@ class RenderView : public RenderWidget, public WebViewDelegate,
HANDLE modal_dialog_event,
int32 opener_id,
const WebPreferences& webkit_prefs,
+ SharedRenderViewCounter* counter,
int32 routing_id);
void UpdateURL(WebFrame* frame);
@@ -443,6 +461,10 @@ class RenderView : public RenderWidget, public WebViewDelegate,
void OnMessageFromExternalHost(const std::string& target,
const std::string& message);
+ // Message that we should no longer be part of the current popup window
+ // grouping, and should form our own grouping.
+ void OnDisassociateFromPopupCount();
+
// Switches the frame's CSS media type to "print" and calculate the number of
// printed pages that are to be expected. |frame| will be used to calculate
// the number of expected pages for this frame only.
@@ -619,6 +641,16 @@ class RenderView : public RenderWidget, public WebViewDelegate,
// True if the page has any frame-level unload or beforeunload listeners.
bool has_unload_listener_;
+ // The total number of unrequested popups that exist and can be followed back
+ // to a common opener. This count is shared among all RenderViews created
+ // with CreateWebView(). All popups are treated as unrequested until
+ // specifically instructed otherwise by the Browser process.
+ scoped_refptr<SharedRenderViewCounter> shared_popup_counter_;
+
+ // Whether this is a top level window (instead of a popup). Top level windows
+ // shouldn't count against their own |shared_popup_counter_|.
+ bool decrement_shared_popup_at_destruction_;
+
// Handles accessibility requests into the renderer side, as well as
// maintains the cache and other features of the accessibility tree.
scoped_ptr<GlueAccessibility> glue_accessibility_;