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/content_settings_provider.h"
16#include "chrome/browser/content_settings/content_settings_rule.h"
17#include "chrome/browser/content_settings/host_content_settings_map.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/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#if defined(OS_WIN)
45  "metro-switch-to-desktop",
46#endif
47};
48COMPILE_ASSERT(arraysize(kTypeNames) == CONTENT_SETTINGS_NUM_TYPES,
49               type_names_incorrect_size);
50
51const char kPatternSeparator[] = ",";
52
53}  // namespace
54
55namespace content_settings {
56
57std::string GetTypeName(ContentSettingsType type) {
58  return std::string(kTypeNames[type]);
59}
60
61std::string CreatePatternString(
62    const ContentSettingsPattern& item_pattern,
63    const ContentSettingsPattern& top_level_frame_pattern) {
64  return item_pattern.ToString()
65         + std::string(kPatternSeparator)
66         + top_level_frame_pattern.ToString();
67}
68
69PatternPair ParsePatternString(const std::string& pattern_str) {
70  std::vector<std::string> pattern_str_list;
71  base::SplitString(pattern_str, kPatternSeparator[0], &pattern_str_list);
72
73  // If the |pattern_str| is an empty string then the |pattern_string_list|
74  // contains a single empty string. In this case the empty string will be
75  // removed to signal an invalid |pattern_str|. Invalid pattern strings are
76  // handle by the "if"-statment below. So the order of the if statements here
77  // must be preserved.
78  if (pattern_str_list.size() == 1) {
79    if (pattern_str_list[0].empty()) {
80      pattern_str_list.pop_back();
81    } else {
82      pattern_str_list.push_back("*");
83    }
84  }
85
86  if (pattern_str_list.size() > 2 ||
87      pattern_str_list.size() == 0) {
88    return PatternPair(ContentSettingsPattern(),
89                       ContentSettingsPattern());
90  }
91
92  PatternPair pattern_pair;
93  pattern_pair.first =
94      ContentSettingsPattern::FromString(pattern_str_list[0]);
95  pattern_pair.second =
96      ContentSettingsPattern::FromString(pattern_str_list[1]);
97  return pattern_pair;
98}
99
100ContentSetting ValueToContentSetting(const base::Value* value) {
101  ContentSetting setting = CONTENT_SETTING_DEFAULT;
102  bool valid = ParseContentSettingValue(value, &setting);
103  DCHECK(valid);
104  return setting;
105}
106
107bool ParseContentSettingValue(const base::Value* value,
108                              ContentSetting* setting) {
109  if (!value) {
110    *setting = CONTENT_SETTING_DEFAULT;
111    return true;
112  }
113  int int_value = -1;
114  if (!value->GetAsInteger(&int_value))
115    return false;
116  *setting = IntToContentSetting(int_value);
117  return *setting != CONTENT_SETTING_DEFAULT;
118}
119
120base::Value* GetContentSettingValueAndPatterns(
121    const ProviderInterface* provider,
122    const GURL& primary_url,
123    const GURL& secondary_url,
124    ContentSettingsType content_type,
125    const std::string& resource_identifier,
126    bool include_incognito,
127    ContentSettingsPattern* primary_pattern,
128    ContentSettingsPattern* secondary_pattern) {
129  if (include_incognito) {
130    // Check incognito-only specific settings. It's essential that the
131    // |RuleIterator| gets out of scope before we get a rule iterator for the
132    // normal mode.
133    scoped_ptr<RuleIterator> incognito_rule_iterator(
134        provider->GetRuleIterator(content_type, resource_identifier, true));
135    base::Value* value = GetContentSettingValueAndPatterns(
136        incognito_rule_iterator.get(), primary_url, secondary_url,
137        primary_pattern, secondary_pattern);
138    if (value)
139      return value;
140  }
141  // No settings from the incognito; use the normal mode.
142  scoped_ptr<RuleIterator> rule_iterator(
143      provider->GetRuleIterator(content_type, resource_identifier, false));
144  return GetContentSettingValueAndPatterns(
145      rule_iterator.get(), primary_url, secondary_url,
146      primary_pattern, secondary_pattern);
147}
148
149base::Value* GetContentSettingValueAndPatterns(
150    RuleIterator* rule_iterator,
151    const GURL& primary_url,
152    const GURL& secondary_url,
153    ContentSettingsPattern* primary_pattern,
154    ContentSettingsPattern* secondary_pattern) {
155  while (rule_iterator->HasNext()) {
156    const Rule& rule = rule_iterator->Next();
157    if (rule.primary_pattern.Matches(primary_url) &&
158        rule.secondary_pattern.Matches(secondary_url)) {
159      if (primary_pattern)
160        *primary_pattern = rule.primary_pattern;
161      if (secondary_pattern)
162        *secondary_pattern = rule.secondary_pattern;
163      return rule.value.get()->DeepCopy();
164    }
165  }
166  return NULL;
167}
168
169base::Value* GetContentSettingValue(const ProviderInterface* provider,
170                                    const GURL& primary_url,
171                                    const GURL& secondary_url,
172                                    ContentSettingsType content_type,
173                                    const std::string& resource_identifier,
174                                    bool include_incognito) {
175  return GetContentSettingValueAndPatterns(provider, primary_url, secondary_url,
176                               content_type, resource_identifier,
177                               include_incognito, NULL, NULL);
178}
179
180ContentSetting GetContentSetting(const ProviderInterface* provider,
181                                 const GURL& primary_url,
182                                 const GURL& secondary_url,
183                                 ContentSettingsType content_type,
184                                 const std::string& resource_identifier,
185                                 bool include_incognito) {
186  scoped_ptr<base::Value> value(
187      GetContentSettingValue(provider, primary_url, secondary_url,
188                             content_type, resource_identifier,
189                             include_incognito));
190  return ValueToContentSetting(value.get());
191}
192
193void GetRendererContentSettingRules(const HostContentSettingsMap* map,
194                                    RendererContentSettingRules* rules) {
195  map->GetSettingsForOneType(
196      CONTENT_SETTINGS_TYPE_IMAGES, std::string(), &(rules->image_rules));
197  map->GetSettingsForOneType(
198      CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(), &(rules->script_rules));
199}
200
201}  // namespace content_settings
202