blob: 7dafab07f014ac438072cc6f5b3e1b40da5f30af [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/test_render_view_host.h"
#include "content/browser/web_contents/navigation_controller_impl.h"
#include "content/browser/web_contents/test_web_contents.h"
#include "content/common/view_messages.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/page_transition_types.h"
#include "content/test/mock_render_process_host.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
#include "webkit/glue/webdropdata.h"
using content::RenderViewHostImplTestHarness;
using content::TestWebContents;
class RenderViewHostTest : public RenderViewHostImplTestHarness {
};
// All about URLs reported by the renderer should get rewritten to about:blank.
// See RenderViewHost::OnMsgNavigate for a discussion.
TEST_F(RenderViewHostTest, FilterAbout) {
test_rvh()->SendNavigate(1, GURL("about:cache"));
ASSERT_TRUE(controller().GetActiveEntry());
EXPECT_EQ(GURL("about:blank"), controller().GetActiveEntry()->GetURL());
}
// Create a full screen popup RenderWidgetHost and View.
TEST_F(RenderViewHostTest, CreateFullscreenWidget) {
int routing_id = process()->GetNextRoutingID();
test_rvh()->CreateNewFullscreenWidget(routing_id);
}
// Makes sure that RenderViewHost::is_waiting_for_unload_ack_ is false when
// reloading a page. If is_waiting_for_unload_ack_ is not false when reloading
// the contents may get closed out even though the user pressed the reload
// button.
TEST_F(RenderViewHostTest, ResetUnloadOnReload) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
// This test is for a subtle timing bug. Here's the sequence that triggered
// the bug:
// . go to a page.
// . go to a new page, preferably one that takes a while to resolve, such
// as one on a site that doesn't exist.
// . After this step is_waiting_for_unload_ack_ has been set to true on
// the first RVH.
// . click stop before the page has been commited.
// . click reload.
// . is_waiting_for_unload_ack_ is still true, and the if the hang monitor
// fires the contents gets closed.
NavigateAndCommit(url1);
controller().LoadURL(
url2, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
// Simulate the ClosePage call which is normally sent by the net::URLRequest.
rvh()->ClosePage();
// Needed so that navigations are not suspended on the RVH.
test_rvh()->SendShouldCloseACK(true);
contents()->Stop();
controller().Reload(false);
EXPECT_FALSE(test_rvh()->is_waiting_for_unload_ack_for_testing());
}
// Ensure we do not grant bindings to a process shared with unprivileged views.
TEST_F(RenderViewHostTest, DontGrantBindingsToSharedProcess) {
// Create another view in the same process.
scoped_ptr<TestWebContents> new_web_contents(
new TestWebContents(browser_context(), rvh()->GetSiteInstance()));
rvh()->AllowBindings(content::BINDINGS_POLICY_WEB_UI);
EXPECT_FALSE(rvh()->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI);
}
class MockDraggingRenderViewHostDelegateView
: public content::RenderViewHostDelegate::View {
public:
virtual ~MockDraggingRenderViewHostDelegateView() {}
virtual void CreateNewWindow(
int route_id,
const ViewHostMsg_CreateWindow_Params& params) {}
virtual void CreateNewWidget(int route_id,
WebKit::WebPopupType popup_type) {}
virtual void CreateNewFullscreenWidget(int route_id) {}
virtual void ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {}
virtual void ShowCreatedWidget(int route_id,
const gfx::Rect& initial_pos) {}
virtual void ShowCreatedFullscreenWidget(int route_id) {}
virtual void ShowContextMenu(const content::ContextMenuParams& params) {}
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,
int selected_item,
const std::vector<WebMenuItem>& items,
bool right_aligned) {}
virtual void StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask allowed_ops,
const SkBitmap& image,
const gfx::Point& image_offset) {
drag_url_ = drop_data.url;
html_base_url_ = drop_data.html_base_url;
}
virtual void UpdateDragCursor(WebKit::WebDragOperation operation) {}
virtual void GotFocus() {}
virtual void TakeFocus(bool reverse) {}
virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
GURL drag_url() {
return drag_url_;
}
GURL html_base_url() {
return html_base_url_;
}
private:
GURL drag_url_;
GURL html_base_url_;
};
TEST_F(RenderViewHostTest, StartDragging) {
TestWebContents* web_contents = contents();
MockDraggingRenderViewHostDelegateView view_delegate;
web_contents->set_view_delegate(&view_delegate);
WebDropData drop_data;
GURL file_url = GURL("file:///home/user/secrets.txt");
drop_data.url = file_url;
drop_data.html_base_url = file_url;
test_rvh()->TestOnMsgStartDragging(drop_data);
EXPECT_EQ(GURL("about:blank"), view_delegate.drag_url());
EXPECT_EQ(GURL("about:blank"), view_delegate.html_base_url());
GURL http_url = GURL("http://www.domain.com/index.html");
drop_data.url = http_url;
drop_data.html_base_url = http_url;
test_rvh()->TestOnMsgStartDragging(drop_data);
EXPECT_EQ(http_url, view_delegate.drag_url());
EXPECT_EQ(http_url, view_delegate.html_base_url());
GURL https_url = GURL("https://www.domain.com/index.html");
drop_data.url = https_url;
drop_data.html_base_url = https_url;
test_rvh()->TestOnMsgStartDragging(drop_data);
EXPECT_EQ(https_url, view_delegate.drag_url());
EXPECT_EQ(https_url, view_delegate.html_base_url());
GURL javascript_url = GURL("javascript:alert('I am a bookmarklet')");
drop_data.url = javascript_url;
drop_data.html_base_url = http_url;
test_rvh()->TestOnMsgStartDragging(drop_data);
EXPECT_EQ(javascript_url, view_delegate.drag_url());
EXPECT_EQ(http_url, view_delegate.html_base_url());
}
TEST_F(RenderViewHostTest, DragEnteredFileURLsStillBlocked) {
WebDropData dropped_data;
gfx::Point client_point;
gfx::Point screen_point;
GURL file_url = GURL("file:///etc/passwd");
dropped_data.url = file_url;
rvh()->DragTargetDragEnter(dropped_data, client_point, screen_point,
WebKit::WebDragOperationNone);
EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
process()->GetID(), file_url));
}
// The test that follow trigger DCHECKS in debug build.
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
// Test that when we fail to de-serialize a message, RenderViewHost calls the
// ReceivedBadMessage() handler.
TEST_F(RenderViewHostTest, BadMessageHandlerRenderViewHost) {
EXPECT_EQ(0, process()->bad_msg_count());
// craft an incorrect ViewHostMsg_UpdateTargetURL message. The real one has
// two payload items but the one we construct has none.
IPC::Message message(0, ViewHostMsg_UpdateTargetURL::ID,
IPC::Message::PRIORITY_NORMAL);
test_rvh()->OnMessageReceived(message);
EXPECT_EQ(1, process()->bad_msg_count());
}
// Test that when we fail to de-serialize a message, RenderWidgetHost calls the
// ReceivedBadMessage() handler.
TEST_F(RenderViewHostTest, BadMessageHandlerRenderWidgetHost) {
EXPECT_EQ(0, process()->bad_msg_count());
// craft an incorrect ViewHostMsg_UpdateRect message. The real one has
// one payload item but the one we construct has none.
IPC::Message message(0, ViewHostMsg_UpdateRect::ID,
IPC::Message::PRIORITY_NORMAL);
test_rvh()->OnMessageReceived(message);
EXPECT_EQ(1, process()->bad_msg_count());
}
// Test that OnMsgInputEventAck() detects bad messages.
TEST_F(RenderViewHostTest, BadMessageHandlerInputEventAck) {
EXPECT_EQ(0, process()->bad_msg_count());
// ViewHostMsg_HandleInputEvent_ACK is defined taking 0 params but
// the code actually expects it to have at least one int para, this this
// bogus message will not fail at de-serialization but should fail in
// OnMsgInputEventAck() processing.
IPC::Message message(0, ViewHostMsg_HandleInputEvent_ACK::ID,
IPC::Message::PRIORITY_NORMAL);
test_rvh()->OnMessageReceived(message);
EXPECT_EQ(1, process()->bad_msg_count());
}
#endif