File: speculation_host_impl.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (135 lines) | stat: -rw-r--r-- 4,758 bytes parent folder | download | duplicates (4)
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