Commit fc0ca5a3 authored by jochen@chromium.org's avatar jochen@chromium.org

Only delete old frames when a new main frame navigation commits

Also, use RVH* to identify frames, not the process id. when we run out of
processes, several unrelated RVHs might share a process.

BUG=136090,139117
TEST=browser_tests:*WebNavigation*, unit_tests:FrameNavigation*

Review URL: https://chromiumcodereview.appspot.com/10835033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149161 0039d316-1c4b-4281-b951-d872f2087c98
parent a4f88532
...@@ -26,30 +26,31 @@ const char* kValidSchemes[] = { ...@@ -26,30 +26,31 @@ const char* kValidSchemes[] = {
FrameNavigationState::FrameID::FrameID() FrameNavigationState::FrameID::FrameID()
: frame_num(-1), : frame_num(-1),
render_process_id(-1) { render_view_host(NULL) {
} }
FrameNavigationState::FrameID::FrameID(int64 frame_num, FrameNavigationState::FrameID::FrameID(
int render_process_id) int64 frame_num,
content::RenderViewHost* render_view_host)
: frame_num(frame_num), : frame_num(frame_num),
render_process_id(render_process_id) { render_view_host(render_view_host) {
} }
bool FrameNavigationState::FrameID::IsValid() const { bool FrameNavigationState::FrameID::IsValid() const {
return frame_num >= 0 && render_process_id >= 0; return frame_num >= 0 && render_view_host;
} }
bool FrameNavigationState::FrameID::operator<( bool FrameNavigationState::FrameID::operator<(
const FrameNavigationState::FrameID& other) const { const FrameNavigationState::FrameID& other) const {
return frame_num < other.frame_num || return frame_num < other.frame_num ||
(frame_num == other.frame_num && (frame_num == other.frame_num &&
render_process_id < other.render_process_id); render_view_host < other.render_view_host);
} }
bool FrameNavigationState::FrameID::operator==( bool FrameNavigationState::FrameID::operator==(
const FrameNavigationState::FrameID& other) const { const FrameNavigationState::FrameID& other) const {
return frame_num == other.frame_num && return frame_num == other.frame_num &&
render_process_id == other.render_process_id; render_view_host == other.render_view_host;
} }
bool FrameNavigationState::FrameID::operator!=( bool FrameNavigationState::FrameID::operator!=(
...@@ -91,10 +92,6 @@ void FrameNavigationState::TrackFrame(FrameID frame_id, ...@@ -91,10 +92,6 @@ void FrameNavigationState::TrackFrame(FrameID frame_id,
const GURL& url, const GURL& url,
bool is_main_frame, bool is_main_frame,
bool is_error_page) { bool is_error_page) {
if (is_main_frame) {
frame_state_map_.clear();
frame_ids_.clear();
}
FrameState& frame_state = frame_state_map_[frame_id]; FrameState& frame_state = frame_state_map_[frame_id];
frame_state.error_occurred = is_error_page; frame_state.error_occurred = is_error_page;
frame_state.url = url; frame_state.url = url;
...@@ -102,12 +99,26 @@ void FrameNavigationState::TrackFrame(FrameID frame_id, ...@@ -102,12 +99,26 @@ void FrameNavigationState::TrackFrame(FrameID frame_id,
frame_state.is_navigating = true; frame_state.is_navigating = true;
frame_state.is_committed = false; frame_state.is_committed = false;
frame_state.is_server_redirected = false; frame_state.is_server_redirected = false;
if (is_main_frame) {
main_frame_id_ = frame_id;
}
frame_ids_.insert(frame_id); frame_ids_.insert(frame_id);
} }
void FrameNavigationState::StopTrackingFramesInRVH(
content::RenderViewHost* render_view_host) {
for (std::set<FrameID>::iterator frame = frame_ids_.begin();
frame != frame_ids_.end();) {
if (frame->render_view_host != render_view_host) {
++frame;
continue;
}
FrameID frame_id = *frame;
++frame;
if (frame_id == main_frame_id_)
main_frame_id_ = FrameID();
frame_state_map_.erase(frame_id);
frame_ids_.erase(frame_id);
}
}
void FrameNavigationState::UpdateFrame(FrameID frame_id, const GURL& url) { void FrameNavigationState::UpdateFrame(FrameID frame_id, const GURL& url) {
FrameIdToStateMap::iterator frame_state = frame_state_map_.find(frame_id); FrameIdToStateMap::iterator frame_state = frame_state_map_.find(frame_id);
if (frame_state == frame_state_map_.end()) { if (frame_state == frame_state_map_.end()) {
...@@ -134,7 +145,10 @@ GURL FrameNavigationState::GetUrl(FrameID frame_id) const { ...@@ -134,7 +145,10 @@ GURL FrameNavigationState::GetUrl(FrameID frame_id) const {
} }
bool FrameNavigationState::IsMainFrame(FrameID frame_id) const { bool FrameNavigationState::IsMainFrame(FrameID frame_id) const {
return main_frame_id_.IsValid() && main_frame_id_ == frame_id; FrameIdToStateMap::const_iterator frame_state =
frame_state_map_.find(frame_id);
return (frame_state != frame_state_map_.end() &&
frame_state->second.is_main_frame);
} }
FrameNavigationState::FrameID FrameNavigationState::GetMainFrameID() const { FrameNavigationState::FrameID FrameNavigationState::GetMainFrameID() const {
...@@ -168,6 +182,8 @@ bool FrameNavigationState::GetNavigationCompleted(FrameID frame_id) const { ...@@ -168,6 +182,8 @@ bool FrameNavigationState::GetNavigationCompleted(FrameID frame_id) const {
void FrameNavigationState::SetNavigationCommitted(FrameID frame_id) { void FrameNavigationState::SetNavigationCommitted(FrameID frame_id) {
DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
frame_state_map_[frame_id].is_committed = true; frame_state_map_[frame_id].is_committed = true;
if (frame_state_map_[frame_id].is_main_frame)
main_frame_id_ = frame_id;
} }
bool FrameNavigationState::GetNavigationCommitted(FrameID frame_id) const { bool FrameNavigationState::GetNavigationCommitted(FrameID frame_id) const {
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "googleurl/src/gurl.h" #include "googleurl/src/gurl.h"
namespace content {
class RenderViewHost;
}
namespace extensions { namespace extensions {
// Tracks the navigation state of all frames in a given tab currently known to // Tracks the navigation state of all frames in a given tab currently known to
...@@ -18,12 +22,10 @@ namespace extensions { ...@@ -18,12 +22,10 @@ namespace extensions {
// occurred so no further events for this frame are being sent. // occurred so no further events for this frame are being sent.
class FrameNavigationState { class FrameNavigationState {
public: public:
// A frame is uniquely identified by its frame ID and the render process ID. // A frame is uniquely identified by its frame ID and the RVH it's in.
// We use the render process ID instead of e.g. a pointer to the RVH so we
// don't depend on the lifetime of the RVH.
struct FrameID { struct FrameID {
FrameID(); FrameID();
FrameID(int64 frame_num, int render_process_id); FrameID(int64 frame_num, content::RenderViewHost* render_view_host);
bool IsValid() const; bool IsValid() const;
...@@ -32,7 +34,7 @@ class FrameNavigationState { ...@@ -32,7 +34,7 @@ class FrameNavigationState {
bool operator!=(const FrameID& other) const; bool operator!=(const FrameID& other) const;
int64 frame_num; int64 frame_num;
int render_process_id; content::RenderViewHost* render_view_host;
}; };
typedef std::set<FrameID>::const_iterator const_iterator; typedef std::set<FrameID>::const_iterator const_iterator;
...@@ -55,6 +57,9 @@ class FrameNavigationState { ...@@ -55,6 +57,9 @@ class FrameNavigationState {
bool is_main_frame, bool is_main_frame,
bool is_error_page); bool is_error_page);
// Stops tracking all frames for a given RenderViewHost.
void StopTrackingFramesInRVH(content::RenderViewHost* render_view_host);
// Update the URL associated with a given frame. // Update the URL associated with a given frame.
void UpdateFrame(FrameID frame_id, const GURL& url); void UpdateFrame(FrameID frame_id, const GURL& url);
...@@ -64,11 +69,12 @@ class FrameNavigationState { ...@@ -64,11 +69,12 @@ class FrameNavigationState {
// Returns the URL corresponding to a tracked frame given by its |frame_id|. // Returns the URL corresponding to a tracked frame given by its |frame_id|.
GURL GetUrl(FrameID frame_id) const; GURL GetUrl(FrameID frame_id) const;
// True if the frame given by its |frame_id| is the main frame of its tab. // True if the frame given by its |frame_id| is a main frame of its tab.
// There might be multiple uncomitted main frames.
bool IsMainFrame(FrameID frame_id) const; bool IsMainFrame(FrameID frame_id) const;
// Returns the frame ID of the main frame, or -1 if the frame ID is not // Returns the frame ID of the last comitted main frame, or -1 if the frame
// known. // ID is not known.
FrameID GetMainFrameID() const; FrameID GetMainFrameID() const;
// Marks a frame as in an error state, i.e. the onErrorOccurred event was // Marks a frame as in an error state, i.e. the onErrorOccurred event was
...@@ -121,7 +127,7 @@ class FrameNavigationState { ...@@ -121,7 +127,7 @@ class FrameNavigationState {
// Set of all known frames. // Set of all known frames.
std::set<FrameID> frame_ids_; std::set<FrameID> frame_ids_;
// The current main frame. // The id of the last comitted main frame.
FrameID main_frame_id_; FrameID main_frame_id_;
// If true, also allow events from chrome-extension:// URLs. // If true, also allow events from chrome-extension:// URLs.
......
...@@ -4,21 +4,20 @@ ...@@ -4,21 +4,20 @@
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h" #include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace extensions { namespace extensions {
class FrameNavigationStateTest : public ChromeRenderViewHostTestHarness { content::RenderViewHost* fake_rvh =
}; reinterpret_cast<content::RenderViewHost*>(31337);
// Test that a frame is correctly tracked, and removed once the tab contents // Test that a frame is correctly tracked, and removed once the tab contents
// goes away. // goes away.
TEST_F(FrameNavigationStateTest, TrackFrame) { TEST(FrameNavigationStateTest, TrackFrame) {
FrameNavigationState navigation_state; FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id1(23, 1); const FrameNavigationState::FrameID frame_id1(23, fake_rvh);
const FrameNavigationState::FrameID frame_id2(42, 1); const FrameNavigationState::FrameID frame_id2(42, fake_rvh);
const GURL url1("http://www.google.com/"); const GURL url1("http://www.google.com/");
const GURL url2("http://mail.google.com/"); const GURL url2("http://mail.google.com/");
...@@ -26,6 +25,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) { ...@@ -26,6 +25,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1)); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id1)); EXPECT_FALSE(navigation_state.IsValidFrame(frame_id1));
navigation_state.TrackFrame(frame_id1, url1, true, false); navigation_state.TrackFrame(frame_id1, url1, true, false);
navigation_state.SetNavigationCommitted(frame_id1);
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_TRUE(navigation_state.IsValidFrame(frame_id1)); EXPECT_TRUE(navigation_state.IsValidFrame(frame_id1));
...@@ -33,6 +33,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) { ...@@ -33,6 +33,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2)); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id2)); EXPECT_FALSE(navigation_state.IsValidFrame(frame_id2));
navigation_state.TrackFrame(frame_id2, url2, false, false); navigation_state.TrackFrame(frame_id2, url2, false, false);
navigation_state.SetNavigationCommitted(frame_id2);
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2)); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
EXPECT_TRUE(navigation_state.IsValidFrame(frame_id2)); EXPECT_TRUE(navigation_state.IsValidFrame(frame_id2));
...@@ -42,13 +43,20 @@ TEST_F(FrameNavigationStateTest, TrackFrame) { ...@@ -42,13 +43,20 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.IsMainFrame(frame_id2)); EXPECT_FALSE(navigation_state.IsMainFrame(frame_id2));
EXPECT_EQ(url2, navigation_state.GetUrl(frame_id2)); EXPECT_EQ(url2, navigation_state.GetUrl(frame_id2));
EXPECT_EQ(frame_id1, navigation_state.GetMainFrameID()); EXPECT_EQ(frame_id1, navigation_state.GetMainFrameID());
// Drop the frames.
navigation_state.StopTrackingFramesInRVH(fake_rvh);
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id1));
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id2));
} }
// Test that no events can be sent for a frame after an error occurred, but // Test that no events can be sent for a frame after an error occurred, but
// before a new navigation happened in this frame. // before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorState) { TEST(FrameNavigationStateTest, ErrorState) {
FrameNavigationState navigation_state; FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id(42, 1); const FrameNavigationState::FrameID frame_id(42, fake_rvh);
const GURL url("http://www.google.com/"); const GURL url("http://www.google.com/");
navigation_state.TrackFrame(frame_id, url, true, false); navigation_state.TrackFrame(frame_id, url, true, false);
...@@ -73,10 +81,10 @@ TEST_F(FrameNavigationStateTest, ErrorState) { ...@@ -73,10 +81,10 @@ TEST_F(FrameNavigationStateTest, ErrorState) {
// Tests that for a sub frame, no events are send after an error occurred, but // Tests that for a sub frame, no events are send after an error occurred, but
// before a new navigation happened in this frame. // before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorStateFrame) { TEST(FrameNavigationStateTest, ErrorStateFrame) {
FrameNavigationState navigation_state; FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id1(23, 1); const FrameNavigationState::FrameID frame_id1(23, fake_rvh);
const FrameNavigationState::FrameID frame_id2(42, 1); const FrameNavigationState::FrameID frame_id2(42, fake_rvh);
const GURL url("http://www.google.com/"); const GURL url("http://www.google.com/");
navigation_state.TrackFrame(frame_id1, url, true, false); navigation_state.TrackFrame(frame_id1, url, true, false);
...@@ -101,9 +109,9 @@ TEST_F(FrameNavigationStateTest, ErrorStateFrame) { ...@@ -101,9 +109,9 @@ TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
} }
// Tests that no events are send for a not web-safe scheme. // Tests that no events are send for a not web-safe scheme.
TEST_F(FrameNavigationStateTest, WebSafeScheme) { TEST(FrameNavigationStateTest, WebSafeScheme) {
FrameNavigationState navigation_state; FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id(23, 1); const FrameNavigationState::FrameID frame_id(23, fake_rvh);
const GURL url("unsafe://www.google.com/"); const GURL url("unsafe://www.google.com/");
navigation_state.TrackFrame(frame_id, url, true, false); navigation_state.TrackFrame(frame_id, url, true, false);
......
...@@ -40,6 +40,8 @@ class WebNavigationTabObserver : public content::NotificationObserver, ...@@ -40,6 +40,8 @@ class WebNavigationTabObserver : public content::NotificationObserver,
return navigation_state_; return navigation_state_;
} }
content::RenderViewHost* GetRenderViewHostInProcess(int process_id) const;
// content::NotificationObserver implementation. // content::NotificationObserver implementation.
virtual void Observe(int type, virtual void Observe(int type,
const content::NotificationSource& source, const content::NotificationSource& source,
...@@ -97,6 +99,12 @@ class WebNavigationTabObserver : public content::NotificationObserver, ...@@ -97,6 +99,12 @@ class WebNavigationTabObserver : public content::NotificationObserver,
bool IsReferenceFragmentNavigation(FrameNavigationState::FrameID frame_id, bool IsReferenceFragmentNavigation(FrameNavigationState::FrameID frame_id,
const GURL& url); const GURL& url);
// Creates and sends onErrorOccurred events for all on-going navigations. If
// |render_view_host| is non-NULL, only generates events for frames in this
// render view host.
void SendErrorEvents(content::WebContents* web_contents,
content::RenderViewHost* render_view_host);
// Tracks the state of the frames we are sending events for. // Tracks the state of the frames we are sending events for.
FrameNavigationState navigation_state_; FrameNavigationState navigation_state_;
......
...@@ -8,7 +8,7 @@ chrome.test.runTests([ ...@@ -8,7 +8,7 @@ chrome.test.runTests([
chrome.tabs.create({"url": "about:blank"}, function(tab) { chrome.tabs.create({"url": "about:blank"}, function(tab) {
tabId = tab.id; tabId = tab.id;
var done = chrome.test.listenForever( var done = chrome.test.listenForever(
chrome.webNavigation.onBeforeNavigate, chrome.webNavigation.onCommitted,
function (details) { function (details) {
if (details.tabId != tabId) if (details.tabId != tabId)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment