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 132 133 134 135
|
// 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 "base/strings/string_util.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;
}
// Speculation rules tags must contain at least one tag. When no tags are
// specified in rules, this should contain std::nullopt that represents a
// null tag.
if (candidate->tags.empty()) {
mojo::ReportBadMessage("SH_EMPTY_TAGS");
return false;
}
// All speculation rules tags must be valid tokens and std::nullopt is valid
// by definition.
for (auto& tag : candidate->tags) {
if (tag.has_value() &&
!std::all_of(tag.value().begin(), tag.value().end(),
base::IsAsciiPrintable<char>)) {
mojo::ReportBadMessage("SH_INVALID_TAG");
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
|