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_impl.h"
6
7#include "base/json/json_writer.h"
8#include "base/strings/utf_string_conversions.h"
9#include "base/values.h"
10#include "content/browser/child_process_security_policy_impl.h"
11#include "content/browser/renderer_host/dip_util.h"
12#include "content/browser/renderer_host/render_process_host_impl.h"
13#include "content/browser/renderer_host/render_view_host_impl.h"
14#include "content/browser/web_contents/web_contents_impl.h"
15#include "content/browser/webui/web_ui_controller_factory_registry.h"
16#include "content/common/view_messages.h"
17#include "content/public/browser/content_browser_client.h"
18#include "content/public/browser/web_contents_delegate.h"
19#include "content/public/browser/web_contents_view.h"
20#include "content/public/browser/web_ui_controller.h"
21#include "content/public/browser/web_ui_message_handler.h"
22#include "content/public/common/bindings_policy.h"
23#include "content/public/common/content_client.h"
24
25namespace content {
26
27const WebUI::TypeID WebUI::kNoWebUI = NULL;
28
29// static
30string16 WebUI::GetJavascriptCall(
31    const std::string& function_name,
32    const std::vector<const Value*>& arg_list) {
33  string16 parameters;
34  std::string json;
35  for (size_t i = 0; i < arg_list.size(); ++i) {
36    if (i > 0)
37      parameters += char16(',');
38
39    base::JSONWriter::Write(arg_list[i], &json);
40    parameters += UTF8ToUTF16(json);
41  }
42  return ASCIIToUTF16(function_name) +
43      char16('(') + parameters + char16(')') + char16(';');
44}
45
46WebUIImpl::WebUIImpl(WebContents* contents)
47    : link_transition_type_(PAGE_TRANSITION_LINK),
48      bindings_(BINDINGS_POLICY_WEB_UI),
49      web_contents_(contents) {
50  DCHECK(contents);
51}
52
53WebUIImpl::~WebUIImpl() {
54  // Delete the controller first, since it may also be keeping a pointer to some
55  // of the handlers and can call them at destruction.
56  controller_.reset();
57}
58
59// WebUIImpl, public: ----------------------------------------------------------
60
61bool WebUIImpl::OnMessageReceived(const IPC::Message& message) {
62  bool handled = true;
63  IPC_BEGIN_MESSAGE_MAP(WebUIImpl, message)
64    IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
65    IPC_MESSAGE_UNHANDLED(handled = false)
66  IPC_END_MESSAGE_MAP()
67  return handled;
68}
69
70void WebUIImpl::OnWebUISend(const GURL& source_url,
71                            const std::string& message,
72                            const ListValue& args) {
73  WebContentsDelegate* delegate = web_contents_->GetDelegate();
74  bool data_urls_allowed = delegate && delegate->CanLoadDataURLsInWebUI();
75  if (!ChildProcessSecurityPolicyImpl::GetInstance()->
76          HasWebUIBindings(web_contents_->GetRenderProcessHost()->GetID()) ||
77      !WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
78          web_contents_->GetBrowserContext(), source_url, data_urls_allowed)) {
79    NOTREACHED() << "Blocked unauthorized use of WebUIBindings.";
80    return;
81  }
82
83  ProcessWebUIMessage(source_url, message, args);
84}
85
86void WebUIImpl::RenderViewCreated(RenderViewHost* render_view_host) {
87  controller_->RenderViewCreated(render_view_host);
88
89  // Do not attempt to set the toolkit property if WebUI is not enabled, e.g.,
90  // the bookmarks manager page.
91  if (!(bindings_ & BINDINGS_POLICY_WEB_UI))
92    return;
93
94#if defined(TOOLKIT_VIEWS)
95  render_view_host->SetWebUIProperty("toolkit", "views");
96#elif defined(TOOLKIT_GTK)
97  render_view_host->SetWebUIProperty("toolkit", "GTK");
98#endif  // defined(TOOLKIT_VIEWS)
99}
100
101WebContents* WebUIImpl::GetWebContents() const {
102  return web_contents_;
103}
104
105ui::ScaleFactor WebUIImpl::GetDeviceScaleFactor() const {
106  return GetScaleFactorForView(web_contents_->GetRenderWidgetHostView());
107}
108
109const string16& WebUIImpl::GetOverriddenTitle() const {
110  return overridden_title_;
111}
112
113void WebUIImpl::OverrideTitle(const string16& title) {
114  overridden_title_ = title;
115}
116
117PageTransition WebUIImpl::GetLinkTransitionType() const {
118  return link_transition_type_;
119}
120
121void WebUIImpl::SetLinkTransitionType(PageTransition type) {
122  link_transition_type_ = type;
123}
124
125int WebUIImpl::GetBindings() const {
126  return bindings_;
127}
128
129void WebUIImpl::SetBindings(int bindings) {
130  bindings_ = bindings;
131}
132
133void WebUIImpl::SetFrameXPath(const std::string& xpath) {
134  frame_xpath_ = xpath;
135}
136
137WebUIController* WebUIImpl::GetController() const {
138  return controller_.get();
139}
140
141void WebUIImpl::SetController(WebUIController* controller) {
142  controller_.reset(controller);
143}
144
145void WebUIImpl::CallJavascriptFunction(const std::string& function_name) {
146  DCHECK(IsStringASCII(function_name));
147  string16 javascript = ASCIIToUTF16(function_name + "();");
148  ExecuteJavascript(javascript);
149}
150
151void WebUIImpl::CallJavascriptFunction(const std::string& function_name,
152                                       const Value& arg) {
153  DCHECK(IsStringASCII(function_name));
154  std::vector<const Value*> args;
155  args.push_back(&arg);
156  ExecuteJavascript(GetJavascriptCall(function_name, args));
157}
158
159void WebUIImpl::CallJavascriptFunction(
160    const std::string& function_name,
161    const Value& arg1, const Value& arg2) {
162  DCHECK(IsStringASCII(function_name));
163  std::vector<const Value*> args;
164  args.push_back(&arg1);
165  args.push_back(&arg2);
166  ExecuteJavascript(GetJavascriptCall(function_name, args));
167}
168
169void WebUIImpl::CallJavascriptFunction(
170    const std::string& function_name,
171    const Value& arg1, const Value& arg2, const Value& arg3) {
172  DCHECK(IsStringASCII(function_name));
173  std::vector<const Value*> args;
174  args.push_back(&arg1);
175  args.push_back(&arg2);
176  args.push_back(&arg3);
177  ExecuteJavascript(GetJavascriptCall(function_name, args));
178}
179
180void WebUIImpl::CallJavascriptFunction(
181    const std::string& function_name,
182    const Value& arg1,
183    const Value& arg2,
184    const Value& arg3,
185    const Value& arg4) {
186  DCHECK(IsStringASCII(function_name));
187  std::vector<const Value*> args;
188  args.push_back(&arg1);
189  args.push_back(&arg2);
190  args.push_back(&arg3);
191  args.push_back(&arg4);
192  ExecuteJavascript(GetJavascriptCall(function_name, args));
193}
194
195void WebUIImpl::CallJavascriptFunction(
196    const std::string& function_name,
197    const std::vector<const Value*>& args) {
198  DCHECK(IsStringASCII(function_name));
199  ExecuteJavascript(GetJavascriptCall(function_name, args));
200}
201
202void WebUIImpl::RegisterMessageCallback(const std::string &message,
203                                        const MessageCallback& callback) {
204  message_callbacks_.insert(std::make_pair(message, callback));
205}
206
207void WebUIImpl::ProcessWebUIMessage(const GURL& source_url,
208                                    const std::string& message,
209                                    const base::ListValue& args) {
210  if (controller_->OverrideHandleWebUIMessage(source_url, message, args))
211    return;
212
213  // Look up the callback for this message.
214  MessageCallbackMap::const_iterator callback =
215      message_callbacks_.find(message);
216  if (callback != message_callbacks_.end()) {
217    // Forward this message and content on.
218    callback->second.Run(&args);
219  } else {
220    NOTREACHED() << "Unhandled chrome.send(\"" << message << "\");";
221  }
222}
223
224// WebUIImpl, protected: -------------------------------------------------------
225
226void WebUIImpl::AddMessageHandler(WebUIMessageHandler* handler) {
227  DCHECK(!handler->web_ui());
228  handler->set_web_ui(this);
229  handler->RegisterMessages();
230  handlers_.push_back(handler);
231}
232
233void WebUIImpl::ExecuteJavascript(const string16& javascript) {
234  static_cast<RenderViewHostImpl*>(
235      web_contents_->GetRenderViewHost())->ExecuteJavascriptInWebFrame(
236      ASCIIToUTF16(frame_xpath_), javascript);
237}
238
239}  // namespace content
240