1// Copyright 2014 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 "extensions/common/manifest_handlers/webview_info.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "extensions/common/error_utils.h"
13#include "extensions/common/manifest.h"
14#include "extensions/common/manifest_constants.h"
15
16namespace extensions {
17
18namespace keys = extensions::manifest_keys;
19namespace errors = extensions::manifest_errors;
20
21namespace {
22
23const WebviewInfo* GetResourcesInfo(
24    const Extension& extension) {
25  return static_cast<WebviewInfo*>(
26      extension.GetManifestData(keys::kWebviewAccessibleResources));
27}
28
29}  // namespace
30
31// A PartitionItem represents a set of accessible resources given a partition
32// ID pattern.
33class PartitionItem {
34 public:
35  explicit PartitionItem(const std::string& partition_pattern)
36      : partition_pattern_(partition_pattern) {
37  }
38
39  virtual ~PartitionItem() {
40  }
41
42  bool Matches(const std::string& partition_id) const {
43    return MatchPattern(partition_id, partition_pattern_);
44  }
45
46  // Adds a pattern to the set. Returns true if a new pattern was inserted,
47  // false if the pattern was already in the set.
48  bool AddPattern(const URLPattern& pattern) {
49    return accessible_resources_.AddPattern(pattern);
50  }
51
52  const URLPatternSet& accessible_resources() const {
53    return accessible_resources_;
54  }
55 private:
56  // A pattern string that matches partition IDs.
57  const std::string partition_pattern_;
58  // A URL pattern set of resources accessible to the given
59  // |partition_pattern_|.
60  URLPatternSet accessible_resources_;
61};
62
63
64WebviewInfo::WebviewInfo() {
65}
66
67WebviewInfo::~WebviewInfo() {
68}
69
70// static
71bool WebviewInfo::IsResourceWebviewAccessible(
72    const Extension* extension,
73    const std::string& partition_id,
74    const std::string& relative_path) {
75  if (!extension)
76    return false;
77
78  const WebviewInfo* info = GetResourcesInfo(*extension);
79  if (!info)
80    return false;
81
82  for (size_t i = 0; i < info->partition_items_.size(); ++i) {
83    const PartitionItem* const item = info->partition_items_[i];
84    if (item->Matches(partition_id) &&
85        extension->ResourceMatches(item->accessible_resources(),
86                                   relative_path)) {
87      return true;
88    }
89  }
90
91  return false;
92}
93
94void WebviewInfo::AddPartitionItem(scoped_ptr<PartitionItem> item) {
95  partition_items_.push_back(item.release());
96}
97
98WebviewHandler::WebviewHandler() {
99}
100
101WebviewHandler::~WebviewHandler() {
102}
103
104bool WebviewHandler::Parse(Extension* extension, base::string16* error) {
105  scoped_ptr<WebviewInfo> info(new WebviewInfo());
106
107  const base::DictionaryValue* dict_value = NULL;
108  if (!extension->manifest()->GetDictionary(keys::kWebview,
109                                            &dict_value)) {
110    *error = base::ASCIIToUTF16(errors::kInvalidWebview);
111    return false;
112  }
113
114  const base::ListValue* partition_list = NULL;
115  if (!dict_value->GetList(keys::kWebviewPartitions, &partition_list)) {
116    *error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
117    return false;
118  }
119
120  // The partition list must have at least one entry.
121  if (partition_list->GetSize() == 0) {
122    *error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
123    return false;
124  }
125
126  for (size_t i = 0; i < partition_list->GetSize(); ++i) {
127    const base::DictionaryValue* partition = NULL;
128    if (!partition_list->GetDictionary(i, &partition)) {
129      *error = ErrorUtils::FormatErrorMessageUTF16(
130          errors::kInvalidWebviewPartition, base::IntToString(i));
131      return false;
132    }
133
134    std::string partition_pattern;
135    if (!partition->GetString(keys::kWebviewName, &partition_pattern)) {
136      *error = ErrorUtils::FormatErrorMessageUTF16(
137          errors::kInvalidWebviewPartitionName, base::IntToString(i));
138      return false;
139    }
140
141    const base::ListValue* url_list = NULL;
142    if (!partition->GetList(keys::kWebviewAccessibleResources,
143                            &url_list)) {
144      *error = base::ASCIIToUTF16(
145          errors::kInvalidWebviewAccessibleResourcesList);
146      return false;
147    }
148
149    // The URL list should have at least one entry.
150    if (url_list->GetSize() == 0) {
151      *error = base::ASCIIToUTF16(
152          errors::kInvalidWebviewAccessibleResourcesList);
153      return false;
154    }
155
156    scoped_ptr<PartitionItem> partition_item(
157        new PartitionItem(partition_pattern));
158
159    for (size_t i = 0; i < url_list->GetSize(); ++i) {
160      std::string relative_path;
161      if (!url_list->GetString(i, &relative_path)) {
162        *error = ErrorUtils::FormatErrorMessageUTF16(
163            errors::kInvalidWebviewAccessibleResource, base::IntToString(i));
164        return false;
165      }
166      URLPattern pattern(URLPattern::SCHEME_EXTENSION,
167                         Extension::GetResourceURL(extension->url(),
168                                                   relative_path).spec());
169      partition_item->AddPattern(pattern);
170    }
171    info->AddPartitionItem(partition_item.Pass());
172  }
173
174  extension->SetManifestData(keys::kWebviewAccessibleResources, info.release());
175  return true;
176}
177
178const std::vector<std::string> WebviewHandler::Keys() const {
179  return SingleKey(keys::kWebview);
180}
181
182}  // namespace extensions
183