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[] = {
FrameNavigationState::FrameID::FrameID()
: frame_num(-1),
render_process_id(-1) {
render_view_host(NULL) {
}
FrameNavigationState::FrameID::FrameID(int64 frame_num,
int render_process_id)
FrameNavigationState::FrameID::FrameID(
int64 frame_num,
content::RenderViewHost* render_view_host)
: frame_num(frame_num),
render_process_id(render_process_id) {
render_view_host(render_view_host) {
}
bool FrameNavigationState::FrameID::IsValid() const {
return frame_num >= 0 && render_process_id >= 0;
return frame_num >= 0 && render_view_host;
}
bool FrameNavigationState::FrameID::operator<(
const FrameNavigationState::FrameID& other) const {
return 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==(
const FrameNavigationState::FrameID& other) const {
return frame_num == other.frame_num &&
render_process_id == other.render_process_id;
render_view_host == other.render_view_host;
}
bool FrameNavigationState::FrameID::operator!=(
......@@ -91,10 +92,6 @@ void FrameNavigationState::TrackFrame(FrameID frame_id,
const GURL& url,
bool is_main_frame,
bool is_error_page) {
if (is_main_frame) {
frame_state_map_.clear();
frame_ids_.clear();
}
FrameState& frame_state = frame_state_map_[frame_id];
frame_state.error_occurred = is_error_page;
frame_state.url = url;
......@@ -102,12 +99,26 @@ void FrameNavigationState::TrackFrame(FrameID frame_id,
frame_state.is_navigating = true;
frame_state.is_committed = false;
frame_state.is_server_redirected = false;
if (is_main_frame) {
main_frame_id_ = 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) {
FrameIdToStateMap::iterator frame_state = frame_state_map_.find(frame_id);
if (frame_state == frame_state_map_.end()) {
......@@ -134,7 +145,10 @@ GURL FrameNavigationState::GetUrl(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 {
......@@ -168,6 +182,8 @@ bool FrameNavigationState::GetNavigationCompleted(FrameID frame_id) const {
void FrameNavigationState::SetNavigationCommitted(FrameID frame_id) {
DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
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 {
......
......@@ -11,6 +11,10 @@
#include "base/compiler_specific.h"
#include "googleurl/src/gurl.h"
namespace content {
class RenderViewHost;
}
namespace extensions {
// Tracks the navigation state of all frames in a given tab currently known to
......@@ -18,12 +22,10 @@ namespace extensions {
// occurred so no further events for this frame are being sent.
class FrameNavigationState {
public:
// A frame is uniquely identified by its frame ID and the render process ID.
// 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.
// A frame is uniquely identified by its frame ID and the RVH it's in.
struct FrameID {
FrameID();
FrameID(int64 frame_num, int render_process_id);
FrameID(int64 frame_num, content::RenderViewHost* render_view_host);
bool IsValid() const;
......@@ -32,7 +34,7 @@ class FrameNavigationState {
bool operator!=(const FrameID& other) const;
int64 frame_num;
int render_process_id;
content::RenderViewHost* render_view_host;
};
typedef std::set<FrameID>::const_iterator const_iterator;
......@@ -55,6 +57,9 @@ class FrameNavigationState {
bool is_main_frame,
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.
void UpdateFrame(FrameID frame_id, const GURL& url);
......@@ -64,11 +69,12 @@ class FrameNavigationState {
// Returns the URL corresponding to a tracked frame given by its |frame_id|.
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;
// Returns the frame ID of the main frame, or -1 if the frame ID is not
// known.
// Returns the frame ID of the last comitted main frame, or -1 if the frame
// ID is not known.
FrameID GetMainFrameID() const;
// Marks a frame as in an error state, i.e. the onErrorOccurred event was
......@@ -121,7 +127,7 @@ class FrameNavigationState {
// Set of all known frames.
std::set<FrameID> frame_ids_;
// The current main frame.
// The id of the last comitted main frame.
FrameID main_frame_id_;
// If true, also allow events from chrome-extension:// URLs.
......
......@@ -4,21 +4,20 @@
#include "base/values.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 "testing/gtest/include/gtest/gtest.h"
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
// goes away.
TEST_F(FrameNavigationStateTest, TrackFrame) {
TEST(FrameNavigationStateTest, TrackFrame) {
FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id1(23, 1);
const FrameNavigationState::FrameID frame_id2(42, 1);
const FrameNavigationState::FrameID frame_id1(23, fake_rvh);
const FrameNavigationState::FrameID frame_id2(42, fake_rvh);
const GURL url1("http://www.google.com/");
const GURL url2("http://mail.google.com/");
......@@ -26,6 +25,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id1));
navigation_state.TrackFrame(frame_id1, url1, true, false);
navigation_state.SetNavigationCommitted(frame_id1);
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_TRUE(navigation_state.IsValidFrame(frame_id1));
......@@ -33,6 +33,7 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
EXPECT_FALSE(navigation_state.IsValidFrame(frame_id2));
navigation_state.TrackFrame(frame_id2, url2, false, false);
navigation_state.SetNavigationCommitted(frame_id2);
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
EXPECT_TRUE(navigation_state.IsValidFrame(frame_id2));
......@@ -42,13 +43,20 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
EXPECT_FALSE(navigation_state.IsMainFrame(frame_id2));
EXPECT_EQ(url2, navigation_state.GetUrl(frame_id2));
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
// before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorState) {
TEST(FrameNavigationStateTest, ErrorState) {
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/");
navigation_state.TrackFrame(frame_id, url, true, false);
......@@ -73,10 +81,10 @@ TEST_F(FrameNavigationStateTest, ErrorState) {
// Tests that for a sub frame, no events are send after an error occurred, but
// before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
TEST(FrameNavigationStateTest, ErrorStateFrame) {
FrameNavigationState navigation_state;
const FrameNavigationState::FrameID frame_id1(23, 1);
const FrameNavigationState::FrameID frame_id2(42, 1);
const FrameNavigationState::FrameID frame_id1(23, fake_rvh);
const FrameNavigationState::FrameID frame_id2(42, fake_rvh);
const GURL url("http://www.google.com/");
navigation_state.TrackFrame(frame_id1, url, true, false);
......@@ -101,9 +109,9 @@ TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
}
// Tests that no events are send for a not web-safe scheme.
TEST_F(FrameNavigationStateTest, WebSafeScheme) {
TEST(FrameNavigationStateTest, WebSafeScheme) {
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/");
navigation_state.TrackFrame(frame_id, url, true, false);
......
......@@ -40,6 +40,8 @@ class WebNavigationTabObserver : public content::NotificationObserver,
return navigation_state_;
}
content::RenderViewHost* GetRenderViewHostInProcess(int process_id) const;
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
......@@ -97,6 +99,12 @@ class WebNavigationTabObserver : public content::NotificationObserver,
bool IsReferenceFragmentNavigation(FrameNavigationState::FrameID frame_id,
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.
FrameNavigationState navigation_state_;
......
......@@ -8,7 +8,7 @@ chrome.test.runTests([
chrome.tabs.create({"url": "about:blank"}, function(tab) {
tabId = tab.id;
var done = chrome.test.listenForever(
chrome.webNavigation.onBeforeNavigate,
chrome.webNavigation.onCommitted,
function (details) {
if (details.tabId != tabId)
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