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 "chrome/common/content_settings.h" 6 #include "chrome/common/render_messages.h" 7 #include "chrome/renderer/content_settings_observer.h" 8 #include "chrome/test/base/chrome_render_view_test.h" 9 #include "content/public/renderer/render_view.h" 10 #include "ipc/ipc_message_macros.h" 11 #include "testing/gmock/include/gmock/gmock.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "third_party/WebKit/public/web/WebView.h" 14 15 using testing::_; 16 using testing::DeleteArg; 17 18 namespace { 19 20 class MockContentSettingsObserver : public ContentSettingsObserver { 21 public: 22 explicit MockContentSettingsObserver(content::RenderFrame* render_frame); 23 24 virtual bool Send(IPC::Message* message); 25 26 MOCK_METHOD1(OnContentBlocked, 27 void(ContentSettingsType)); 28 29 MOCK_METHOD5(OnAllowDOMStorage, 30 void(int, const GURL&, const GURL&, bool, IPC::Message*)); 31 GURL image_url_; 32 std::string image_origin_; 33 }; 34 35 MockContentSettingsObserver::MockContentSettingsObserver( 36 content::RenderFrame* render_frame) 37 : ContentSettingsObserver(render_frame, NULL), 38 image_url_("http://www.foo.com/image.jpg"), 39 image_origin_("http://www.foo.com") { 40 } 41 42 bool MockContentSettingsObserver::Send(IPC::Message* message) { 43 IPC_BEGIN_MESSAGE_MAP(MockContentSettingsObserver, *message) 44 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ContentBlocked, OnContentBlocked) 45 IPC_MESSAGE_HANDLER_DELAY_REPLY(ChromeViewHostMsg_AllowDOMStorage, 46 OnAllowDOMStorage) 47 IPC_MESSAGE_UNHANDLED(ADD_FAILURE()) 48 IPC_END_MESSAGE_MAP() 49 50 // Our super class deletes the message. 51 return RenderFrameObserver::Send(message); 52 } 53 54 } // namespace 55 56 TEST_F(ChromeRenderViewTest, DidBlockContentType) { 57 MockContentSettingsObserver observer(view_->GetMainRenderFrame()); 58 EXPECT_CALL(observer, 59 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES)); 60 observer.DidBlockContentType(CONTENT_SETTINGS_TYPE_COOKIES); 61 62 // Blocking the same content type a second time shouldn't send a notification. 63 observer.DidBlockContentType(CONTENT_SETTINGS_TYPE_COOKIES); 64 ::testing::Mock::VerifyAndClearExpectations(&observer); 65 } 66 67 // Tests that multiple invokations of AllowDOMStorage result in a single IPC. 68 // Fails due to http://crbug.com/104300 69 TEST_F(ChromeRenderViewTest, DISABLED_AllowDOMStorage) { 70 // Load some HTML, so we have a valid security origin. 71 LoadHTML("<html></html>"); 72 MockContentSettingsObserver observer(view_->GetMainRenderFrame()); 73 ON_CALL(observer, 74 OnAllowDOMStorage(_, _, _, _, _)).WillByDefault(DeleteArg<4>()); 75 EXPECT_CALL(observer, 76 OnAllowDOMStorage(_, _, _, _, _)); 77 observer.allowStorage(true); 78 79 // Accessing localStorage from the same origin again shouldn't result in a 80 // new IPC. 81 observer.allowStorage(true); 82 ::testing::Mock::VerifyAndClearExpectations(&observer); 83 } 84 85 // Regression test for http://crbug.com/35011 86 TEST_F(ChromeRenderViewTest, JSBlockSentAfterPageLoad) { 87 // 1. Load page with JS. 88 std::string html = "<html>" 89 "<head>" 90 "<script>document.createElement('div');</script>" 91 "</head>" 92 "<body>" 93 "</body>" 94 "</html>"; 95 render_thread_->sink().ClearMessages(); 96 LoadHTML(html.c_str()); 97 98 // 2. Block JavaScript. 99 RendererContentSettingRules content_setting_rules; 100 ContentSettingsForOneType& script_setting_rules = 101 content_setting_rules.script_rules; 102 script_setting_rules.push_back( 103 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 104 ContentSettingsPattern::Wildcard(), 105 CONTENT_SETTING_BLOCK, 106 std::string(), 107 false)); 108 ContentSettingsObserver* observer = ContentSettingsObserver::Get( 109 view_->GetMainRenderFrame()); 110 observer->SetContentSettingRules(&content_setting_rules); 111 112 // Make sure no pending messages are in the queue. 113 ProcessPendingMessages(); 114 render_thread_->sink().ClearMessages(); 115 116 // 3. Reload page. 117 std::string url_str = "data:text/html;charset=utf-8,"; 118 url_str.append(html); 119 GURL url(url_str); 120 Reload(url); 121 ProcessPendingMessages(); 122 123 // 4. Verify that the notification that javascript was blocked is sent after 124 // the navigation notification is sent. 125 int navigation_index = -1; 126 int block_index = -1; 127 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) { 128 const IPC::Message* msg = render_thread_->sink().GetMessageAt(i); 129 if (msg->type() == GetNavigationIPCType()) 130 navigation_index = i; 131 if (msg->type() == ChromeViewHostMsg_ContentBlocked::ID) 132 block_index = i; 133 } 134 EXPECT_NE(-1, navigation_index); 135 EXPECT_NE(-1, block_index); 136 EXPECT_LT(navigation_index, block_index); 137 } 138 139 TEST_F(ChromeRenderViewTest, PluginsTemporarilyAllowed) { 140 // Load some HTML. 141 LoadHTML("<html>Foo</html>"); 142 143 std::string foo_plugin = "foo"; 144 std::string bar_plugin = "bar"; 145 146 ContentSettingsObserver* observer = 147 ContentSettingsObserver::Get(view_->GetMainRenderFrame()); 148 EXPECT_FALSE(observer->IsPluginTemporarilyAllowed(foo_plugin)); 149 150 // Temporarily allow the "foo" plugin. 151 observer->OnLoadBlockedPlugins(foo_plugin); 152 EXPECT_TRUE(observer->IsPluginTemporarilyAllowed(foo_plugin)); 153 EXPECT_FALSE(observer->IsPluginTemporarilyAllowed(bar_plugin)); 154 155 // Simulate a navigation within the page. 156 DidNavigateWithinPage(GetMainFrame(), true); 157 EXPECT_TRUE(observer->IsPluginTemporarilyAllowed(foo_plugin)); 158 EXPECT_FALSE(observer->IsPluginTemporarilyAllowed(bar_plugin)); 159 160 // Navigate to a different page. 161 LoadHTML("<html>Bar</html>"); 162 EXPECT_FALSE(observer->IsPluginTemporarilyAllowed(foo_plugin)); 163 EXPECT_FALSE(observer->IsPluginTemporarilyAllowed(bar_plugin)); 164 165 // Temporarily allow all plugins. 166 observer->OnLoadBlockedPlugins(std::string()); 167 EXPECT_TRUE(observer->IsPluginTemporarilyAllowed(foo_plugin)); 168 EXPECT_TRUE(observer->IsPluginTemporarilyAllowed(bar_plugin)); 169 } 170 171 TEST_F(ChromeRenderViewTest, ImagesBlockedByDefault) { 172 MockContentSettingsObserver mock_observer(view_->GetMainRenderFrame()); 173 174 // Load some HTML. 175 LoadHTML("<html>Foo</html>"); 176 177 // Set the default image blocking setting. 178 RendererContentSettingRules content_setting_rules; 179 ContentSettingsForOneType& image_setting_rules = 180 content_setting_rules.image_rules; 181 image_setting_rules.push_back( 182 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 183 ContentSettingsPattern::Wildcard(), 184 CONTENT_SETTING_BLOCK, 185 std::string(), 186 false)); 187 188 ContentSettingsObserver* observer = ContentSettingsObserver::Get( 189 view_->GetMainRenderFrame()); 190 observer->SetContentSettingRules(&content_setting_rules); 191 EXPECT_CALL(mock_observer, 192 OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES)); 193 EXPECT_FALSE(observer->allowImage(true, mock_observer.image_url_)); 194 ::testing::Mock::VerifyAndClearExpectations(&observer); 195 196 // Create an exception which allows the image. 197 image_setting_rules.insert( 198 image_setting_rules.begin(), 199 ContentSettingPatternSource( 200 ContentSettingsPattern::Wildcard(), 201 ContentSettingsPattern::FromString(mock_observer.image_origin_), 202 CONTENT_SETTING_ALLOW, 203 std::string(), 204 false)); 205 206 EXPECT_CALL( 207 mock_observer, 208 OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES)).Times(0); 209 EXPECT_TRUE(observer->allowImage(true, mock_observer.image_url_)); 210 ::testing::Mock::VerifyAndClearExpectations(&observer); 211 } 212 213 TEST_F(ChromeRenderViewTest, ImagesAllowedByDefault) { 214 MockContentSettingsObserver mock_observer(view_->GetMainRenderFrame()); 215 216 // Load some HTML. 217 LoadHTML("<html>Foo</html>"); 218 219 // Set the default image blocking setting. 220 RendererContentSettingRules content_setting_rules; 221 ContentSettingsForOneType& image_setting_rules = 222 content_setting_rules.image_rules; 223 image_setting_rules.push_back( 224 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 225 ContentSettingsPattern::Wildcard(), 226 CONTENT_SETTING_ALLOW, 227 std::string(), 228 false)); 229 230 ContentSettingsObserver* observer = 231 ContentSettingsObserver::Get(view_->GetMainRenderFrame()); 232 observer->SetContentSettingRules(&content_setting_rules); 233 EXPECT_CALL( 234 mock_observer, 235 OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES)).Times(0); 236 EXPECT_TRUE(observer->allowImage(true, mock_observer.image_url_)); 237 ::testing::Mock::VerifyAndClearExpectations(&observer); 238 239 // Create an exception which blocks the image. 240 image_setting_rules.insert( 241 image_setting_rules.begin(), 242 ContentSettingPatternSource( 243 ContentSettingsPattern::Wildcard(), 244 ContentSettingsPattern::FromString(mock_observer.image_origin_), 245 CONTENT_SETTING_BLOCK, 246 std::string(), 247 false)); 248 EXPECT_CALL(mock_observer, 249 OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES)); 250 EXPECT_FALSE(observer->allowImage(true, mock_observer.image_url_)); 251 ::testing::Mock::VerifyAndClearExpectations(&observer); 252 } 253 254 TEST_F(ChromeRenderViewTest, ContentSettingsBlockScripts) { 255 // Set the content settings for scripts. 256 RendererContentSettingRules content_setting_rules; 257 ContentSettingsForOneType& script_setting_rules = 258 content_setting_rules.script_rules; 259 script_setting_rules.push_back( 260 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 261 ContentSettingsPattern::Wildcard(), 262 CONTENT_SETTING_BLOCK, 263 std::string(), 264 false)); 265 266 ContentSettingsObserver* observer = 267 ContentSettingsObserver::Get(view_->GetMainRenderFrame()); 268 observer->SetContentSettingRules(&content_setting_rules); 269 270 // Load a page which contains a script. 271 std::string html = "<html>" 272 "<head>" 273 "<script src='data:foo'></script>" 274 "</head>" 275 "<body>" 276 "</body>" 277 "</html>"; 278 LoadHTML(html.c_str()); 279 280 // Verify that the script was blocked. 281 bool was_blocked = false; 282 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) { 283 const IPC::Message* msg = render_thread_->sink().GetMessageAt(i); 284 if (msg->type() == ChromeViewHostMsg_ContentBlocked::ID) 285 was_blocked = true; 286 } 287 EXPECT_TRUE(was_blocked); 288 } 289 290 TEST_F(ChromeRenderViewTest, ContentSettingsAllowScripts) { 291 // Set the content settings for scripts. 292 RendererContentSettingRules content_setting_rules; 293 ContentSettingsForOneType& script_setting_rules = 294 content_setting_rules.script_rules; 295 script_setting_rules.push_back( 296 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 297 ContentSettingsPattern::Wildcard(), 298 CONTENT_SETTING_ALLOW, 299 std::string(), 300 false)); 301 302 ContentSettingsObserver* observer = 303 ContentSettingsObserver::Get(view_->GetMainRenderFrame()); 304 observer->SetContentSettingRules(&content_setting_rules); 305 306 // Load a page which contains a script. 307 std::string html = "<html>" 308 "<head>" 309 "<script src='data:foo'></script>" 310 "</head>" 311 "<body>" 312 "</body>" 313 "</html>"; 314 LoadHTML(html.c_str()); 315 316 // Verify that the script was not blocked. 317 bool was_blocked = false; 318 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) { 319 const IPC::Message* msg = render_thread_->sink().GetMessageAt(i); 320 if (msg->type() == ChromeViewHostMsg_ContentBlocked::ID) 321 was_blocked = true; 322 } 323 EXPECT_FALSE(was_blocked); 324 } 325 326 TEST_F(ChromeRenderViewTest, ContentSettingsInterstitialPages) { 327 MockContentSettingsObserver mock_observer(view_->GetMainRenderFrame()); 328 // Block scripts. 329 RendererContentSettingRules content_setting_rules; 330 ContentSettingsForOneType& script_setting_rules = 331 content_setting_rules.script_rules; 332 script_setting_rules.push_back( 333 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 334 ContentSettingsPattern::Wildcard(), 335 CONTENT_SETTING_BLOCK, 336 std::string(), 337 false)); 338 // Block images. 339 ContentSettingsForOneType& image_setting_rules = 340 content_setting_rules.image_rules; 341 image_setting_rules.push_back( 342 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(), 343 ContentSettingsPattern::Wildcard(), 344 CONTENT_SETTING_BLOCK, 345 std::string(), 346 false)); 347 348 ContentSettingsObserver* observer = 349 ContentSettingsObserver::Get(view_->GetMainRenderFrame()); 350 observer->SetContentSettingRules(&content_setting_rules); 351 observer->OnSetAsInterstitial(); 352 353 // Load a page which contains a script. 354 std::string html = "<html>" 355 "<head>" 356 "<script src='data:foo'></script>" 357 "</head>" 358 "<body>" 359 "</body>" 360 "</html>"; 361 LoadHTML(html.c_str()); 362 363 // Verify that the script was allowed. 364 bool was_blocked = false; 365 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) { 366 const IPC::Message* msg = render_thread_->sink().GetMessageAt(i); 367 if (msg->type() == ChromeViewHostMsg_ContentBlocked::ID) 368 was_blocked = true; 369 } 370 EXPECT_FALSE(was_blocked); 371 372 // Verify that images are allowed. 373 EXPECT_CALL( 374 mock_observer, 375 OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES)).Times(0); 376 EXPECT_TRUE(observer->allowImage(true, mock_observer.image_url_)); 377 ::testing::Mock::VerifyAndClearExpectations(&observer); 378 } 379