| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/webui/web_ui_impl.h" |
| |
| #include "base/json/json_writer.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "content/browser/child_process_security_policy_impl.h" |
| #include "content/browser/renderer_host/dip_util.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/browser/web_contents/web_contents_view.h" |
| #include "content/browser/webui/web_ui_controller_factory_registry.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/web_ui_controller.h" |
| #include "content/public/browser/web_ui_message_handler.h" |
| #include "content/public/common/bindings_policy.h" |
| #include "content/public/common/content_client.h" |
| |
| namespace content { |
| |
| const WebUI::TypeID WebUI::kNoWebUI = NULL; |
| |
| // static |
| base::string16 WebUI::GetJavascriptCall( |
| const std::string& function_name, |
| const std::vector<const base::Value*>& arg_list) { |
| base::string16 parameters; |
| std::string json; |
| for (size_t i = 0; i < arg_list.size(); ++i) { |
| if (i > 0) |
| parameters += base::char16(','); |
| |
| base::JSONWriter::Write(arg_list[i], &json); |
| parameters += base::UTF8ToUTF16(json); |
| } |
| return base::ASCIIToUTF16(function_name) + |
| base::char16('(') + parameters + base::char16(')') + base::char16(';'); |
| } |
| |
| WebUIImpl::WebUIImpl(WebContents* contents) |
| : link_transition_type_(PAGE_TRANSITION_LINK), |
| bindings_(BINDINGS_POLICY_WEB_UI), |
| web_contents_(contents) { |
| DCHECK(contents); |
| } |
| |
| WebUIImpl::~WebUIImpl() { |
| // Delete the controller first, since it may also be keeping a pointer to some |
| // of the handlers and can call them at destruction. |
| controller_.reset(); |
| } |
| |
| // WebUIImpl, public: ---------------------------------------------------------- |
| |
| bool WebUIImpl::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(WebUIImpl, message) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void WebUIImpl::OnWebUISend(const GURL& source_url, |
| const std::string& message, |
| const base::ListValue& args) { |
| if (!ChildProcessSecurityPolicyImpl::GetInstance()-> |
| HasWebUIBindings(web_contents_->GetRenderProcessHost()->GetID()) || |
| !WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( |
| web_contents_->GetBrowserContext(), source_url)) { |
| NOTREACHED() << "Blocked unauthorized use of WebUIBindings."; |
| return; |
| } |
| |
| ProcessWebUIMessage(source_url, message, args); |
| } |
| |
| void WebUIImpl::RenderViewCreated(RenderViewHost* render_view_host) { |
| controller_->RenderViewCreated(render_view_host); |
| |
| // Do not attempt to set the toolkit property if WebUI is not enabled, e.g., |
| // the bookmarks manager page. |
| if (!(bindings_ & BINDINGS_POLICY_WEB_UI)) |
| return; |
| |
| #if defined(TOOLKIT_VIEWS) |
| render_view_host->SetWebUIProperty("toolkit", "views"); |
| #endif // defined(TOOLKIT_VIEWS) |
| } |
| |
| WebContents* WebUIImpl::GetWebContents() const { |
| return web_contents_; |
| } |
| |
| float WebUIImpl::GetDeviceScaleFactor() const { |
| return GetScaleFactorForView(web_contents_->GetRenderWidgetHostView()); |
| } |
| |
| const base::string16& WebUIImpl::GetOverriddenTitle() const { |
| return overridden_title_; |
| } |
| |
| void WebUIImpl::OverrideTitle(const base::string16& title) { |
| overridden_title_ = title; |
| } |
| |
| PageTransition WebUIImpl::GetLinkTransitionType() const { |
| return link_transition_type_; |
| } |
| |
| void WebUIImpl::SetLinkTransitionType(PageTransition type) { |
| link_transition_type_ = type; |
| } |
| |
| int WebUIImpl::GetBindings() const { |
| return bindings_; |
| } |
| |
| void WebUIImpl::SetBindings(int bindings) { |
| bindings_ = bindings; |
| } |
| |
| void WebUIImpl::OverrideJavaScriptFrame(const std::string& frame_name) { |
| frame_name_ = frame_name; |
| } |
| |
| WebUIController* WebUIImpl::GetController() const { |
| return controller_.get(); |
| } |
| |
| void WebUIImpl::SetController(WebUIController* controller) { |
| controller_.reset(controller); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction(const std::string& function_name) { |
| DCHECK(base::IsStringASCII(function_name)); |
| base::string16 javascript = base::ASCIIToUTF16(function_name + "();"); |
| ExecuteJavascript(javascript); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction(const std::string& function_name, |
| const base::Value& arg) { |
| DCHECK(base::IsStringASCII(function_name)); |
| std::vector<const base::Value*> args; |
| args.push_back(&arg); |
| ExecuteJavascript(GetJavascriptCall(function_name, args)); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction( |
| const std::string& function_name, |
| const base::Value& arg1, const base::Value& arg2) { |
| DCHECK(base::IsStringASCII(function_name)); |
| std::vector<const base::Value*> args; |
| args.push_back(&arg1); |
| args.push_back(&arg2); |
| ExecuteJavascript(GetJavascriptCall(function_name, args)); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction( |
| const std::string& function_name, |
| const base::Value& arg1, const base::Value& arg2, const base::Value& arg3) { |
| DCHECK(base::IsStringASCII(function_name)); |
| std::vector<const base::Value*> args; |
| args.push_back(&arg1); |
| args.push_back(&arg2); |
| args.push_back(&arg3); |
| ExecuteJavascript(GetJavascriptCall(function_name, args)); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction( |
| const std::string& function_name, |
| const base::Value& arg1, |
| const base::Value& arg2, |
| const base::Value& arg3, |
| const base::Value& arg4) { |
| DCHECK(base::IsStringASCII(function_name)); |
| std::vector<const base::Value*> args; |
| args.push_back(&arg1); |
| args.push_back(&arg2); |
| args.push_back(&arg3); |
| args.push_back(&arg4); |
| ExecuteJavascript(GetJavascriptCall(function_name, args)); |
| } |
| |
| void WebUIImpl::CallJavascriptFunction( |
| const std::string& function_name, |
| const std::vector<const base::Value*>& args) { |
| DCHECK(base::IsStringASCII(function_name)); |
| ExecuteJavascript(GetJavascriptCall(function_name, args)); |
| } |
| |
| void WebUIImpl::RegisterMessageCallback(const std::string &message, |
| const MessageCallback& callback) { |
| message_callbacks_.insert(std::make_pair(message, callback)); |
| } |
| |
| void WebUIImpl::ProcessWebUIMessage(const GURL& source_url, |
| const std::string& message, |
| const base::ListValue& args) { |
| if (controller_->OverrideHandleWebUIMessage(source_url, message, args)) |
| return; |
| |
| // Look up the callback for this message. |
| MessageCallbackMap::const_iterator callback = |
| message_callbacks_.find(message); |
| if (callback != message_callbacks_.end()) { |
| // Forward this message and content on. |
| callback->second.Run(&args); |
| } else { |
| NOTREACHED() << "Unhandled chrome.send(\"" << message << "\");"; |
| } |
| } |
| |
| // WebUIImpl, protected: ------------------------------------------------------- |
| |
| void WebUIImpl::AddMessageHandler(WebUIMessageHandler* handler) { |
| DCHECK(!handler->web_ui()); |
| handler->set_web_ui(this); |
| handler->RegisterMessages(); |
| handlers_.push_back(handler); |
| } |
| |
| void WebUIImpl::ExecuteJavascript(const base::string16& javascript) { |
| RenderFrameHost* target_frame = TargetFrame(); |
| if (target_frame) |
| target_frame->ExecuteJavaScript(javascript); |
| } |
| |
| RenderFrameHost* WebUIImpl::TargetFrame() { |
| if (frame_name_.empty()) |
| return web_contents_->GetMainFrame(); |
| |
| std::set<RenderFrameHost*> frame_set; |
| web_contents_->ForEachFrame(base::Bind(&WebUIImpl::AddToSetIfFrameNameMatches, |
| base::Unretained(this), |
| &frame_set)); |
| |
| // It happens that some sub-pages attempt to send JavaScript messages before |
| // their frames are loaded. |
| DCHECK_GE(1U, frame_set.size()); |
| if (frame_set.empty()) |
| return NULL; |
| return *frame_set.begin(); |
| } |
| |
| void WebUIImpl::AddToSetIfFrameNameMatches( |
| std::set<RenderFrameHost*>* frame_set, |
| RenderFrameHost* host) { |
| if (host->GetFrameName() == frame_name_) |
| frame_set->insert(host); |
| } |
| |
| } // namespace content |