electron_api_ipc_handler_impl.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright (c) 2022 Slack Technologies, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/electron_api_ipc_handler_impl.h"
  5. #include <utility>
  6. #include "content/public/browser/render_frame_host.h"
  7. #include "content/public/browser/render_process_host.h"
  8. #include "gin/handle.h"
  9. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  10. #include "shell/browser/api/electron_api_session.h"
  11. #include "shell/common/gin_converters/content_converter.h"
  12. #include "shell/common/gin_converters/frame_converter.h"
  13. #include "shell/common/gin_helper/event.h"
  14. namespace electron {
  15. ElectronApiIPCHandlerImpl::ElectronApiIPCHandlerImpl(
  16. content::RenderFrameHost* frame_host,
  17. mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver)
  18. : render_frame_host_id_(frame_host->GetGlobalId()) {
  19. content::WebContents* web_contents =
  20. content::WebContents::FromRenderFrameHost(frame_host);
  21. DCHECK(web_contents);
  22. content::WebContentsObserver::Observe(web_contents);
  23. receiver_.Bind(std::move(receiver));
  24. receiver_.set_disconnect_handler(base::BindOnce(
  25. &ElectronApiIPCHandlerImpl::OnConnectionError, GetWeakPtr()));
  26. }
  27. ElectronApiIPCHandlerImpl::~ElectronApiIPCHandlerImpl() = default;
  28. void ElectronApiIPCHandlerImpl::WebContentsDestroyed() {
  29. delete this;
  30. }
  31. void ElectronApiIPCHandlerImpl::OnConnectionError() {
  32. delete this;
  33. }
  34. void ElectronApiIPCHandlerImpl::Message(bool internal,
  35. const std::string& channel,
  36. blink::CloneableMessage arguments) {
  37. auto* session = GetSession();
  38. v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  39. v8::HandleScope handle_scope(isolate);
  40. auto event = MakeIPCEvent(isolate, session, internal);
  41. if (event.IsEmpty())
  42. return;
  43. session->Message(event, channel, std::move(arguments));
  44. }
  45. void ElectronApiIPCHandlerImpl::Invoke(bool internal,
  46. const std::string& channel,
  47. blink::CloneableMessage arguments,
  48. InvokeCallback callback) {
  49. auto* session = GetSession();
  50. v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  51. v8::HandleScope handle_scope(isolate);
  52. auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
  53. if (event.IsEmpty())
  54. return;
  55. session->Invoke(event, channel, std::move(arguments));
  56. }
  57. void ElectronApiIPCHandlerImpl::ReceivePostMessage(
  58. const std::string& channel,
  59. blink::TransferableMessage message) {
  60. auto* session = GetSession();
  61. v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  62. v8::HandleScope handle_scope(isolate);
  63. auto event = MakeIPCEvent(isolate, session, false);
  64. if (event.IsEmpty())
  65. return;
  66. session->ReceivePostMessage(event, channel, std::move(message));
  67. }
  68. void ElectronApiIPCHandlerImpl::MessageSync(bool internal,
  69. const std::string& channel,
  70. blink::CloneableMessage arguments,
  71. MessageSyncCallback callback) {
  72. auto* session = GetSession();
  73. v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  74. v8::HandleScope handle_scope(isolate);
  75. auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
  76. if (event.IsEmpty())
  77. return;
  78. session->MessageSync(event, channel, std::move(arguments));
  79. }
  80. void ElectronApiIPCHandlerImpl::MessageHost(const std::string& channel,
  81. blink::CloneableMessage arguments) {
  82. auto* session = GetSession();
  83. v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  84. v8::HandleScope handle_scope(isolate);
  85. auto event = MakeIPCEvent(isolate, session, false);
  86. if (event.IsEmpty())
  87. return;
  88. session->MessageHost(event, channel, std::move(arguments));
  89. }
  90. content::RenderFrameHost* ElectronApiIPCHandlerImpl::GetRenderFrameHost() {
  91. return content::RenderFrameHost::FromID(render_frame_host_id_);
  92. }
  93. api::Session* ElectronApiIPCHandlerImpl::GetSession() {
  94. auto* rfh = GetRenderFrameHost();
  95. return rfh ? api::Session::FromBrowserContext(rfh->GetBrowserContext())
  96. : nullptr;
  97. }
  98. gin::Handle<gin_helper::internal::Event>
  99. ElectronApiIPCHandlerImpl::MakeIPCEvent(
  100. v8::Isolate* isolate,
  101. api::Session* session,
  102. bool internal,
  103. electron::mojom::ElectronApiIPC::InvokeCallback callback) {
  104. if (!session) {
  105. if (callback) {
  106. // We must always invoke the callback if present.
  107. gin_helper::internal::ReplyChannel::Create(isolate, std::move(callback))
  108. ->SendError("Session does not exist");
  109. }
  110. return {};
  111. }
  112. api::WebContents* api_web_contents = api::WebContents::From(web_contents());
  113. if (!api_web_contents) {
  114. if (callback) {
  115. // We must always invoke the callback if present.
  116. gin_helper::internal::ReplyChannel::Create(isolate, std::move(callback))
  117. ->SendError("WebContents does not exist");
  118. }
  119. return {};
  120. }
  121. v8::Local<v8::Object> wrapper;
  122. if (!api_web_contents->GetWrapper(isolate).ToLocal(&wrapper)) {
  123. if (callback) {
  124. // We must always invoke the callback if present.
  125. gin_helper::internal::ReplyChannel::Create(isolate, std::move(callback))
  126. ->SendError("WebContents was destroyed");
  127. }
  128. return {};
  129. }
  130. content::RenderFrameHost* frame = GetRenderFrameHost();
  131. gin::Handle<gin_helper::internal::Event> event =
  132. gin_helper::internal::Event::New(isolate);
  133. gin_helper::Dictionary dict(isolate, event.ToV8().As<v8::Object>());
  134. dict.Set("type", "frame");
  135. dict.Set("sender", web_contents());
  136. if (internal)
  137. dict.SetHidden("internal", internal);
  138. if (callback)
  139. dict.Set("_replyChannel", gin_helper::internal::ReplyChannel::Create(
  140. isolate, std::move(callback)));
  141. if (frame) {
  142. dict.SetGetter("senderFrame", frame);
  143. dict.Set("frameId", frame->GetRoutingID());
  144. dict.Set("processId", frame->GetProcess()->GetID().GetUnsafeValue());
  145. dict.Set("frameTreeNodeId", frame->GetFrameTreeNodeId());
  146. }
  147. return event;
  148. }
  149. // static
  150. void ElectronApiIPCHandlerImpl::Create(
  151. content::RenderFrameHost* frame_host,
  152. mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver) {
  153. new ElectronApiIPCHandlerImpl(frame_host, std::move(receiver));
  154. }
  155. } // namespace electron