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 "content/browser/webui/web_ui_data_source_impl.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/memory/ref_counted_memory.h"
11#include "base/strings/string_util.h"
12#include "content/grit/content_resources.h"
13#include "content/public/common/content_client.h"
14#include "mojo/public/js/bindings/constants.h"
15#include "ui/base/webui/jstemplate_builder.h"
16#include "ui/base/webui/web_ui_util.h"
17
18namespace content {
19
20// static
21WebUIDataSource* WebUIDataSource::Create(const std::string& source_name) {
22  return new WebUIDataSourceImpl(source_name);
23}
24
25// static
26WebUIDataSource* WebUIDataSource::AddMojoDataSource(
27    BrowserContext* browser_context) {
28  WebUIDataSource* mojo_source = Create("mojo");
29
30  static const struct {
31    const char* path;
32    int id;
33  } resources[] = {
34    { mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS },
35    { mojo::kCodecModuleName, IDR_MOJO_CODEC_JS },
36    { mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS },
37    { mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS },
38    { mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS },
39    { mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS },
40    { mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS },
41  };
42  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i)
43    mojo_source->AddResourcePath(resources[i].path, resources[i].id);
44
45  URLDataManager::AddWebUIDataSource(browser_context, mojo_source);
46  return mojo_source;
47}
48
49// static
50void WebUIDataSource::Add(BrowserContext* browser_context,
51                          WebUIDataSource* source) {
52  URLDataManager::AddWebUIDataSource(browser_context, source);
53}
54
55// Internal class to hide the fact that WebUIDataSourceImpl implements
56// URLDataSource.
57class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
58 public:
59  InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {
60  }
61
62  virtual ~InternalDataSource() {
63  }
64
65  // URLDataSource implementation.
66  virtual std::string GetSource() const OVERRIDE {
67    return parent_->GetSource();
68  }
69  virtual std::string GetMimeType(const std::string& path) const OVERRIDE {
70    return parent_->GetMimeType(path);
71  }
72  virtual void StartDataRequest(
73      const std::string& path,
74      int render_process_id,
75      int render_frame_id,
76      const URLDataSource::GotDataCallback& callback) OVERRIDE {
77    return parent_->StartDataRequest(path, render_process_id, render_frame_id,
78                                     callback);
79  }
80  virtual bool ShouldReplaceExistingSource() const OVERRIDE {
81    return parent_->replace_existing_source_;
82  }
83  virtual bool AllowCaching() const OVERRIDE {
84    return false;
85  }
86  virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
87    return parent_->add_csp_;
88  }
89  virtual std::string GetContentSecurityPolicyObjectSrc() const OVERRIDE {
90    if (parent_->object_src_set_)
91      return parent_->object_src_;
92    return URLDataSource::GetContentSecurityPolicyObjectSrc();
93  }
94  virtual std::string GetContentSecurityPolicyFrameSrc() const OVERRIDE {
95    if (parent_->frame_src_set_)
96      return parent_->frame_src_;
97    return URLDataSource::GetContentSecurityPolicyFrameSrc();
98  }
99  virtual bool ShouldDenyXFrameOptions() const OVERRIDE {
100    return parent_->deny_xframe_options_;
101  }
102
103 private:
104  WebUIDataSourceImpl* parent_;
105};
106
107WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
108    : URLDataSourceImpl(
109          source_name,
110          new InternalDataSource(this)),
111      source_name_(source_name),
112      default_resource_(-1),
113      json_js_format_v2_(false),
114      add_csp_(true),
115      object_src_set_(false),
116      frame_src_set_(false),
117      deny_xframe_options_(true),
118      disable_set_font_strings_(false),
119      replace_existing_source_(true) {
120}
121
122WebUIDataSourceImpl::~WebUIDataSourceImpl() {
123}
124
125void WebUIDataSourceImpl::AddString(const std::string& name,
126                                    const base::string16& value) {
127  localized_strings_.SetString(name, value);
128}
129
130void WebUIDataSourceImpl::AddString(const std::string& name,
131                                    const std::string& value) {
132  localized_strings_.SetString(name, value);
133}
134
135void WebUIDataSourceImpl::AddLocalizedString(const std::string& name,
136                                             int ids) {
137  localized_strings_.SetString(
138      name, GetContentClient()->GetLocalizedString(ids));
139}
140
141void WebUIDataSourceImpl::AddLocalizedStrings(
142    const base::DictionaryValue& localized_strings) {
143  localized_strings_.MergeDictionary(&localized_strings);
144}
145
146void WebUIDataSourceImpl::AddBoolean(const std::string& name, bool value) {
147  localized_strings_.SetBoolean(name, value);
148}
149
150void WebUIDataSourceImpl::SetJsonPath(const std::string& path) {
151  json_path_ = path;
152}
153
154void WebUIDataSourceImpl::SetUseJsonJSFormatV2() {
155  json_js_format_v2_ = true;
156}
157
158void WebUIDataSourceImpl::AddResourcePath(const std::string &path,
159                                          int resource_id) {
160  path_to_idr_map_[path] = resource_id;
161}
162
163void WebUIDataSourceImpl::SetDefaultResource(int resource_id) {
164  default_resource_ = resource_id;
165}
166
167void WebUIDataSourceImpl::SetRequestFilter(
168    const WebUIDataSource::HandleRequestCallback& callback) {
169  filter_callback_ = callback;
170}
171
172void WebUIDataSourceImpl::DisableReplaceExistingSource() {
173  replace_existing_source_ = false;
174}
175
176void WebUIDataSourceImpl::DisableContentSecurityPolicy() {
177  add_csp_ = false;
178}
179
180void WebUIDataSourceImpl::OverrideContentSecurityPolicyObjectSrc(
181    const std::string& data) {
182  object_src_set_ = true;
183  object_src_ = data;
184}
185
186void WebUIDataSourceImpl::OverrideContentSecurityPolicyFrameSrc(
187    const std::string& data) {
188  frame_src_set_ = true;
189  frame_src_ = data;
190}
191
192void WebUIDataSourceImpl::DisableDenyXFrameOptions() {
193  deny_xframe_options_ = false;
194}
195
196std::string WebUIDataSourceImpl::GetSource() const {
197  return source_name_;
198}
199
200std::string WebUIDataSourceImpl::GetMimeType(const std::string& path) const {
201  if (EndsWith(path, ".js", false))
202    return "application/javascript";
203
204  if (EndsWith(path, ".json", false))
205    return "application/json";
206
207  if (EndsWith(path, ".pdf", false))
208    return "application/pdf";
209
210  if (EndsWith(path, ".svg", false))
211    return "image/svg+xml";
212
213  return "text/html";
214}
215
216void WebUIDataSourceImpl::StartDataRequest(
217    const std::string& path,
218    int render_process_id,
219    int render_frame_id,
220    const URLDataSource::GotDataCallback& callback) {
221  if (!filter_callback_.is_null() &&
222      filter_callback_.Run(path, callback)) {
223    return;
224  }
225
226  if (!json_path_.empty() && path == json_path_) {
227    SendLocalizedStringsAsJSON(callback);
228    return;
229  }
230
231  int resource_id = default_resource_;
232  std::map<std::string, int>::iterator result;
233  result = path_to_idr_map_.find(path);
234  if (result != path_to_idr_map_.end())
235    resource_id = result->second;
236  DCHECK_NE(resource_id, -1);
237  SendFromResourceBundle(callback, resource_id);
238}
239
240void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
241    const URLDataSource::GotDataCallback& callback) {
242  std::string template_data;
243  if (!disable_set_font_strings_)
244    webui::SetFontAndTextDirection(&localized_strings_);
245
246  scoped_ptr<webui::UseVersion2> version2;
247  if (json_js_format_v2_)
248    version2.reset(new webui::UseVersion2);
249
250  webui::AppendJsonJS(&localized_strings_, &template_data);
251  callback.Run(base::RefCountedString::TakeString(&template_data));
252}
253
254void WebUIDataSourceImpl::SendFromResourceBundle(
255    const URLDataSource::GotDataCallback& callback, int idr) {
256  scoped_refptr<base::RefCountedStaticMemory> response(
257      GetContentClient()->GetDataResourceBytes(idr));
258  callback.Run(response.get());
259}
260
261}  // namespace content
262