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. 4 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/input_messages.h" 13#include "content/common/view_messages.h" 14#include "content/public/browser/browser_context.h" 15#include "content/public/browser/navigation_entry.h" 16#include "content/public/common/bindings_policy.h" 17#include "content/public/common/drop_data.h" 18#include "content/public/common/url_constants.h" 19#include "content/public/test/mock_render_process_host.h" 20#include "content/test/test_content_browser_client.h" 21#include "content/test/test_render_view_host.h" 22#include "content/test/test_web_contents.h" 23#include "net/base/filename_util.h" 24#include "third_party/WebKit/public/web/WebDragOperation.h" 25#include "ui/base/page_transition_types.h" 26 27namespace content { 28 29class RenderViewHostTestBrowserClient : public TestContentBrowserClient { 30 public: 31 RenderViewHostTestBrowserClient() {} 32 virtual ~RenderViewHostTestBrowserClient() {} 33 34 virtual bool IsHandledURL(const GURL& url) OVERRIDE { 35 return url.scheme() == url::kFileScheme; 36 } 37 38 private: 39 DISALLOW_COPY_AND_ASSIGN(RenderViewHostTestBrowserClient); 40}; 41 42class RenderViewHostTest : public RenderViewHostImplTestHarness { 43 public: 44 RenderViewHostTest() : old_browser_client_(NULL) {} 45 virtual ~RenderViewHostTest() {} 46 47 virtual void SetUp() OVERRIDE { 48 RenderViewHostImplTestHarness::SetUp(); 49 old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_); 50 } 51 52 virtual void TearDown() OVERRIDE { 53 SetBrowserClientForTesting(old_browser_client_); 54 RenderViewHostImplTestHarness::TearDown(); 55 } 56 57 private: 58 RenderViewHostTestBrowserClient test_browser_client_; 59 ContentBrowserClient* old_browser_client_; 60 61 DISALLOW_COPY_AND_ASSIGN(RenderViewHostTest); 62}; 63 64// All about URLs reported by the renderer should get rewritten to about:blank. 65// See RenderViewHost::OnNavigate for a discussion. 66TEST_F(RenderViewHostTest, FilterAbout) { 67 test_rvh()->SendNavigate(1, GURL("about:cache")); 68 ASSERT_TRUE(controller().GetVisibleEntry()); 69 EXPECT_EQ(GURL(url::kAboutBlankURL), 70 controller().GetVisibleEntry()->GetURL()); 71} 72 73// Create a full screen popup RenderWidgetHost and View. 74TEST_F(RenderViewHostTest, CreateFullscreenWidget) { 75 int routing_id = process()->GetNextRoutingID(); 76 test_rvh()->CreateNewFullscreenWidget(routing_id); 77} 78 79// Makes sure that the RenderViewHost is not waiting for an unload ack when 80// reloading a page. If this is not the case, when reloading, the contents may 81// get closed out even though the user pressed the reload button. 82TEST_F(RenderViewHostTest, ResetUnloadOnReload) { 83 const GURL url1("http://foo1"); 84 const GURL url2("http://foo2"); 85 86 // This test is for a subtle timing bug. Here's the sequence that triggered 87 // the bug: 88 // . go to a page. 89 // . go to a new page, preferably one that takes a while to resolve, such 90 // as one on a site that doesn't exist. 91 // . After this step IsWaitingForUnloadACK returns true on the first RVH. 92 // . click stop before the page has been commited. 93 // . click reload. 94 // . IsWaitingForUnloadACK still returns true, and if the hang monitor fires 95 // the contents gets closed. 96 97 NavigateAndCommit(url1); 98 controller().LoadURL( 99 url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); 100 // Simulate the ClosePage call which is normally sent by the net::URLRequest. 101 rvh()->ClosePage(); 102 // Needed so that navigations are not suspended on the RVH. 103 test_rvh()->SendBeforeUnloadACK(true); 104 contents()->Stop(); 105 controller().Reload(false); 106 EXPECT_FALSE(test_rvh()->IsWaitingForUnloadACK()); 107} 108 109// Ensure we do not grant bindings to a process shared with unprivileged views. 110TEST_F(RenderViewHostTest, DontGrantBindingsToSharedProcess) { 111 // Create another view in the same process. 112 scoped_ptr<TestWebContents> new_web_contents( 113 TestWebContents::Create(browser_context(), rvh()->GetSiteInstance())); 114 115 rvh()->AllowBindings(BINDINGS_POLICY_WEB_UI); 116 EXPECT_FALSE(rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI); 117} 118 119class MockDraggingRenderViewHostDelegateView 120 : public RenderViewHostDelegateView { 121 public: 122 virtual ~MockDraggingRenderViewHostDelegateView() {} 123 virtual void StartDragging(const DropData& drop_data, 124 blink::WebDragOperationsMask allowed_ops, 125 const gfx::ImageSkia& image, 126 const gfx::Vector2d& image_offset, 127 const DragEventSourceInfo& event_info) OVERRIDE { 128 drag_url_ = drop_data.url; 129 html_base_url_ = drop_data.html_base_url; 130 } 131 virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE {} 132 virtual void GotFocus() OVERRIDE {} 133 virtual void TakeFocus(bool reverse) OVERRIDE {} 134 virtual void UpdatePreferredSize(const gfx::Size& pref_size) {} 135 136 GURL drag_url() { 137 return drag_url_; 138 } 139 140 GURL html_base_url() { 141 return html_base_url_; 142 } 143 144 private: 145 GURL drag_url_; 146 GURL html_base_url_; 147}; 148 149TEST_F(RenderViewHostTest, StartDragging) { 150 TestWebContents* web_contents = contents(); 151 MockDraggingRenderViewHostDelegateView delegate_view; 152 web_contents->set_delegate_view(&delegate_view); 153 154 DropData drop_data; 155 GURL file_url = GURL("file:///home/user/secrets.txt"); 156 drop_data.url = file_url; 157 drop_data.html_base_url = file_url; 158 test_rvh()->TestOnStartDragging(drop_data); 159 EXPECT_EQ(GURL(url::kAboutBlankURL), delegate_view.drag_url()); 160 EXPECT_EQ(GURL(url::kAboutBlankURL), delegate_view.html_base_url()); 161 162 GURL http_url = GURL("http://www.domain.com/index.html"); 163 drop_data.url = http_url; 164 drop_data.html_base_url = http_url; 165 test_rvh()->TestOnStartDragging(drop_data); 166 EXPECT_EQ(http_url, delegate_view.drag_url()); 167 EXPECT_EQ(http_url, delegate_view.html_base_url()); 168 169 GURL https_url = GURL("https://www.domain.com/index.html"); 170 drop_data.url = https_url; 171 drop_data.html_base_url = https_url; 172 test_rvh()->TestOnStartDragging(drop_data); 173 EXPECT_EQ(https_url, delegate_view.drag_url()); 174 EXPECT_EQ(https_url, delegate_view.html_base_url()); 175 176 GURL javascript_url = GURL("javascript:alert('I am a bookmarklet')"); 177 drop_data.url = javascript_url; 178 drop_data.html_base_url = http_url; 179 test_rvh()->TestOnStartDragging(drop_data); 180 EXPECT_EQ(javascript_url, delegate_view.drag_url()); 181 EXPECT_EQ(http_url, delegate_view.html_base_url()); 182} 183 184TEST_F(RenderViewHostTest, DragEnteredFileURLsStillBlocked) { 185 DropData dropped_data; 186 gfx::Point client_point; 187 gfx::Point screen_point; 188 // We use "//foo/bar" path (rather than "/foo/bar") since dragged paths are 189 // expected to be absolute on any platforms. 190 base::FilePath highlighted_file_path(FILE_PATH_LITERAL("//tmp/foo.html")); 191 base::FilePath dragged_file_path(FILE_PATH_LITERAL("//tmp/image.jpg")); 192 base::FilePath sensitive_file_path(FILE_PATH_LITERAL("//etc/passwd")); 193 GURL highlighted_file_url = net::FilePathToFileURL(highlighted_file_path); 194 GURL dragged_file_url = net::FilePathToFileURL(dragged_file_path); 195 GURL sensitive_file_url = net::FilePathToFileURL(sensitive_file_path); 196 dropped_data.url = highlighted_file_url; 197 dropped_data.filenames.push_back( 198 ui::FileInfo(dragged_file_path, base::FilePath())); 199 200 rvh()->DragTargetDragEnter(dropped_data, client_point, screen_point, 201 blink::WebDragOperationNone, 0); 202 203 int id = process()->GetID(); 204 ChildProcessSecurityPolicyImpl* policy = 205 ChildProcessSecurityPolicyImpl::GetInstance(); 206 207 EXPECT_FALSE(policy->CanRequestURL(id, highlighted_file_url)); 208 EXPECT_FALSE(policy->CanReadFile(id, highlighted_file_path)); 209 EXPECT_TRUE(policy->CanRequestURL(id, dragged_file_url)); 210 EXPECT_TRUE(policy->CanReadFile(id, dragged_file_path)); 211 EXPECT_FALSE(policy->CanRequestURL(id, sensitive_file_url)); 212 EXPECT_FALSE(policy->CanReadFile(id, sensitive_file_path)); 213} 214 215TEST_F(RenderViewHostTest, MessageWithBadHistoryItemFiles) { 216 base::FilePath file_path; 217 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path)); 218 file_path = file_path.AppendASCII("foo"); 219 EXPECT_EQ(0, process()->bad_msg_count()); 220 test_rvh()->TestOnUpdateStateWithFile(-1, file_path); 221 EXPECT_EQ(1, process()->bad_msg_count()); 222 223 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 224 process()->GetID(), file_path); 225 test_rvh()->TestOnUpdateStateWithFile(-1, file_path); 226 EXPECT_EQ(1, process()->bad_msg_count()); 227} 228 229TEST_F(RenderViewHostTest, NavigationWithBadHistoryItemFiles) { 230 GURL url("http://www.google.com"); 231 base::FilePath file_path; 232 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path)); 233 file_path = file_path.AppendASCII("bar"); 234 EXPECT_EQ(0, process()->bad_msg_count()); 235 test_rvh()->SendNavigateWithFile(1, url, file_path); 236 EXPECT_EQ(1, process()->bad_msg_count()); 237 238 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 239 process()->GetID(), file_path); 240 test_rvh()->SendNavigateWithFile(process()->GetID(), url, file_path); 241 EXPECT_EQ(1, process()->bad_msg_count()); 242} 243 244TEST_F(RenderViewHostTest, RoutingIdSane) { 245 RenderFrameHostImpl* root_rfh = 246 contents()->GetFrameTree()->root()->current_frame_host(); 247 EXPECT_EQ(test_rvh()->GetProcess(), root_rfh->GetProcess()); 248 EXPECT_NE(test_rvh()->GetRoutingID(), root_rfh->routing_id()); 249} 250 251class TestSaveImageFromDataURL : public RenderMessageFilter { 252 public: 253 TestSaveImageFromDataURL( 254 BrowserContext* context) 255 : RenderMessageFilter( 256 0, 257 nullptr, 258 context, 259 context->GetRequestContext(), 260 nullptr, 261 nullptr, 262 nullptr, 263 nullptr) { 264 Reset(); 265 } 266 267 void Reset() { 268 url_string_ = std::string(); 269 is_downloaded_ = false; 270 } 271 272 std::string& UrlString() const { 273 return url_string_; 274 } 275 276 bool IsDownloaded() const { 277 return is_downloaded_; 278 } 279 280 void Test(const std::string& url) { 281 OnMessageReceived(ViewHostMsg_SaveImageFromDataURL(0, url)); 282 } 283 284 protected: 285 virtual ~TestSaveImageFromDataURL() { } 286 virtual void DownloadUrl(int render_view_id, 287 const GURL& url, 288 const Referrer& referrer, 289 const base::string16& suggested_name, 290 const bool use_prompt) const OVERRIDE { 291 url_string_ = url.spec(); 292 is_downloaded_ = true; 293 } 294 295 private: 296 mutable std::string url_string_; 297 mutable bool is_downloaded_; 298}; 299 300TEST_F(RenderViewHostTest, SaveImageFromDataURL) { 301 scoped_refptr<TestSaveImageFromDataURL> tester( 302 new TestSaveImageFromDataURL(browser_context())); 303 304 tester->Reset(); 305 tester->Test("http://non-data-url.com"); 306 EXPECT_EQ(tester->UrlString(), ""); 307 EXPECT_FALSE(tester->IsDownloaded()); 308 309 const std::string data_url = "data:image/gif;base64," 310 "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="; 311 312 tester->Reset(); 313 tester->Test(data_url); 314 EXPECT_EQ(tester->UrlString(), data_url); 315 EXPECT_TRUE(tester->IsDownloaded()); 316} 317 318} // namespace content 319