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_(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 PageTransition WebUIImpl::GetLinkTransitionType() const { 114 return link_transition_type_; 115 } 116 117 void WebUIImpl::SetLinkTransitionType(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