summaryrefslogtreecommitdiff
path: root/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
blob: 8936e4ecff8b4987744f097558b5dab5a9b8e4ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/on_load_script_injector/browser/on_load_script_injector_host.h"

#include <utility>

#include "base/numerics/safe_math.h"
#include "base/strings/utf_string_conversions.h"
#include "components/on_load_script_injector/on_load_script_injector.mojom.h"
#include "content/public/browser/render_frame_host.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "url/gurl.h"

namespace on_load_script_injector {

OriginScopedScript::OriginScopedScript() = default;

OriginScopedScript::OriginScopedScript(std::vector<url::Origin> origins,
                                       base::ReadOnlySharedMemoryRegion script)
    : origins_(std::move(origins)), script_(std::move(script)) {}

OriginScopedScript& OriginScopedScript::operator=(OriginScopedScript&& other) {
  origins_ = std::move(other.origins_);
  script_ = std::move(other.script_);
  return *this;
}

OriginScopedScript::~OriginScopedScript() = default;

template <typename ScriptId>
OnLoadScriptInjectorHost<ScriptId>::OnLoadScriptInjectorHost() = default;
template <typename ScriptId>
OnLoadScriptInjectorHost<ScriptId>::~OnLoadScriptInjectorHost() = default;

template <typename ScriptId>
void OnLoadScriptInjectorHost<ScriptId>::AddScript(
    ScriptId id,
    std::vector<url::Origin> origins_to_inject,
    base::StringPiece script) {
  // If there is no script with the identifier |id|, then create a place for
  // it at the end of the injection sequence.
  if (before_load_scripts_.find(id) == before_load_scripts_.end())
    before_load_scripts_order_.push_back(id);

  // Convert script to UTF-16.
  std::u16string script_utf16 = base::UTF8ToUTF16(script);
  size_t script_utf16_size =
      (base::CheckedNumeric<size_t>(script_utf16.size()) * sizeof(char16_t))
          .ValueOrDie();
  base::WritableSharedMemoryRegion script_shared_memory =
      base::WritableSharedMemoryRegion::Create(script_utf16_size);
  memcpy(script_shared_memory.Map().memory(), script_utf16.data(),
         script_utf16_size);

  base::ReadOnlySharedMemoryRegion script_shared_memory_readonly =
      base::WritableSharedMemoryRegion::ConvertToReadOnly(
          std::move(script_shared_memory));
  CHECK(script_shared_memory_readonly.IsValid());

  before_load_scripts_[id] = OriginScopedScript(
      origins_to_inject, std::move(script_shared_memory_readonly));
}

template <typename ScriptId>
void OnLoadScriptInjectorHost<ScriptId>::AddScriptForAllOrigins(
    ScriptId id,
    base::StringPiece script) {
  AddScript(id, {kMatchAllOrigins}, script);
}

template <typename ScriptId>
void OnLoadScriptInjectorHost<ScriptId>::RemoveScript(ScriptId id) {
  before_load_scripts_.erase(id);

  for (auto script_id_iter = before_load_scripts_order_.begin();
       script_id_iter != before_load_scripts_order_.end(); ++script_id_iter) {
    if (*script_id_iter == id) {
      before_load_scripts_order_.erase(script_id_iter);
      return;
    }
  }

  LOG(WARNING) << "Ignoring attempt to remove unknown OnLoad script: " << id;
}

template <typename ScriptId>
void OnLoadScriptInjectorHost<ScriptId>::InjectScriptsForURL(
    const GURL& url,
    content::RenderFrameHost* render_frame_host) {
  DCHECK(url.is_valid());

  mojo::AssociatedRemote<mojom::OnLoadScriptInjector> injector;
  render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&injector);

  injector->ClearOnLoadScripts();

  if (before_load_scripts_.empty())
    return;

  // Provision the renderer's ScriptInjector with the scripts associated with
  // |url|.
  for (ScriptId script_id : before_load_scripts_order_) {
    const OriginScopedScript& script = before_load_scripts_[script_id];
    if (IsUrlMatchedByOriginList(url, script.origins()))
      injector->AddOnLoadScript(script.script().Duplicate());
  }
}

template <typename ScriptId>
bool OnLoadScriptInjectorHost<ScriptId>::IsUrlMatchedByOriginList(
    const GURL& url,
    const std::vector<url::Origin>& allowed_origins) {
  for (const url::Origin& allowed_origin : allowed_origins) {
    if (allowed_origin == kMatchAllOrigins)
      return true;

    DCHECK(!allowed_origin.opaque());
    if (allowed_origin.IsSameOriginWith(url))
      return true;
  }

  return false;
}

template class OnLoadScriptInjectorHost<std::string>;
template class OnLoadScriptInjectorHost<uint64_t>;

}  // namespace on_load_script_injector