1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4
5 #include "libcef/renderer/frame_impl.h"
6
7 #include "base/compiler_specific.h"
8
9 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
10 #if defined(OS_WIN)
11 #if defined(__clang__)
12 #pragma GCC diagnostic push
13 #pragma GCC diagnostic error "-Wdeprecated-declarations"
14 #else
15 #pragma warning(push)
16 #pragma warning(default : 4996)
17 #endif
18 #endif
19
20 #include "libcef/common/app_manager.h"
21 #include "libcef/common/cef_messages.h"
22 #include "libcef/common/net/http_header_utils.h"
23 #include "libcef/common/process_message_impl.h"
24 #include "libcef/common/request_impl.h"
25 #include "libcef/common/response_manager.h"
26 #include "libcef/renderer/blink_glue.h"
27 #include "libcef/renderer/browser_impl.h"
28 #include "libcef/renderer/dom_document_impl.h"
29 #include "libcef/renderer/render_frame_util.h"
30 #include "libcef/renderer/render_urlrequest_impl.h"
31 #include "libcef/renderer/thread_util.h"
32 #include "libcef/renderer/v8_impl.h"
33
34 #include "base/strings/utf_string_conversions.h"
35 #include "content/public/renderer/render_view.h"
36 #include "content/renderer/render_frame_impl.h"
37 #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
38 #include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
39 #include "third_party/blink/public/platform/web_data.h"
40 #include "third_party/blink/public/platform/web_string.h"
41 #include "third_party/blink/public/platform/web_url.h"
42 #include "third_party/blink/public/web/blink.h"
43 #include "third_party/blink/public/web/web_document.h"
44 #include "third_party/blink/public/web/web_document_loader.h"
45 #include "third_party/blink/public/web/web_frame_content_dumper.h"
46 #include "third_party/blink/public/web/web_local_frame.h"
47 #include "third_party/blink/public/web/web_navigation_control.h"
48 #include "third_party/blink/public/web/web_script_source.h"
49 #include "third_party/blink/public/web/web_view.h"
50
CefFrameImpl(CefBrowserImpl * browser,blink::WebLocalFrame * frame,int64_t frame_id)51 CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser,
52 blink::WebLocalFrame* frame,
53 int64_t frame_id)
54 : browser_(browser),
55 frame_(frame),
56 frame_id_(frame_id),
57 response_manager_(new CefResponseManager) {}
58
~CefFrameImpl()59 CefFrameImpl::~CefFrameImpl() {}
60
IsValid()61 bool CefFrameImpl::IsValid() {
62 CEF_REQUIRE_RT_RETURN(false);
63
64 return (frame_ != nullptr);
65 }
66
Undo()67 void CefFrameImpl::Undo() {
68 ExecuteCommand("Undo");
69 }
70
Redo()71 void CefFrameImpl::Redo() {
72 ExecuteCommand("Redo");
73 }
74
Cut()75 void CefFrameImpl::Cut() {
76 ExecuteCommand("Cut");
77 }
78
Copy()79 void CefFrameImpl::Copy() {
80 ExecuteCommand("Copy");
81 }
82
Paste()83 void CefFrameImpl::Paste() {
84 ExecuteCommand("Paste");
85 }
86
Delete()87 void CefFrameImpl::Delete() {
88 ExecuteCommand("Delete");
89 }
90
SelectAll()91 void CefFrameImpl::SelectAll() {
92 ExecuteCommand("SelectAll");
93 }
94
ViewSource()95 void CefFrameImpl::ViewSource() {
96 NOTREACHED() << "ViewSource cannot be called from the renderer process";
97 }
98
GetSource(CefRefPtr<CefStringVisitor> visitor)99 void CefFrameImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
100 CEF_REQUIRE_RT_RETURN_VOID();
101 if (frame_) {
102 const CefString& content = blink_glue::DumpDocumentMarkup(frame_);
103 visitor->Visit(content);
104 }
105 }
106
GetText(CefRefPtr<CefStringVisitor> visitor)107 void CefFrameImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
108 CEF_REQUIRE_RT_RETURN_VOID();
109 if (frame_) {
110 const CefString& content = blink_glue::DumpDocumentText(frame_);
111 visitor->Visit(content);
112 }
113 }
114
LoadRequest(CefRefPtr<CefRequest> request)115 void CefFrameImpl::LoadRequest(CefRefPtr<CefRequest> request) {
116 CEF_REQUIRE_RT_RETURN_VOID();
117
118 if (!frame_)
119 return;
120
121 CefMsg_LoadRequest_Params params;
122 params.url = GURL(std::string(request->GetURL()));
123 params.method = request->GetMethod();
124 params.site_for_cookies = net::SiteForCookies::FromUrl(
125 GURL(request->GetFirstPartyForCookies().ToString()));
126
127 CefRequest::HeaderMap headerMap;
128 request->GetHeaderMap(headerMap);
129 if (!headerMap.empty())
130 params.headers = HttpHeaderUtils::GenerateHeaders(headerMap);
131
132 CefRefPtr<CefPostData> postData = request->GetPostData();
133 if (postData.get()) {
134 CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postData.get());
135 params.upload_data = new net::UploadData();
136 impl->Get(*params.upload_data.get());
137 }
138
139 params.load_flags = request->GetFlags();
140
141 OnLoadRequest(params);
142 }
143
LoadURL(const CefString & url)144 void CefFrameImpl::LoadURL(const CefString& url) {
145 CEF_REQUIRE_RT_RETURN_VOID();
146
147 if (!frame_)
148 return;
149
150 CefMsg_LoadRequest_Params params;
151 params.url = GURL(url.ToString());
152 params.method = "GET";
153
154 OnLoadRequest(params);
155 }
156
ExecuteJavaScript(const CefString & jsCode,const CefString & scriptUrl,int startLine)157 void CefFrameImpl::ExecuteJavaScript(const CefString& jsCode,
158 const CefString& scriptUrl,
159 int startLine) {
160 CEF_REQUIRE_RT_RETURN_VOID();
161
162 if (jsCode.empty())
163 return;
164 if (startLine < 1)
165 startLine = 1;
166
167 if (frame_) {
168 GURL gurl = GURL(scriptUrl.ToString());
169 frame_->ExecuteScript(blink::WebScriptSource(
170 blink::WebString::FromUTF16(jsCode.ToString16()), gurl, startLine));
171 }
172 }
173
IsMain()174 bool CefFrameImpl::IsMain() {
175 CEF_REQUIRE_RT_RETURN(false);
176
177 if (frame_)
178 return (frame_->Parent() == nullptr);
179 return false;
180 }
181
IsFocused()182 bool CefFrameImpl::IsFocused() {
183 CEF_REQUIRE_RT_RETURN(false);
184
185 if (frame_ && frame_->View())
186 return (frame_->View()->FocusedFrame() == frame_);
187 return false;
188 }
189
GetName()190 CefString CefFrameImpl::GetName() {
191 CefString name;
192 CEF_REQUIRE_RT_RETURN(name);
193
194 if (frame_)
195 name = render_frame_util::GetName(frame_);
196 return name;
197 }
198
GetIdentifier()199 int64 CefFrameImpl::GetIdentifier() {
200 CEF_REQUIRE_RT_RETURN(0);
201
202 return frame_id_;
203 }
204
GetParent()205 CefRefPtr<CefFrame> CefFrameImpl::GetParent() {
206 CEF_REQUIRE_RT_RETURN(nullptr);
207
208 if (frame_) {
209 blink::WebFrame* parent = frame_->Parent();
210 if (parent && parent->IsWebLocalFrame())
211 return browser_->GetWebFrameImpl(parent->ToWebLocalFrame()).get();
212 }
213
214 return nullptr;
215 }
216
GetURL()217 CefString CefFrameImpl::GetURL() {
218 CefString url;
219 CEF_REQUIRE_RT_RETURN(url);
220
221 if (frame_) {
222 GURL gurl = frame_->GetDocument().Url();
223 url = gurl.spec();
224 }
225 return url;
226 }
227
GetBrowser()228 CefRefPtr<CefBrowser> CefFrameImpl::GetBrowser() {
229 CEF_REQUIRE_RT_RETURN(nullptr);
230
231 return browser_;
232 }
233
GetV8Context()234 CefRefPtr<CefV8Context> CefFrameImpl::GetV8Context() {
235 CEF_REQUIRE_RT_RETURN(nullptr);
236
237 if (frame_) {
238 v8::Isolate* isolate = blink::MainThreadIsolate();
239 v8::HandleScope handle_scope(isolate);
240 return new CefV8ContextImpl(isolate, frame_->MainWorldScriptContext());
241 } else {
242 return nullptr;
243 }
244 }
245
VisitDOM(CefRefPtr<CefDOMVisitor> visitor)246 void CefFrameImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
247 CEF_REQUIRE_RT_RETURN_VOID();
248
249 if (!frame_)
250 return;
251
252 // Create a CefDOMDocumentImpl object that is valid only for the scope of this
253 // method.
254 CefRefPtr<CefDOMDocumentImpl> documentImpl;
255 const blink::WebDocument& document = frame_->GetDocument();
256 if (!document.IsNull())
257 documentImpl = new CefDOMDocumentImpl(browser_, frame_);
258
259 visitor->Visit(documentImpl.get());
260
261 if (documentImpl.get())
262 documentImpl->Detach();
263 }
264
CreateURLRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client)265 CefRefPtr<CefURLRequest> CefFrameImpl::CreateURLRequest(
266 CefRefPtr<CefRequest> request,
267 CefRefPtr<CefURLRequestClient> client) {
268 CEF_REQUIRE_RT_RETURN(nullptr);
269
270 if (!request || !client || !frame_)
271 return nullptr;
272
273 CefRefPtr<CefRenderURLRequest> impl =
274 new CefRenderURLRequest(this, request, client);
275 if (impl->Start())
276 return impl.get();
277 return nullptr;
278 }
279
SendProcessMessage(CefProcessId target_process,CefRefPtr<CefProcessMessage> message)280 void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
281 CefRefPtr<CefProcessMessage> message) {
282 Cef_Request_Params params;
283 CefProcessMessageImpl* impl =
284 static_cast<CefProcessMessageImpl*>(message.get());
285 if (impl->CopyTo(params)) {
286 SendProcessMessage(target_process, params.name, ¶ms.arguments, true);
287 }
288 }
289
CreateURLLoader()290 std::unique_ptr<blink::WebURLLoader> CefFrameImpl::CreateURLLoader() {
291 CEF_REQUIRE_RT();
292 if (!frame_)
293 return nullptr;
294
295 if (!url_loader_factory_) {
296 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
297 if (render_frame) {
298 url_loader_factory_ = render_frame->CreateURLLoaderFactory();
299 }
300 }
301 if (!url_loader_factory_)
302 return nullptr;
303
304 // KeepAlive is not supported.
305 mojo::PendingRemote<blink::mojom::KeepAliveHandle> keep_alive_handle =
306 mojo::NullRemote();
307
308 return url_loader_factory_->CreateURLLoader(
309 blink::WebURLRequest(),
310 blink_glue::CreateResourceLoadingTaskRunnerHandle(frame_),
311 blink_glue::CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(frame_),
312 std::move(keep_alive_handle), blink::WebBackForwardCacheLoaderHelper());
313 }
314
315 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
CreateResourceLoadInfoNotifierWrapper()316 CefFrameImpl::CreateResourceLoadInfoNotifierWrapper() {
317 CEF_REQUIRE_RT();
318 if (frame_) {
319 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
320 if (render_frame)
321 return render_frame->CreateResourceLoadInfoNotifierWrapper();
322 }
323 return nullptr;
324 }
325
OnAttached()326 void CefFrameImpl::OnAttached() {
327 Send(new CefHostMsg_FrameAttached(MSG_ROUTING_NONE));
328 }
329
OnMessageReceived(const IPC::Message & message)330 bool CefFrameImpl::OnMessageReceived(const IPC::Message& message) {
331 bool handled = true;
332 IPC_BEGIN_MESSAGE_MAP(CefFrameImpl, message)
333 IPC_MESSAGE_HANDLER(CefMsg_Request, OnRequest)
334 IPC_MESSAGE_HANDLER(CefMsg_Response, OnResponse)
335 IPC_MESSAGE_HANDLER(CefMsg_ResponseAck, OnResponseAck)
336 IPC_MESSAGE_HANDLER(CefMsg_LoadRequest, OnLoadRequest)
337 IPC_MESSAGE_HANDLER(CefMsg_DidStopLoading, OnDidStopLoading)
338 IPC_MESSAGE_HANDLER(CefMsg_MoveOrResizeStarted, OnMoveOrResizeStarted)
339 IPC_MESSAGE_UNHANDLED(handled = false)
340 IPC_END_MESSAGE_MAP()
341 return handled;
342 }
343
OnDidFinishLoad()344 void CefFrameImpl::OnDidFinishLoad() {
345 // Ignore notifications from the embedded frame hosting a mime-type plugin.
346 // We'll eventually receive a notification from the owner frame.
347 if (blink_glue::HasPluginFrameOwner(frame_))
348 return;
349
350 blink::WebDocumentLoader* dl = frame_->GetDocumentLoader();
351 const int http_status_code = dl->GetResponse().HttpStatusCode();
352 Send(new CefHostMsg_DidFinishLoad(MSG_ROUTING_NONE, dl->GetUrl(),
353 http_status_code));
354
355 CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
356 if (app) {
357 CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
358 if (handler) {
359 CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
360 if (load_handler) {
361 load_handler->OnLoadEnd(browser_, this, http_status_code);
362 }
363 }
364 }
365 }
366
OnDraggableRegionsChanged()367 void CefFrameImpl::OnDraggableRegionsChanged() {
368 blink::WebVector<blink::WebDraggableRegion> webregions =
369 frame_->GetDocument().DraggableRegions();
370 std::vector<Cef_DraggableRegion_Params> regions;
371 for (size_t i = 0; i < webregions.size(); ++i) {
372 Cef_DraggableRegion_Params region;
373 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
374 render_frame->ConvertViewportToWindow(&webregions[i].bounds);
375 region.bounds = webregions[i].bounds;
376 region.draggable = webregions[i].draggable;
377 regions.push_back(region);
378 }
379 Send(new CefHostMsg_UpdateDraggableRegions(MSG_ROUTING_NONE, regions));
380 }
381
OnDetached()382 void CefFrameImpl::OnDetached() {
383 // The browser may hold the last reference to |this|. Take a reference here to
384 // keep |this| alive until after this method returns.
385 CefRefPtr<CefFrameImpl> self = this;
386
387 browser_->FrameDetached(frame_id_);
388
389 browser_ = nullptr;
390 frame_ = nullptr;
391 url_loader_factory_.reset();
392 response_manager_.reset();
393 }
394
ExecuteCommand(const std::string & command)395 void CefFrameImpl::ExecuteCommand(const std::string& command) {
396 CEF_REQUIRE_RT_RETURN_VOID();
397 if (frame_)
398 frame_->ExecuteCommand(blink::WebString::FromUTF8(command));
399 }
400
SendProcessMessage(CefProcessId target_process,const std::string & name,base::ListValue * arguments,bool user_initiated)401 void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
402 const std::string& name,
403 base::ListValue* arguments,
404 bool user_initiated) {
405 DCHECK_EQ(PID_BROWSER, target_process);
406 DCHECK(!name.empty());
407
408 if (!frame_)
409 return;
410
411 Cef_Request_Params params;
412 params.name = name;
413 if (arguments)
414 params.arguments.Swap(arguments);
415 params.user_initiated = user_initiated;
416 params.request_id = -1;
417 params.expect_response = false;
418
419 Send(new CefHostMsg_Request(MSG_ROUTING_NONE, params));
420 }
421
Send(IPC::Message * message)422 void CefFrameImpl::Send(IPC::Message* message) {
423 if (!frame_) {
424 delete message;
425 return;
426 }
427
428 auto render_frame = content::RenderFrame::FromWebFrame(frame_);
429 message->set_routing_id(render_frame->GetRoutingID());
430 render_frame->Send(message);
431 }
432
OnRequest(const Cef_Request_Params & params)433 void CefFrameImpl::OnRequest(const Cef_Request_Params& params) {
434 DCHECK(browser_);
435 DCHECK(frame_);
436
437 bool success = false;
438 std::string response;
439 bool expect_response_ack = false;
440
441 TRACE_EVENT2("cef", "CefBrowserImpl::OnRequest", "request_id",
442 params.request_id, "expect_response",
443 params.expect_response ? 1 : 0);
444
445 if (params.user_initiated) {
446 // Give the user a chance to handle the request.
447 CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
448 if (app.get()) {
449 CefRefPtr<CefRenderProcessHandler> handler =
450 app->GetRenderProcessHandler();
451 if (handler.get()) {
452 CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
453 const_cast<Cef_Request_Params*>(¶ms), false, true));
454 success = handler->OnProcessMessageReceived(browser_, this, PID_BROWSER,
455 message.get());
456 message->Detach(nullptr);
457 }
458 }
459 } else if (params.name == "execute-code") {
460 // Execute code.
461 DCHECK_EQ(params.arguments.GetSize(), (size_t)4);
462
463 bool is_javascript = false;
464 std::string code, script_url;
465 int script_start_line = 0;
466
467 params.arguments.GetBoolean(0, &is_javascript);
468 params.arguments.GetString(1, &code);
469 DCHECK(!code.empty());
470 params.arguments.GetString(2, &script_url);
471 params.arguments.GetInteger(3, &script_start_line);
472 DCHECK_GE(script_start_line, 0);
473
474 if (is_javascript) {
475 frame_->ExecuteScript(
476 blink::WebScriptSource(blink::WebString::FromUTF8(code),
477 GURL(script_url), script_start_line));
478 success = true;
479 } else {
480 // TODO(cef): implement support for CSS code.
481 NOTIMPLEMENTED();
482 }
483 } else if (params.name == "execute-command") {
484 // Execute command.
485 DCHECK_EQ(params.arguments.GetSize(), (size_t)1);
486
487 std::string command;
488
489 params.arguments.GetString(0, &command);
490 DCHECK(!command.empty());
491
492 if (base::LowerCaseEqualsASCII(command, "getsource")) {
493 response = blink_glue::DumpDocumentMarkup(frame_);
494 success = true;
495 } else if (base::LowerCaseEqualsASCII(command, "gettext")) {
496 response = blink_glue::DumpDocumentText(frame_);
497 success = true;
498 } else if (frame_->ExecuteCommand(blink::WebString::FromUTF8(command))) {
499 success = true;
500 }
501 } else {
502 // Invalid request.
503 NOTREACHED();
504 }
505
506 if (params.expect_response) {
507 DCHECK_GE(params.request_id, 0);
508
509 // Send a response to the browser.
510 Cef_Response_Params response_params;
511 response_params.request_id = params.request_id;
512 response_params.success = success;
513 response_params.response = response;
514 response_params.expect_response_ack = expect_response_ack;
515 Send(new CefHostMsg_Response(MSG_ROUTING_NONE, response_params));
516 }
517 }
518
OnResponse(const Cef_Response_Params & params)519 void CefFrameImpl::OnResponse(const Cef_Response_Params& params) {
520 response_manager_->RunHandler(params);
521 if (params.expect_response_ack)
522 Send(new CefHostMsg_ResponseAck(MSG_ROUTING_NONE, params.request_id));
523 }
524
OnResponseAck(int request_id)525 void CefFrameImpl::OnResponseAck(int request_id) {
526 response_manager_->RunAckHandler(request_id);
527 }
528
OnDidStopLoading()529 void CefFrameImpl::OnDidStopLoading() {
530 // We should only receive this notification for the highest-level LocalFrame
531 // in this frame's in-process subtree. If there are multiple of these for the
532 // same browser then the other occurrences will be discarded in
533 // OnLoadingStateChange.
534 browser_->OnLoadingStateChange(false);
535 }
536
OnMoveOrResizeStarted()537 void CefFrameImpl::OnMoveOrResizeStarted() {
538 if (frame_) {
539 auto web_view = frame_->View();
540 if (web_view)
541 web_view->CancelPagePopup();
542 }
543 }
544
OnLoadRequest(const CefMsg_LoadRequest_Params & params)545 void CefFrameImpl::OnLoadRequest(const CefMsg_LoadRequest_Params& params) {
546 DCHECK(frame_);
547
548 blink::WebURLRequest request;
549 CefRequestImpl::Get(params, request);
550
551 blink_glue::StartNavigation(frame_, request);
552 }
553
554 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
555 #if defined(OS_WIN)
556 #if defined(__clang__)
557 #pragma GCC diagnostic pop
558 #else
559 #pragma warning(pop)
560 #endif
561 #endif
562