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
content / browser / preloading / speculation_rules / speculation_host_impl.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/preloading/speculation_rules/speculation_host_impl.h"
#include <functional>
#include "base/feature_list.h"
#include "content/browser/preloading/prefetch/prefetch_document_manager.h"
#include "content/browser/preloading/preloading_decider.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "third_party/blink/public/common/features.h"
namespace content {
namespace {
bool CandidatesAreValid(
std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) {
for (const auto& candidate : candidates) {
// These non-http candidates should be filtered out in Blink and
// SpeculationHostImpl should not see them. If SpeculationHostImpl receives
// non-http candidates, it may mean the renderer process has a bug
// or is compromised.
if (!candidate->url.SchemeIsHTTPOrHTTPS()) {
mojo::ReportBadMessage("SH_NON_HTTP");
return false;
}
// Only "prerender" action supports `target_browsing_context_name_hint`.
// Invalid Speculation Rules are ignored and invalid candidates are not
// produced in Blink.
if (candidate->action != blink::mojom::SpeculationAction::kPrerender &&
candidate->target_browsing_context_name_hint !=
blink::mojom::SpeculationTargetHint::kNoHint) {
mojo::ReportBadMessage("SH_TARGET_HINT_ON_PREFETCH");
return false;
}
// Only "prefetch" action supports the requirement
// "anonymous-client-ip-when-cross-origin". Invalid Speculation Rules are
// ignored and invalid candidates are not produced in Blink.
if (candidate->action != blink::mojom::SpeculationAction::kPrefetch &&
candidate->requires_anonymous_client_ip_when_cross_origin) {
mojo::ReportBadMessage(
"SH_INVALID_REQUIRES_ANONYMOUS_CLIENT_IP_WHEN_CROSS_ORIGIN");
return false;
}
}
return true;
}
} // namespace
// static
void SpeculationHostImpl::Bind(
RenderFrameHost* frame_host,
mojo::PendingReceiver<blink::mojom::SpeculationHost> receiver) {
CHECK(frame_host);
// DocumentService will destroy this on pipe closure or frame destruction.
new SpeculationHostImpl(*frame_host, std::move(receiver));
}
SpeculationHostImpl::SpeculationHostImpl(
RenderFrameHost& frame_host,
mojo::PendingReceiver<blink::mojom::SpeculationHost> receiver)
: DocumentService(frame_host, std::move(receiver)) {}
SpeculationHostImpl::~SpeculationHostImpl() = default;
void SpeculationHostImpl::UpdateSpeculationCandidates(
std::vector<blink::mojom::SpeculationCandidatePtr> candidates) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!CandidatesAreValid(candidates))
return;
// Only handle messages from an active main frame.
if (!render_frame_host().IsActive())
return;
if (render_frame_host().GetParent())
return;
auto* preloading_decider =
PreloadingDecider::GetOrCreateForCurrentDocument(&render_frame_host());
preloading_decider->UpdateSpeculationCandidates(candidates);
}
void SpeculationHostImpl::OnLCPPredicted() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto* preloading_decider =
PreloadingDecider::GetOrCreateForCurrentDocument(&render_frame_host());
preloading_decider->OnLCPPredicted();
}
void SpeculationHostImpl::InitiatePreview(const GURL& url) {
if (!base::FeatureList::IsEnabled(blink::features::kLinkPreview)) {
mojo::ReportBadMessage("SH_PREVIEW");
return;
}
// Link Preview is not allowed in a frame with untrusted network disabled.
if (render_frame_host().IsUntrustedNetworkDisabled()) {
return;
}
WebContents* web_contents =
WebContents::FromRenderFrameHost(&render_frame_host());
CHECK(web_contents);
WebContentsDelegate* delegate = web_contents->GetDelegate();
CHECK(delegate);
delegate->InitiatePreview(*web_contents, url);
}
} // namespace content