js_communication.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2019 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.
  4. #include "components/js_injection/renderer/js_communication.h"
  5. #include "components/js_injection/common/origin_matcher.h"
  6. #include "components/js_injection/renderer/js_binding.h"
  7. #include "content/public/common/isolated_world_ids.h"
  8. #include "content/public/renderer/render_frame.h"
  9. #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
  10. #include "third_party/blink/public/platform/task_type.h"
  11. #include "third_party/blink/public/web/web_local_frame.h"
  12. #include "third_party/blink/public/web/web_script_source.h"
  13. #include "url/gurl.h"
  14. #include "url/origin.h"
  15. namespace js_injection {
  16. struct JsCommunication::JsObjectInfo {
  17. OriginMatcher origin_matcher;
  18. mojo::AssociatedRemote<mojom::JsToBrowserMessaging> js_to_java_messaging;
  19. };
  20. struct JsCommunication::DocumentStartJavaScript {
  21. OriginMatcher origin_matcher;
  22. blink::WebString script;
  23. int32_t script_id;
  24. };
  25. JsCommunication::JsCommunication(content::RenderFrame* render_frame)
  26. : RenderFrameObserver(render_frame),
  27. RenderFrameObserverTracker<JsCommunication>(render_frame) {
  28. render_frame->GetAssociatedInterfaceRegistry()
  29. ->AddInterface<mojom::JsCommunication>(base::BindRepeating(
  30. &JsCommunication::BindPendingReceiver, base::Unretained(this)));
  31. }
  32. JsCommunication::~JsCommunication() = default;
  33. void JsCommunication::SetJsObjects(
  34. std::vector<mojom::JsObjectPtr> js_object_ptrs) {
  35. JsObjectMap js_objects;
  36. for (const auto& js_object : js_object_ptrs) {
  37. const auto& js_object_info_pair = js_objects.insert(
  38. {js_object->js_object_name, std::make_unique<JsObjectInfo>()});
  39. JsObjectInfo* js_object_info = js_object_info_pair.first->second.get();
  40. js_object_info->origin_matcher = js_object->origin_matcher;
  41. js_object_info->js_to_java_messaging =
  42. mojo::AssociatedRemote<mojom::JsToBrowserMessaging>(
  43. std::move(js_object->js_to_browser_messaging));
  44. }
  45. js_objects_.swap(js_objects);
  46. }
  47. void JsCommunication::AddDocumentStartScript(
  48. mojom::DocumentStartJavaScriptPtr script_ptr) {
  49. DocumentStartJavaScript* script = new DocumentStartJavaScript{
  50. script_ptr->origin_matcher,
  51. blink::WebString::FromUTF16(script_ptr->script), script_ptr->script_id};
  52. scripts_.push_back(std::unique_ptr<DocumentStartJavaScript>(script));
  53. }
  54. void JsCommunication::RemoveDocumentStartScript(int32_t script_id) {
  55. for (auto it = scripts_.begin(); it != scripts_.end(); ++it) {
  56. if ((*it)->script_id == script_id) {
  57. scripts_.erase(it);
  58. break;
  59. }
  60. }
  61. }
  62. void JsCommunication::DidClearWindowObject() {
  63. if (inside_did_clear_window_object_)
  64. return;
  65. base::AutoReset<bool> flag_entry(&inside_did_clear_window_object_, true);
  66. // Invalidate `weak_ptr_factory_for_bindings_` so that existing bindings
  67. // can not send messages back to the browser (JsBinding is owned by v8,
  68. // so we can't delete it here).
  69. weak_ptr_factory_for_bindings_.InvalidateWeakPtrs();
  70. url::Origin frame_origin =
  71. url::Origin(render_frame()->GetWebFrame()->GetSecurityOrigin());
  72. std::vector<base::WeakPtr<JsBinding>> js_bindings;
  73. js_bindings.reserve(js_objects_.size());
  74. for (const auto& js_object : js_objects_) {
  75. if (!js_object.second->origin_matcher.Matches(frame_origin))
  76. continue;
  77. base::WeakPtr<JsBinding> js_binding =
  78. JsBinding::Install(render_frame(), js_object.first,
  79. weak_ptr_factory_for_bindings_.GetWeakPtr());
  80. if (js_binding)
  81. js_bindings.push_back(std::move(js_binding));
  82. }
  83. js_bindings_.swap(js_bindings);
  84. }
  85. void JsCommunication::WillReleaseScriptContext(v8::Local<v8::Context> context,
  86. int32_t world_id) {
  87. // We created v8 global objects only in the main world, should clear them only
  88. // when this is for main world.
  89. if (world_id != content::ISOLATED_WORLD_ID_GLOBAL)
  90. return;
  91. for (const auto& js_binding : js_bindings_) {
  92. if (js_binding)
  93. js_binding->ReleaseV8GlobalObjects();
  94. }
  95. }
  96. void JsCommunication::OnDestruct() {
  97. delete this;
  98. }
  99. void JsCommunication::RunScriptsAtDocumentStart() {
  100. url::Origin frame_origin =
  101. url::Origin(render_frame()->GetWebFrame()->GetSecurityOrigin());
  102. for (const auto& script : scripts_) {
  103. if (!script->origin_matcher.Matches(frame_origin))
  104. continue;
  105. render_frame()->GetWebFrame()->ExecuteScript(
  106. blink::WebScriptSource(script->script));
  107. }
  108. }
  109. void JsCommunication::BindPendingReceiver(
  110. mojo::PendingAssociatedReceiver<mojom::JsCommunication> pending_receiver) {
  111. receiver_.reset();
  112. receiver_.Bind(std::move(pending_receiver),
  113. render_frame()->GetTaskRunner(
  114. blink::TaskType::kInternalNavigationAssociated));
  115. }
  116. mojom::JsToBrowserMessaging* JsCommunication::GetJsToJavaMessage(
  117. const std::u16string& js_object_name) {
  118. auto iterator = js_objects_.find(js_object_name);
  119. if (iterator == js_objects_.end())
  120. return nullptr;
  121. return iterator->second->js_to_java_messaging.get();
  122. }
  123. } // namespace js_injection