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/browser/content_settings/content_settings_utils.h"
6
7#include <vector>
8
9#include "base/command_line.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/scoped_vector.h"
13#include "base/strings/string_split.h"
14#include "base/values.h"
15#include "chrome/browser/content_settings/host_content_settings_map.h"
16#include "chrome/common/chrome_switches.h"
17#include "components/content_settings/core/browser/content_settings_provider.h"
18#include "components/content_settings/core/browser/content_settings_rule.h"
19#include "components/content_settings/core/common/content_settings_pattern.h"
20#include "url/gurl.h"
21
22namespace {
23
24// The names of the ContentSettingsType values, for use with dictionary prefs.
25const char* kTypeNames[] = {
26  "cookies",
27  "images",
28  "javascript",
29  "plugins",
30  "popups",
31  "geolocation",
32  "notifications",
33  "auto-select-certificate",
34  "fullscreen",
35  "mouselock",
36  "mixed-script",
37  "media-stream",
38  "media-stream-mic",
39  "media-stream-camera",
40  "register-protocol-handler",
41  "ppapi-broker",
42  "multiple-automatic-downloads",
43  "midi-sysex",
44  "push-messaging",
45  "ssl-cert-decisions",
46#if defined(OS_WIN)
47  "metro-switch-to-desktop",
48#elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
49  "protected-media-identifier",
50#endif
51#if defined(OS_ANDROID)
52  "app-banner",
53#endif
54};
55COMPILE_ASSERT(arraysize(kTypeNames) == CONTENT_SETTINGS_NUM_TYPES,
56               type_names_incorrect_size);
57
58const char kPatternSeparator[] = ",";
59
60}  // namespace
61
62namespace content_settings {
63
64std::string GetTypeName(ContentSettingsType type) {
65  return std::string(kTypeNames[type]);
66}
67
68bool GetTypeFromName(const std::string& name,
69                     ContentSettingsType* return_setting) {
70  for (size_t type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
71    if (name.compare(kTypeNames[type]) == 0) {
72      *return_setting = static_cast<ContentSettingsType>(type);
73      return true;
74    }
75  }
76  return false;
77}
78
79std::string ContentSettingToString(ContentSetting setting) {
80  switch (setting) {
81    case CONTENT_SETTING_ALLOW:
82      return "allow";
83    case CONTENT_SETTING_ASK:
84      return "ask";
85    case CONTENT_SETTING_BLOCK:
86      return "block";
87    case CONTENT_SETTING_SESSION_ONLY:
88      return "session";
89    case CONTENT_SETTING_DEFAULT:
90      return "default";
91    case CONTENT_SETTING_NUM_SETTINGS:
92      NOTREACHED();
93  }
94
95  return std::string();
96}
97
98ContentSetting ContentSettingFromString(const std::string& name) {
99  if (name == "allow")
100    return CONTENT_SETTING_ALLOW;
101  if (name == "ask")
102    return CONTENT_SETTING_ASK;
103  if (name == "block")
104    return CONTENT_SETTING_BLOCK;
105  if (name == "session")
106    return CONTENT_SETTING_SESSION_ONLY;
107
108  NOTREACHED() << name << " is not a recognized content setting.";
109  return CONTENT_SETTING_DEFAULT;
110}
111
112std::string CreatePatternString(
113    const ContentSettingsPattern& item_pattern,
114    const ContentSettingsPattern& top_level_frame_pattern) {
115  return item_pattern.ToString()
116         + std::string(kPatternSeparator)
117         + top_level_frame_pattern.ToString();
118}
119
120PatternPair ParsePatternString(const std::string& pattern_str) {
121  std::vector<std::string> pattern_str_list;
122  base::SplitString(pattern_str, kPatternSeparator[0], &pattern_str_list);
123
124  // If the |pattern_str| is an empty string then the |pattern_string_list|
125  // contains a single empty string. In this case the empty string will be
126  // removed to signal an invalid |pattern_str|. Invalid pattern strings are
127  // handle by the "if"-statment below. So the order of the if statements here
128  // must be preserved.
129  if (pattern_str_list.size() == 1) {
130    if (pattern_str_list[0].empty()) {
131      pattern_str_list.pop_back();
132    } else {
133      pattern_str_list.push_back("*");
134    }
135  }
136
137  if (pattern_str_list.size() > 2 ||
138      pattern_str_list.size() == 0) {
139    return PatternPair(ContentSettingsPattern(),
140                       ContentSettingsPattern());
141  }
142
143  PatternPair pattern_pair;
144  pattern_pair.first =
145      ContentSettingsPattern::FromString(pattern_str_list[0]);
146  pattern_pair.second =
147      ContentSettingsPattern::FromString(pattern_str_list[1]);
148  return pattern_pair;
149}
150
151ContentSetting ValueToContentSetting(const base::Value* value) {
152  ContentSetting setting = CONTENT_SETTING_DEFAULT;
153  bool valid = ParseContentSettingValue(value, &setting);
154  DCHECK(valid);
155  return setting;
156}
157
158bool ParseContentSettingValue(const base::Value* value,
159                              ContentSetting* setting) {
160  if (!value) {
161    *setting = CONTENT_SETTING_DEFAULT;
162    return true;
163  }
164  int int_value = -1;
165  if (!value->GetAsInteger(&int_value))
166    return false;
167  *setting = IntToContentSetting(int_value);
168  return *setting != CONTENT_SETTING_DEFAULT;
169}
170
171base::Value* GetContentSettingValueAndPatterns(
172    const ProviderInterface* provider,
173    const GURL& primary_url,
174    const GURL& secondary_url,
175    ContentSettingsType content_type,
176    const std::string& resource_identifier,
177    bool include_incognito,
178    ContentSettingsPattern* primary_pattern,
179    ContentSettingsPattern* secondary_pattern) {
180  if (include_incognito) {
181    // Check incognito-only specific settings. It's essential that the
182    // |RuleIterator| gets out of scope before we get a rule iterator for the
183    // normal mode.
184    scoped_ptr<RuleIterator> incognito_rule_iterator(
185        provider->GetRuleIterator(content_type, resource_identifier, true));
186    base::Value* value = GetContentSettingValueAndPatterns(
187        incognito_rule_iterator.get(), primary_url, secondary_url,
188        primary_pattern, secondary_pattern);
189    if (value)
190      return value;
191  }
192  // No settings from the incognito; use the normal mode.
193  scoped_ptr<RuleIterator> rule_iterator(
194      provider->GetRuleIterator(content_type, resource_identifier, false));
195  return GetContentSettingValueAndPatterns(
196      rule_iterator.get(), primary_url, secondary_url,
197      primary_pattern, secondary_pattern);
198}
199
200base::Value* GetContentSettingValueAndPatterns(
201    RuleIterator* rule_iterator,
202    const GURL& primary_url,
203    const GURL& secondary_url,
204    ContentSettingsPattern* primary_pattern,
205    ContentSettingsPattern* secondary_pattern) {
206  while (rule_iterator->HasNext()) {
207    const Rule& rule = rule_iterator->Next();
208    if (rule.primary_pattern.Matches(primary_url) &&
209        rule.secondary_pattern.Matches(secondary_url)) {
210      if (primary_pattern)
211        *primary_pattern = rule.primary_pattern;
212      if (secondary_pattern)
213        *secondary_pattern = rule.secondary_pattern;
214      return rule.value.get()->DeepCopy();
215    }
216  }
217  return NULL;
218}
219
220base::Value* GetContentSettingValue(const ProviderInterface* provider,
221                                    const GURL& primary_url,
222                                    const GURL& secondary_url,
223                                    ContentSettingsType content_type,
224                                    const std::string& resource_identifier,
225                                    bool include_incognito) {
226  return GetContentSettingValueAndPatterns(provider, primary_url, secondary_url,
227                               content_type, resource_identifier,
228                               include_incognito, NULL, NULL);
229}
230
231ContentSetting GetContentSetting(const ProviderInterface* provider,
232                                 const GURL& primary_url,
233                                 const GURL& secondary_url,
234                                 ContentSettingsType content_type,
235                                 const std::string& resource_identifier,
236                                 bool include_incognito) {
237  scoped_ptr<base::Value> value(
238      GetContentSettingValue(provider, primary_url, secondary_url,
239                             content_type, resource_identifier,
240                             include_incognito));
241  return ValueToContentSetting(value.get());
242}
243
244void GetRendererContentSettingRules(const HostContentSettingsMap* map,
245                                    RendererContentSettingRules* rules) {
246  map->GetSettingsForOneType(
247      CONTENT_SETTINGS_TYPE_IMAGES, std::string(), &(rules->image_rules));
248  map->GetSettingsForOneType(
249      CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(), &(rules->script_rules));
250}
251
252}  // namespace content_settings
253