• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params.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*>(&params), 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