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.
5 #include "content/browser/webui/web_ui_impl.h"
7 #include "base/debug/dump_without_crashing.h"
8 #include "base/json/json_writer.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "content/browser/child_process_security_policy_impl.h"
12 #include "content/browser/renderer_host/dip_util.h"
13 #include "content/browser/renderer_host/render_process_host_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/browser/web_contents/web_contents_view.h"
16 #include "content/browser/webui/web_ui_controller_factory_registry.h"
17 #include "content/common/view_messages.h"
18 #include "content/public/browser/content_browser_client.h"
19 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/web_ui_controller.h"
22 #include "content/public/browser/web_ui_message_handler.h"
23 #include "content/public/common/bindings_policy.h"
24 #include "content/public/common/content_client.h"
28 const WebUI::TypeID
WebUI::kNoWebUI
= NULL
;
31 base::string16
WebUI::GetJavascriptCall(
32 const std::string
& function_name
,
33 const std::vector
<const base::Value
*>& arg_list
) {
34 base::string16 parameters
;
36 for (size_t i
= 0; i
< arg_list
.size(); ++i
) {
38 parameters
+= base::char16(',');
40 base::JSONWriter::Write(*arg_list
[i
], &json
);
41 parameters
+= base::UTF8ToUTF16(json
);
43 return base::ASCIIToUTF16(function_name
) +
44 base::char16('(') + parameters
+ base::char16(')') + base::char16(';');
47 WebUIImpl::WebUIImpl(WebContents
* contents
, const std::string
& frame_name
)
48 : link_transition_type_(ui::PAGE_TRANSITION_LINK
),
49 bindings_(BINDINGS_POLICY_WEB_UI
),
50 web_contents_(contents
),
51 frame_name_(frame_name
) {
55 WebUIImpl::~WebUIImpl() {
56 // Delete the controller first, since it may also be keeping a pointer to some
57 // of the handlers and can call them at destruction.
61 // WebUIImpl, public: ----------------------------------------------------------
63 bool WebUIImpl::OnMessageReceived(const IPC::Message
& message
) {
65 IPC_BEGIN_MESSAGE_MAP(WebUIImpl
, message
)
66 IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend
, OnWebUISend
)
67 IPC_MESSAGE_UNHANDLED(handled
= false)
72 void WebUIImpl::OnWebUISend(const GURL
& source_url
,
73 const std::string
& message
,
74 const base::ListValue
& args
) {
75 if (!ChildProcessSecurityPolicyImpl::GetInstance()->
76 HasWebUIBindings(web_contents_
->GetRenderProcessHost()->GetID()) ||
77 !WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
78 web_contents_
->GetBrowserContext(), source_url
)) {
79 NOTREACHED() << "Blocked unauthorized use of WebUIBindings.";
83 ProcessWebUIMessage(source_url
, message
, args
);
86 void WebUIImpl::RenderViewCreated(RenderViewHost
* render_view_host
) {
87 controller_
->RenderViewCreated(render_view_host
);
90 WebContents
* WebUIImpl::GetWebContents() const {
94 float WebUIImpl::GetDeviceScaleFactor() const {
95 return GetScaleFactorForView(web_contents_
->GetRenderWidgetHostView());
98 const base::string16
& WebUIImpl::GetOverriddenTitle() const {
99 return overridden_title_
;
102 void WebUIImpl::OverrideTitle(const base::string16
& title
) {
103 overridden_title_
= title
;
106 ui::PageTransition
WebUIImpl::GetLinkTransitionType() const {
107 return link_transition_type_
;
110 void WebUIImpl::SetLinkTransitionType(ui::PageTransition type
) {
111 link_transition_type_
= type
;
114 int WebUIImpl::GetBindings() const {
118 void WebUIImpl::SetBindings(int bindings
) {
119 bindings_
= bindings
;
122 WebUIController
* WebUIImpl::GetController() const {
123 return controller_
.get();
126 void WebUIImpl::SetController(WebUIController
* controller
) {
127 controller_
.reset(controller
);
130 void WebUIImpl::CallJavascriptFunction(const std::string
& function_name
) {
131 DCHECK(base::IsStringASCII(function_name
));
132 base::string16 javascript
= base::ASCIIToUTF16(function_name
+ "();");
133 ExecuteJavascript(javascript
);
136 void WebUIImpl::CallJavascriptFunction(const std::string
& function_name
,
137 const base::Value
& arg
) {
138 DCHECK(base::IsStringASCII(function_name
));
139 std::vector
<const base::Value
*> args
;
140 args
.push_back(&arg
);
141 ExecuteJavascript(GetJavascriptCall(function_name
, args
));
144 void WebUIImpl::CallJavascriptFunction(
145 const std::string
& function_name
,
146 const base::Value
& arg1
, const base::Value
& arg2
) {
147 DCHECK(base::IsStringASCII(function_name
));
148 std::vector
<const base::Value
*> args
;
149 args
.push_back(&arg1
);
150 args
.push_back(&arg2
);
151 ExecuteJavascript(GetJavascriptCall(function_name
, args
));
154 void WebUIImpl::CallJavascriptFunction(
155 const std::string
& function_name
,
156 const base::Value
& arg1
, const base::Value
& arg2
, const base::Value
& arg3
) {
157 DCHECK(base::IsStringASCII(function_name
));
158 std::vector
<const base::Value
*> args
;
159 args
.push_back(&arg1
);
160 args
.push_back(&arg2
);
161 args
.push_back(&arg3
);
162 ExecuteJavascript(GetJavascriptCall(function_name
, args
));
165 void WebUIImpl::CallJavascriptFunction(
166 const std::string
& function_name
,
167 const base::Value
& arg1
,
168 const base::Value
& arg2
,
169 const base::Value
& arg3
,
170 const base::Value
& arg4
) {
171 DCHECK(base::IsStringASCII(function_name
));
172 std::vector
<const base::Value
*> args
;
173 args
.push_back(&arg1
);
174 args
.push_back(&arg2
);
175 args
.push_back(&arg3
);
176 args
.push_back(&arg4
);
177 ExecuteJavascript(GetJavascriptCall(function_name
, args
));
180 void WebUIImpl::CallJavascriptFunction(
181 const std::string
& function_name
,
182 const std::vector
<const base::Value
*>& args
) {
183 DCHECK(base::IsStringASCII(function_name
));
184 ExecuteJavascript(GetJavascriptCall(function_name
, args
));
187 void WebUIImpl::RegisterMessageCallback(const std::string
&message
,
188 const MessageCallback
& callback
) {
189 message_callbacks_
.insert(std::make_pair(message
, callback
));
192 void WebUIImpl::ProcessWebUIMessage(const GURL
& source_url
,
193 const std::string
& message
,
194 const base::ListValue
& args
) {
195 if (controller_
->OverrideHandleWebUIMessage(source_url
, message
, args
))
198 // Look up the callback for this message.
199 MessageCallbackMap::const_iterator callback
=
200 message_callbacks_
.find(message
);
201 if (callback
!= message_callbacks_
.end()) {
202 // Forward this message and content on.
203 callback
->second
.Run(&args
);
205 NOTREACHED() << "Unhandled chrome.send(\"" << message
<< "\");";
209 // WebUIImpl, protected: -------------------------------------------------------
211 void WebUIImpl::AddMessageHandler(WebUIMessageHandler
* handler
) {
212 DCHECK(!handler
->web_ui());
213 handler
->set_web_ui(this);
214 handler
->RegisterMessages();
215 handlers_
.push_back(handler
);
218 void WebUIImpl::ExecuteJavascript(const base::string16
& javascript
) {
219 RenderFrameHost
* target_frame
= TargetFrame();
221 if (!(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
222 target_frame
->GetProcess()->GetID()) ||
223 // It's possible to load about:blank in a Web UI renderer.
224 // See http://crbug.com/42547
225 target_frame
->GetLastCommittedURL().spec() == url::kAboutBlankURL
)) {
226 // Don't crash when we try to inject JavaScript into a non-WebUI page, but
227 // upload a crash report anyways. http://crbug.com/516690
228 base::debug::DumpWithoutCrashing();
231 target_frame
->ExecuteJavaScript(javascript
);
235 RenderFrameHost
* WebUIImpl::TargetFrame() {
236 if (frame_name_
.empty())
237 return web_contents_
->GetMainFrame();
239 std::set
<RenderFrameHost
*> frame_set
;
240 web_contents_
->ForEachFrame(base::Bind(&WebUIImpl::AddToSetIfFrameNameMatches
,
241 base::Unretained(this),
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())
249 return *frame_set
.begin();
252 void WebUIImpl::AddToSetIfFrameNameMatches(
253 std::set
<RenderFrameHost
*>* frame_set
,
254 RenderFrameHost
* host
) {
255 if (host
->GetFrameName() == frame_name_
)
256 frame_set
->insert(host
);
259 } // namespace content