1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/path_service.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/child_process_security_policy_impl.h"
8 #include "content/browser/frame_host/render_frame_host_impl.h"
9 #include "content/browser/renderer_host/render_message_filter.h"
10 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
11 #include "content/browser/renderer_host/render_widget_helper.h"
12 #include "content/common/frame_messages.h"
13 #include "content/common/input_messages.h"
14 #include "content/common/view_messages.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/common/bindings_policy.h"
18 #include "content/public/common/drop_data.h"
19 #include "content/public/common/url_constants.h"
20 #include "content/public/test/mock_render_process_host.h"
21 #include "content/test/test_content_browser_client.h"
22 #include "content/test/test_render_view_host.h"
23 #include "content/test/test_web_contents.h"
24 #include "net/base/filename_util.h"
25 #include "third_party/WebKit/public/web/WebDragOperation.h"
26 #include "ui/base/page_transition_types.h"
30 class RenderViewHostTestBrowserClient
: public TestContentBrowserClient
{
32 RenderViewHostTestBrowserClient() {}
33 ~RenderViewHostTestBrowserClient() override
{}
35 bool IsHandledURL(const GURL
& url
) override
{
36 return url
.scheme() == url::kFileScheme
;
40 DISALLOW_COPY_AND_ASSIGN(RenderViewHostTestBrowserClient
);
43 class RenderViewHostTest
: public RenderViewHostImplTestHarness
{
45 RenderViewHostTest() : old_browser_client_(NULL
) {}
46 ~RenderViewHostTest() override
{}
48 void SetUp() override
{
49 RenderViewHostImplTestHarness::SetUp();
50 old_browser_client_
= SetBrowserClientForTesting(&test_browser_client_
);
53 void TearDown() override
{
54 SetBrowserClientForTesting(old_browser_client_
);
55 RenderViewHostImplTestHarness::TearDown();
59 RenderViewHostTestBrowserClient test_browser_client_
;
60 ContentBrowserClient
* old_browser_client_
;
62 DISALLOW_COPY_AND_ASSIGN(RenderViewHostTest
);
65 // All about URLs reported by the renderer should get rewritten to about:blank.
66 // See RenderViewHost::OnNavigate for a discussion.
67 TEST_F(RenderViewHostTest
, FilterAbout
) {
68 main_test_rfh()->NavigateAndCommitRendererInitiated(
69 1, true, GURL("about:cache"));
70 ASSERT_TRUE(controller().GetVisibleEntry());
71 EXPECT_EQ(GURL(url::kAboutBlankURL
),
72 controller().GetVisibleEntry()->GetURL());
75 // Create a full screen popup RenderWidgetHost and View.
76 TEST_F(RenderViewHostTest
, CreateFullscreenWidget
) {
77 int routing_id
= process()->GetNextRoutingID();
78 test_rvh()->CreateNewFullscreenWidget(routing_id
);
81 // Makes sure that the RenderViewHost is not waiting for an unload ack when
82 // reloading a page. If this is not the case, when reloading, the contents may
83 // get closed out even though the user pressed the reload button.
84 TEST_F(RenderViewHostTest
, ResetUnloadOnReload
) {
85 const GURL
url1("http://foo1");
86 const GURL
url2("http://foo2");
88 // This test is for a subtle timing bug. Here's the sequence that triggered
91 // . go to a new page, preferably one that takes a while to resolve, such
92 // as one on a site that doesn't exist.
93 // . After this step IsWaitingForUnloadACK returns true on the first RVH.
94 // . click stop before the page has been commited.
96 // . IsWaitingForUnloadACK still returns true, and if the hang monitor fires
97 // the contents gets closed.
99 NavigateAndCommit(url1
);
100 controller().LoadURL(
101 url2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
102 // Simulate the ClosePage call which is normally sent by the net::URLRequest.
103 test_rvh()->ClosePage();
104 // Needed so that navigations are not suspended on the RFH.
105 main_test_rfh()->SendBeforeUnloadACK(true);
107 controller().Reload(false);
108 EXPECT_FALSE(main_test_rfh()->IsWaitingForUnloadACK());
111 // Ensure we do not grant bindings to a process shared with unprivileged views.
112 TEST_F(RenderViewHostTest
, DontGrantBindingsToSharedProcess
) {
113 // Create another view in the same process.
114 scoped_ptr
<TestWebContents
> new_web_contents(
115 TestWebContents::Create(browser_context(), rvh()->GetSiteInstance()));
117 rvh()->AllowBindings(BINDINGS_POLICY_WEB_UI
);
118 EXPECT_FALSE(rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
121 class MockDraggingRenderViewHostDelegateView
122 : public RenderViewHostDelegateView
{
124 ~MockDraggingRenderViewHostDelegateView() override
{}
125 void StartDragging(const DropData
& drop_data
,
126 blink::WebDragOperationsMask allowed_ops
,
127 const gfx::ImageSkia
& image
,
128 const gfx::Vector2d
& image_offset
,
129 const DragEventSourceInfo
& event_info
) override
{
130 drag_url_
= drop_data
.url
;
131 html_base_url_
= drop_data
.html_base_url
;
133 void UpdateDragCursor(blink::WebDragOperation operation
) override
{}
134 void GotFocus() override
{}
135 void TakeFocus(bool reverse
) override
{}
136 virtual void UpdatePreferredSize(const gfx::Size
& pref_size
) {}
142 GURL
html_base_url() {
143 return html_base_url_
;
151 TEST_F(RenderViewHostTest
, StartDragging
) {
152 TestWebContents
* web_contents
= contents();
153 MockDraggingRenderViewHostDelegateView delegate_view
;
154 web_contents
->set_delegate_view(&delegate_view
);
157 GURL file_url
= GURL("file:///home/user/secrets.txt");
158 drop_data
.url
= file_url
;
159 drop_data
.html_base_url
= file_url
;
160 test_rvh()->TestOnStartDragging(drop_data
);
161 EXPECT_EQ(GURL(url::kAboutBlankURL
), delegate_view
.drag_url());
162 EXPECT_EQ(GURL(url::kAboutBlankURL
), delegate_view
.html_base_url());
164 GURL http_url
= GURL("http://www.domain.com/index.html");
165 drop_data
.url
= http_url
;
166 drop_data
.html_base_url
= http_url
;
167 test_rvh()->TestOnStartDragging(drop_data
);
168 EXPECT_EQ(http_url
, delegate_view
.drag_url());
169 EXPECT_EQ(http_url
, delegate_view
.html_base_url());
171 GURL https_url
= GURL("https://www.domain.com/index.html");
172 drop_data
.url
= https_url
;
173 drop_data
.html_base_url
= https_url
;
174 test_rvh()->TestOnStartDragging(drop_data
);
175 EXPECT_EQ(https_url
, delegate_view
.drag_url());
176 EXPECT_EQ(https_url
, delegate_view
.html_base_url());
178 GURL javascript_url
= GURL("javascript:alert('I am a bookmarklet')");
179 drop_data
.url
= javascript_url
;
180 drop_data
.html_base_url
= http_url
;
181 test_rvh()->TestOnStartDragging(drop_data
);
182 EXPECT_EQ(javascript_url
, delegate_view
.drag_url());
183 EXPECT_EQ(http_url
, delegate_view
.html_base_url());
186 TEST_F(RenderViewHostTest
, DragEnteredFileURLsStillBlocked
) {
187 DropData dropped_data
;
188 gfx::Point client_point
;
189 gfx::Point screen_point
;
190 // We use "//foo/bar" path (rather than "/foo/bar") since dragged paths are
191 // expected to be absolute on any platforms.
192 base::FilePath
highlighted_file_path(FILE_PATH_LITERAL("//tmp/foo.html"));
193 base::FilePath
dragged_file_path(FILE_PATH_LITERAL("//tmp/image.jpg"));
194 base::FilePath
sensitive_file_path(FILE_PATH_LITERAL("//etc/passwd"));
195 GURL highlighted_file_url
= net::FilePathToFileURL(highlighted_file_path
);
196 GURL dragged_file_url
= net::FilePathToFileURL(dragged_file_path
);
197 GURL sensitive_file_url
= net::FilePathToFileURL(sensitive_file_path
);
198 dropped_data
.url
= highlighted_file_url
;
199 dropped_data
.filenames
.push_back(
200 ui::FileInfo(dragged_file_path
, base::FilePath()));
202 rvh()->DragTargetDragEnter(dropped_data
, client_point
, screen_point
,
203 blink::WebDragOperationNone
, 0);
205 int id
= process()->GetID();
206 ChildProcessSecurityPolicyImpl
* policy
=
207 ChildProcessSecurityPolicyImpl::GetInstance();
209 EXPECT_FALSE(policy
->CanRequestURL(id
, highlighted_file_url
));
210 EXPECT_FALSE(policy
->CanReadFile(id
, highlighted_file_path
));
211 EXPECT_TRUE(policy
->CanRequestURL(id
, dragged_file_url
));
212 EXPECT_TRUE(policy
->CanReadFile(id
, dragged_file_path
));
213 EXPECT_FALSE(policy
->CanRequestURL(id
, sensitive_file_url
));
214 EXPECT_FALSE(policy
->CanReadFile(id
, sensitive_file_path
));
217 TEST_F(RenderViewHostTest
, MessageWithBadHistoryItemFiles
) {
218 base::FilePath file_path
;
219 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file_path
));
220 file_path
= file_path
.AppendASCII("foo");
221 EXPECT_EQ(0, process()->bad_msg_count());
222 test_rvh()->TestOnUpdateStateWithFile(-1, file_path
);
223 EXPECT_EQ(1, process()->bad_msg_count());
225 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
226 process()->GetID(), file_path
);
227 test_rvh()->TestOnUpdateStateWithFile(-1, file_path
);
228 EXPECT_EQ(1, process()->bad_msg_count());
232 void SetBadFilePath(const GURL
& url
,
233 const base::FilePath
& file_path
,
234 FrameHostMsg_DidCommitProvisionalLoad_Params
* params
) {
236 PageState::CreateForTesting(url
, false, "data", &file_path
);
240 TEST_F(RenderViewHostTest
, NavigationWithBadHistoryItemFiles
) {
241 GURL
url("http://www.google.com");
242 base::FilePath file_path
;
243 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file_path
));
244 file_path
= file_path
.AppendASCII("bar");
245 auto set_bad_file_path_callback
= base::Bind(SetBadFilePath
, url
, file_path
);
247 EXPECT_EQ(0, process()->bad_msg_count());
248 main_test_rfh()->SendRendererInitiatedNavigationRequest(url
, false);
249 main_test_rfh()->PrepareForCommit();
250 contents()->GetMainFrame()->SendNavigateWithModificationCallback(
251 1, 1, true, url
, set_bad_file_path_callback
);
252 EXPECT_EQ(1, process()->bad_msg_count());
254 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
255 process()->GetID(), file_path
);
256 main_test_rfh()->SendRendererInitiatedNavigationRequest(url
, false);
257 main_test_rfh()->PrepareForCommit();
258 contents()->GetMainFrame()->SendNavigateWithModificationCallback(
259 2, 2, true, url
, set_bad_file_path_callback
);
260 EXPECT_EQ(1, process()->bad_msg_count());
263 TEST_F(RenderViewHostTest
, RoutingIdSane
) {
264 RenderFrameHostImpl
* root_rfh
=
265 contents()->GetFrameTree()->root()->current_frame_host();
266 EXPECT_EQ(contents()->GetMainFrame(), root_rfh
);
267 EXPECT_EQ(test_rvh()->GetProcess(), root_rfh
->GetProcess());
268 EXPECT_NE(test_rvh()->GetRoutingID(), root_rfh
->routing_id());
271 class TestSaveImageFromDataURL
: public RenderMessageFilter
{
273 TestSaveImageFromDataURL(
274 BrowserContext
* context
)
275 : RenderMessageFilter(
279 context
->GetRequestContext(),
288 url_string_
= std::string();
289 is_downloaded_
= false;
292 std::string
& UrlString() const {
296 bool IsDownloaded() const {
297 return is_downloaded_
;
300 void Test(const std::string
& url
) {
301 OnMessageReceived(ViewHostMsg_SaveImageFromDataURL(0, url
));
305 ~TestSaveImageFromDataURL() override
{}
306 void DownloadUrl(int render_view_id
,
308 const Referrer
& referrer
,
309 const base::string16
& suggested_name
,
310 const bool use_prompt
) const override
{
311 url_string_
= url
.spec();
312 is_downloaded_
= true;
316 mutable std::string url_string_
;
317 mutable bool is_downloaded_
;
320 TEST_F(RenderViewHostTest
, SaveImageFromDataURL
) {
321 scoped_refptr
<TestSaveImageFromDataURL
> tester(
322 new TestSaveImageFromDataURL(browser_context()));
325 tester
->Test("http://non-data-url.com");
326 EXPECT_EQ(tester
->UrlString(), "");
327 EXPECT_FALSE(tester
->IsDownloaded());
329 const std::string data_url
= "data:image/gif;base64,"
330 "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
333 tester
->Test(data_url
);
334 EXPECT_EQ(tester
->UrlString(), data_url
);
335 EXPECT_TRUE(tester
->IsDownloaded());
338 } // namespace content