Home | History | Annotate | Download | only in webui
      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/web_contents/web_contents_impl.h"
     14 #include "content/browser/web_contents/web_contents_view.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/render_frame_host.h"
     19 #include "content/public/browser/render_view_host.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 
     25 namespace content {
     26 
     27 const WebUI::TypeID WebUI::kNoWebUI = NULL;
     28 
     29 // static
     30 base::string16 WebUI::GetJavascriptCall(
     31     const std::string& function_name,
     32     const std::vector<const base::Value*>& arg_list) {
     33   base::string16 parameters;
     34   std::string json;
     35   for (size_t i = 0; i < arg_list.size(); ++i) {
     36     if (i > 0)
     37       parameters += base::char16(',');
     38 
     39     base::JSONWriter::Write(arg_list[i], &json);
     40     parameters += base::UTF8ToUTF16(json);
     41   }
     42   return base::ASCIIToUTF16(function_name) +
     43       base::char16('(') + parameters + base::char16(')') + base::char16(';');
     44 }
     45 
     46 WebUIImpl::WebUIImpl(WebContents* contents)
     47     : link_transition_type_(ui::PAGE_TRANSITION_LINK),
     48       bindings_(BINDINGS_POLICY_WEB_UI),
     49       web_contents_(contents) {
     50   DCHECK(contents);
     51 }
     52 
     53 WebUIImpl::~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 
     61 bool 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 
     70 void WebUIImpl::OnWebUISend(const GURL& source_url,
     71                             const std::string& message,
     72                             const base::ListValue& args) {
     73   if (!ChildProcessSecurityPolicyImpl::GetInstance()->
     74           HasWebUIBindings(web_contents_->GetRenderProcessHost()->GetID()) ||
     75       !WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
     76           web_contents_->GetBrowserContext(), source_url)) {
     77     NOTREACHED() << "Blocked unauthorized use of WebUIBindings.";
     78     return;
     79   }
     80 
     81   ProcessWebUIMessage(source_url, message, args);
     82 }
     83 
     84 void WebUIImpl::RenderViewCreated(RenderViewHost* render_view_host) {
     85   controller_->RenderViewCreated(render_view_host);
     86 
     87   // Do not attempt to set the toolkit property if WebUI is not enabled, e.g.,
     88   // the bookmarks manager page.
     89   if (!(bindings_ & BINDINGS_POLICY_WEB_UI))
     90     return;
     91 
     92 #if defined(TOOLKIT_VIEWS)
     93   render_view_host->SetWebUIProperty("toolkit", "views");
     94 #endif  // defined(TOOLKIT_VIEWS)
     95 }
     96 
     97 WebContents* WebUIImpl::GetWebContents() const {
     98   return web_contents_;
     99 }
    100 
    101 float WebUIImpl::GetDeviceScaleFactor() const {
    102   return GetScaleFactorForView(web_contents_->GetRenderWidgetHostView());
    103 }
    104 
    105 const base::string16& WebUIImpl::GetOverriddenTitle() const {
    106   return overridden_title_;
    107 }
    108 
    109 void WebUIImpl::OverrideTitle(const base::string16& title) {
    110   overridden_title_ = title;
    111 }
    112 
    113 ui::PageTransition WebUIImpl::GetLinkTransitionType() const {
    114   return link_transition_type_;
    115 }
    116 
    117 void WebUIImpl::SetLinkTransitionType(ui::PageTransition type) {
    118   link_transition_type_ = type;
    119 }
    120 
    121 int WebUIImpl::GetBindings() const {
    122   return bindings_;
    123 }
    124 
    125 void WebUIImpl::SetBindings(int bindings) {
    126   bindings_ = bindings;
    127 }
    128 
    129 void WebUIImpl::OverrideJavaScriptFrame(const std::string& frame_name) {
    130   frame_name_ = frame_name;
    131 }
    132 
    133 WebUIController* WebUIImpl::GetController() const {
    134   return controller_.get();
    135 }
    136 
    137 void WebUIImpl::SetController(WebUIController* controller) {
    138   controller_.reset(controller);
    139 }
    140 
    141 void WebUIImpl::CallJavascriptFunction(const std::string& function_name) {
    142   DCHECK(base::IsStringASCII(function_name));
    143   base::string16 javascript = base::ASCIIToUTF16(function_name + "();");
    144   ExecuteJavascript(javascript);
    145 }
    146 
    147 void WebUIImpl::CallJavascriptFunction(const std::string& function_name,
    148                                        const base::Value& arg) {
    149   DCHECK(base::IsStringASCII(function_name));
    150   std::vector<const base::Value*> args;
    151   args.push_back(&arg);
    152   ExecuteJavascript(GetJavascriptCall(function_name, args));
    153 }
    154 
    155 void WebUIImpl::CallJavascriptFunction(
    156     const std::string& function_name,
    157     const base::Value& arg1, const base::Value& arg2) {
    158   DCHECK(base::IsStringASCII(function_name));
    159   std::vector<const base::Value*> args;
    160   args.push_back(&arg1);
    161   args.push_back(&arg2);
    162   ExecuteJavascript(GetJavascriptCall(function_name, args));
    163 }
    164 
    165 void WebUIImpl::CallJavascriptFunction(
    166     const std::string& function_name,
    167     const base::Value& arg1, const base::Value& arg2, const base::Value& arg3) {
    168   DCHECK(base::IsStringASCII(function_name));
    169   std::vector<const base::Value*> args;
    170   args.push_back(&arg1);
    171   args.push_back(&arg2);
    172   args.push_back(&arg3);
    173   ExecuteJavascript(GetJavascriptCall(function_name, args));
    174 }
    175 
    176 void WebUIImpl::CallJavascriptFunction(
    177     const std::string& function_name,
    178     const base::Value& arg1,
    179     const base::Value& arg2,
    180     const base::Value& arg3,
    181     const base::Value& arg4) {
    182   DCHECK(base::IsStringASCII(function_name));
    183   std::vector<const base::Value*> args;
    184   args.push_back(&arg1);
    185   args.push_back(&arg2);
    186   args.push_back(&arg3);
    187   args.push_back(&arg4);
    188   ExecuteJavascript(GetJavascriptCall(function_name, args));
    189 }
    190 
    191 void WebUIImpl::CallJavascriptFunction(
    192     const std::string& function_name,
    193     const std::vector<const base::Value*>& args) {
    194   DCHECK(base::IsStringASCII(function_name));
    195   ExecuteJavascript(GetJavascriptCall(function_name, args));
    196 }
    197 
    198 void WebUIImpl::RegisterMessageCallback(const std::string &message,
    199                                         const MessageCallback& callback) {
    200   message_callbacks_.insert(std::make_pair(message, callback));
    201 }
    202 
    203 void WebUIImpl::ProcessWebUIMessage(const GURL& source_url,
    204                                     const std::string& message,
    205                                     const base::ListValue& args) {
    206   if (controller_->OverrideHandleWebUIMessage(source_url, message, args))
    207     return;
    208 
    209   // Look up the callback for this message.
    210   MessageCallbackMap::const_iterator callback =
    211       message_callbacks_.find(message);
    212   if (callback != message_callbacks_.end()) {
    213     // Forward this message and content on.
    214     callback->second.Run(&args);
    215   } else {
    216     NOTREACHED() << "Unhandled chrome.send(\"" << message << "\");";
    217   }
    218 }
    219 
    220 // WebUIImpl, protected: -------------------------------------------------------
    221 
    222 void WebUIImpl::AddMessageHandler(WebUIMessageHandler* handler) {
    223   DCHECK(!handler->web_ui());
    224   handler->set_web_ui(this);
    225   handler->RegisterMessages();
    226   handlers_.push_back(handler);
    227 }
    228 
    229 void WebUIImpl::ExecuteJavascript(const base::string16& javascript) {
    230   RenderFrameHost* target_frame = TargetFrame();
    231   if (target_frame)
    232     target_frame->ExecuteJavaScript(javascript);
    233 }
    234 
    235 RenderFrameHost* WebUIImpl::TargetFrame() {
    236   if (frame_name_.empty())
    237     return web_contents_->GetMainFrame();
    238 
    239   std::set<RenderFrameHost*> frame_set;
    240   web_contents_->ForEachFrame(base::Bind(&WebUIImpl::AddToSetIfFrameNameMatches,
    241                                          base::Unretained(this),
    242                                          &frame_set));
    243 
    244   // It happens that some sub-pages attempt to send JavaScript messages before
    245   // their frames are loaded.
    246   DCHECK_GE(1U, frame_set.size());
    247   if (frame_set.empty())
    248     return NULL;
    249   return *frame_set.begin();
    250 }
    251 
    252 void WebUIImpl::AddToSetIfFrameNameMatches(
    253     std::set<RenderFrameHost*>* frame_set,
    254     RenderFrameHost* host) {
    255   if (host->GetFrameName() == frame_name_)
    256     frame_set->insert(host);
    257 }
    258 
    259 }  // namespace content
    260