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 "components/content_settings/core/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
15using testing::_;
16using testing::DeleteArg;
17
18namespace {
19
20class 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
35MockContentSettingsObserver::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
42bool 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
56TEST_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
69TEST_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
86TEST_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
139TEST_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
171TEST_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
213TEST_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
254TEST_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
290TEST_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
326TEST_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