summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authoralexmos <alexmos@chromium.org>2015-04-27 10:59:56 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-27 18:00:52 +0000
commita7a4ff82f6f78186faf446e1db4d1443c8496371 (patch)
treed94a3a86a1c467ebabd3645724c413acde202884 /content
parent0becb33779f8678e2703d6ff1a73ce2b45571f98 (diff)
downloadchromium_src-a7a4ff82f6f78186faf446e1db4d1443c8496371.zip
chromium_src-a7a4ff82f6f78186faf446e1db4d1443c8496371.tar.gz
chromium_src-a7a4ff82f6f78186faf446e1db4d1443c8496371.tar.bz2
Send origin updates to frame proxies when a frame navigates to new origin.
One current use for this is to ensure that cross-domain access error messages (see https://crbug.com/478254) show the latest origin for RemoteFrames. BUG=426512, 478254 Review URL: https://codereview.chromium.org/1098763003 Cr-Commit-Position: refs/heads/master@{#327068}
Diffstat (limited to 'content')
-rw-r--r--content/browser/frame_host/frame_tree_node.cc11
-rw-r--r--content/browser/frame_host/frame_tree_node.h6
-rw-r--r--content/browser/frame_host/navigator_impl.cc2
-rw-r--r--content/browser/frame_host/render_frame_host_manager.cc11
-rw-r--r--content/browser/frame_host/render_frame_host_manager.h5
-rw-r--r--content/browser/site_per_process_browsertest.cc107
-rw-r--r--content/common/frame_messages.h4
-rw-r--r--content/common/frame_replication_state.h33
-rw-r--r--content/renderer/render_frame_proxy.cc6
-rw-r--r--content/renderer/render_frame_proxy.h2
-rw-r--r--content/test/data/frame_tree/page_with_two_frames.html4
11 files changed, 179 insertions, 12 deletions
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 1567980..cabc819 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -135,11 +135,16 @@ void FrameTreeNode::ResetForNewProcess() {
old_children.clear(); // May notify observers.
}
+void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
+ if (!origin.IsSameAs(replication_state_.origin))
+ render_manager_.OnDidUpdateOrigin(origin);
+ replication_state_.origin = origin;
+}
+
void FrameTreeNode::SetFrameName(const std::string& name) {
+ if (name != replication_state_.name)
+ render_manager_.OnDidUpdateName(name);
replication_state_.name = name;
-
- // Notify this frame's proxies about the updated name.
- render_manager_.OnDidUpdateName(name);
}
bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index 7e1add1..bcb7780 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -93,10 +93,10 @@ class CONTENT_EXPORT FrameTreeNode {
current_url_ = url;
}
- void set_current_origin(const url::Origin& origin) {
- replication_state_.origin = origin;
- }
+ // Set the current origin and notify proxies about the update.
+ void SetCurrentOrigin(const url::Origin& origin);
+ // Set the current name and notify proxies about the update.
void SetFrameName(const std::string& name);
SandboxFlags effective_sandbox_flags() { return effective_sandbox_flags_; }
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index a00f9723d..1f9a3b3 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -414,7 +414,7 @@ void NavigatorImpl::DidNavigate(
// origin because it creates a RenderFrameProxy that needs this to initialize
// its security context. This origin will also be sent to RenderFrameProxies
// created via ViewMsg_New and FrameMsg_NewFrameProxy.
- render_frame_host->frame_tree_node()->set_current_origin(params.origin);
+ render_frame_host->frame_tree_node()->SetCurrentOrigin(params.origin);
// When using --site-per-process, we notify the RFHM for all navigations,
// not just main frame navigations.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index e4edb08..c9eadcd 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -889,6 +889,17 @@ void RenderFrameHostManager::OnDidUpdateName(const std::string& name) {
}
}
+void RenderFrameHostManager::OnDidUpdateOrigin(const url::Origin& origin) {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ for (const auto& pair : proxy_hosts_) {
+ pair.second->Send(
+ new FrameMsg_DidUpdateOrigin(pair.second->GetRoutingID(), origin));
+ }
+}
+
void RenderFrameHostManager::Observe(
int type,
const NotificationSource& source,
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index f8004d9..086dea5 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -19,6 +19,7 @@
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/referrer.h"
#include "ui/base/page_transition_types.h"
+#include "url/origin.h"
namespace content {
class BrowserContext;
@@ -417,6 +418,10 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// window.name property.
void OnDidUpdateName(const std::string& name);
+ // Send updated origin to all frame proxies when the frame navigates to a new
+ // origin.
+ void OnDidUpdateOrigin(const url::Origin& origin);
+
void EnsureRenderViewInitialized(FrameTreeNode* source,
RenderViewHostImpl* render_view_host,
SiteInstance* instance);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 4bf3a50..a078c4d 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -163,6 +163,58 @@ void RenderFrameHostCreatedObserver::RenderFrameCreated(
}
}
+// A WebContentsDelegate that catches messages sent to the console.
+class ConsoleObserverDelegate : public WebContentsDelegate {
+ public:
+ ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
+ : web_contents_(web_contents),
+ filter_(filter),
+ message_(""),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ ~ConsoleObserverDelegate() override {}
+
+ bool AddMessageToConsole(WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) override;
+
+ std::string message() { return message_; }
+
+ void Wait();
+
+ private:
+ WebContents* web_contents_;
+ std::string filter_;
+ std::string message_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
+};
+
+void ConsoleObserverDelegate::Wait() {
+ message_loop_runner_->Run();
+}
+
+bool ConsoleObserverDelegate::AddMessageToConsole(
+ WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) {
+ DCHECK(source == web_contents_);
+
+ std::string ascii_message = base::UTF16ToASCII(message);
+ if (MatchPattern(ascii_message, filter_)) {
+ message_ = ascii_message;
+ message_loop_runner_->Quit();
+ }
+ return false;
+}
+
//
// SitePerProcessBrowserTest
//
@@ -1786,6 +1838,61 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
EXPECT_EQ(foo_url, root->child_at(0)->current_url());
}
+// Verify that when a frame is navigated to a new origin, the origin update
+// propagates to the frame's proxies.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://bar.com/",
+ DepictFrameTree(root));
+
+ // Navigate second subframe to a baz.com. This should send an origin update
+ // to the frame's proxy in the bar.com (first frame's) process.
+ GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(1), frame_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(frame_url, observer.last_navigation_url());
+
+ // The first frame can't directly observe the second frame's origin with
+ // JavaScript. Instead, try to navigate the second frame from the first
+ // frame. This should fail with a console error message, which should
+ // contain the second frame's updated origin (see blink::Frame::canNavigate).
+ scoped_ptr<ConsoleObserverDelegate> console_delegate(
+ new ConsoleObserverDelegate(
+ shell()->web_contents(),
+ "Unsafe JavaScript attempt to initiate navigation*"));
+ shell()->web_contents()->SetDelegate(console_delegate.get());
+
+ // frames[1] can't be used due to a bug where RemoteFrames are created out of
+ // order (https://crbug.com/478792). Instead, target second frame by name.
+ EXPECT_TRUE(ExecuteScript(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
+ console_delegate->Wait();
+
+ std::string frame_origin =
+ root->child_at(1)->current_replication_state().origin.string();
+ EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
+ EXPECT_TRUE(
+ MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
+ << "Error message does not contain the frame's latest origin ("
+ << frame_origin << ")";
+}
+
// Ensure that navigating subframes in --site-per-process mode properly fires
// the DidStopLoading event on WebContentsObserver.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 32052df..70870ab 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -534,6 +534,10 @@ IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateSandboxFlags, content::SandboxFlags)
// changed in another process.
IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateName, std::string /* name */)
+// Update a proxy's replicated origin. Used when the frame is navigated to a
+// new origin.
+IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateOrigin, url::Origin /* origin */)
+
// Send to the RenderFrame to set text track style settings.
// Sent for top-level frames.
IPC_MESSAGE_ROUTED1(FrameMsg_SetTextTrackSettings,
diff --git a/content/common/frame_replication_state.h b/content/common/frame_replication_state.h
index f6cfa94..77ec859 100644
--- a/content/common/frame_replication_state.h
+++ b/content/common/frame_replication_state.h
@@ -48,15 +48,42 @@ struct CONTENT_EXPORT FrameReplicationState {
FrameReplicationState(const std::string& name);
~FrameReplicationState();
- // Current serialized security origin of the frame. Unique origins are
- // represented as the string "null" per RFC 6454.
+ // Current serialized security origin of the frame. Unique origins are
+ // represented as the string "null" per RFC 6454. This field is updated
+ // whenever a frame navigation commits.
+ //
+ // TODO(alexmos): For now, |origin| updates are immediately sent to all frame
+ // proxies when in --site-per-process mode. This isn't ideal, since Blink
+ // typically needs a proxy's origin only when performing security checks on
+ // the ancestors of a local frame. So, as a future improvement, we could
+ // delay sending origin updates to proxies until they have a local descendant
+ // (if ever). This would reduce leaking a user's browsing history into a
+ // compromized renderer.
url::Origin origin;
- // Current sandbox flags of the frame.
+ // Current sandbox flags of the frame. |sandbox_flags| are initialized for
+ // new child frames using the value of the <iframe> element's "sandbox"
+ // attribute. They are updated dynamically whenever a parent frame updates an
+ // <iframe>'s sandbox attribute via JavaScript.
+ //
+ // Updates to |sandbox_flags| are sent to proxies, but only after a
+ // subsequent navigation of the (sandboxed) frame, since the flags only take
+ // effect on navigation (see also FrameTreeNode::effective_sandbox_flags_).
+ // The proxies need updated flags so that they can be inherited properly if a
+ // proxy ever becomes a parent of a local frame.
SandboxFlags sandbox_flags;
// The assigned name of the frame. This name can be empty, unlike the unique
// name generated internally in the DOM tree.
+ //
+ // |name| is set when a new child frame is created using the value of the
+ // <iframe> element's "name" attribute (see
+ // RenderFrameHostImpl::OnCreateChildFrame), and it is updated dynamically
+ // whenever a frame sets its window.name.
+ //
+ // |name| updates are immediately sent to all frame proxies (when in
+ // --site-per-process mode), so that other frames can look up or navigate a
+ // frame using its updated name (e.g., using window.open(url, frame_name)).
std::string name;
// TODO(alexmos): Eventually, this structure can also hold other state that
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index f433733..558c391 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -211,6 +211,7 @@ bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags)
IPC_MESSAGE_HANDLER(FrameMsg_DispatchLoad, OnDispatchLoad)
IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateName, OnDidUpdateName)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -303,6 +304,11 @@ void RenderFrameProxy::OnDidUpdateName(const std::string& name) {
web_frame_->setReplicatedName(blink::WebString::fromUTF8(name));
}
+void RenderFrameProxy::OnDidUpdateOrigin(const url::Origin& origin) {
+ web_frame_->setReplicatedOrigin(blink::WebSecurityOrigin::createFromString(
+ blink::WebString::fromUTF8(origin.string())));
+}
+
void RenderFrameProxy::frameDetached() {
if (web_frame_->parent()) {
web_frame_->parent()->removeChild(web_frame_);
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 19a94f6..fba8c9a 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -12,6 +12,7 @@
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebRemoteFrame.h"
#include "third_party/WebKit/public/web/WebRemoteFrameClient.h"
+#include "url/origin.h"
struct FrameMsg_BuffersSwapped_Params;
struct FrameMsg_CompositorFrameSwapped_Params;
@@ -144,6 +145,7 @@ class CONTENT_EXPORT RenderFrameProxy
void OnDidUpdateSandboxFlags(SandboxFlags flags);
void OnDispatchLoad();
void OnDidUpdateName(const std::string& name);
+ void OnDidUpdateOrigin(const url::Origin& origin);
// The routing ID by which this RenderFrameProxy is known.
const int routing_id_;
diff --git a/content/test/data/frame_tree/page_with_two_frames.html b/content/test/data/frame_tree/page_with_two_frames.html
index 3313ce4..c6323ad 100644
--- a/content/test/data/frame_tree/page_with_two_frames.html
+++ b/content/test/data/frame_tree/page_with_two_frames.html
@@ -3,8 +3,8 @@
</head>
<body>
This page has two iframes: one is cross-site, the other is same-site.
- <iframe src="/cross-site/bar.com/title1.html"></iframe>
- <iframe src="../title1.html"></iframe>
+ <iframe name="frame1" src="/cross-site/bar.com/title1.html"></iframe>
+ <iframe name="frame2" src="../title1.html"></iframe>
</body>
</html>