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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
content / browser / reduce_accept_language / reduce_accept_language_utils.h [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_REDUCE_ACCEPT_LANGUAGE_REDUCE_ACCEPT_LANGUAGE_UTILS_H_
#define CONTENT_BROWSER_REDUCE_ACCEPT_LANGUAGE_REDUCE_ACCEPT_LANGUAGE_UTILS_H_
#include "content/common/content_export.h"
#include "content/public/browser/origin_trials_controller_delegate.h"
#include "content/public/browser/reduce_accept_language_controller_delegate.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/mojom/parsed_headers.mojom-forward.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
class FrameTreeNode;
// This class is a collection of utils used by navigation requests to reduce the
// fingerprinting surface of the Accept-Language header. See
// https://github.com/Tanych/accept-language.
class CONTENT_EXPORT ReduceAcceptLanguageUtils {
public:
explicit ReduceAcceptLanguageUtils(
ReduceAcceptLanguageControllerDelegate& delegate);
~ReduceAcceptLanguageUtils();
// No copy constructor and no copy assignment operator.
ReduceAcceptLanguageUtils(const ReduceAcceptLanguageUtils&) = delete;
ReduceAcceptLanguageUtils& operator=(const ReduceAcceptLanguageUtils&) =
delete;
// Create and return a ReduceAcceptLanguageUtils instance based on provided
// `browser_context`.
static std::optional<ReduceAcceptLanguageUtils> Create(
BrowserContext* browser_context);
// Returns true if `accept_language` matches `content_language` using the
// Basic Filtering scheme. See RFC4647 of Section 3.3.
static bool DoesAcceptLanguageMatchContentLanguage(
const std::string& accept_language,
const std::string& content_language);
// Starting from each preferred language in `preferred_languages` in order,
// return the first matched language if the language matches any language in
// `available_languages`, otherwise return std::nullopt. The matching
// algorithm is that if any language in `available_languages` is a wildcard or
// matches the language `preferred_languages`, return the matched language as
// preferred language.
static std::optional<std::string> GetFirstMatchPreferredLanguage(
const std::vector<std::string>& preferred_languages,
const std::vector<std::string>& available_languages);
// Returns whether reduce accept language can happen for the given URL.
// This is true only if the URL is eligible.
//
// `request_origin` is the origin to be used for reduced accept language
// storage.
//
// TODO(crbug.com/40224802) confirm with CSP sandbox owner if language
// preferences need to be hidden from sandboxed origins.
static bool OriginCanReduceAcceptLanguage(const url::Origin& request_origin);
// Return true if the given `request_origin` opted into the
// ReduceAcceptLanguage deprecation origin trial. This method can only be
// called on the UI thread.
static bool CheckDisableReduceAcceptLanguageOriginTrial(
const GURL& request_url,
FrameTreeNode* frame_tree_node,
OriginTrialsControllerDelegate* origin_trials_delegate);
// Updates the accept-language present in headers and returns the reduced
// accept language added to accept-language header. This is called when
// NavigationRequest was created and when language value changes after
// the NavigationRequest was created.
//
// See `OriginCanReduceAcceptLanguage` for `request_origin`.
std::optional<std::string> AddNavigationRequestAcceptLanguageHeaders(
const url::Origin& request_origin,
FrameTreeNode* frame_tree_node,
net::HttpRequestHeaders* headers);
// Reads incoming language and persists it to HostContentSettingsMap prefs
// storage as appropriate. Returns a bool indicating whether it needs to
// resend the request.
bool ReadAndPersistAcceptLanguageForNavigation(
const url::Origin& request_origin,
const net::HttpRequestHeaders& request_headers,
const network::mojom::ParsedHeadersPtr& parsed_headers);
// Looks up which reduced accept language should be used.
//
// Warning: This could potentially clear the persisted language in pref
// storage if the persisted language can't be found in the user's
// Accept-Language.
//
// This is based on the top-level document's origin.
// - For main frame navigation, this is the origin of the new document to
// commit, given by `request_origin`.
// - For iframe navigations, this is the current top-level document's origin
// retrieved via `frame_tree_node`.
//
// See `OriginCanReduceAcceptLanguage` for `request_origin`.
std::optional<std::string> LookupReducedAcceptLanguage(
const url::Origin& request_origin,
FrameTreeNode* frame_tree_node);
// Remove the persisted language for the given top-level document's `origin`.
void RemoveReducedAcceptLanguage(const url::Origin& origin,
FrameTreeNode* frame_tree_node);
private:
// Captures the state used in applying persist accept language.
struct PersistLanguageResult {
PersistLanguageResult();
PersistLanguageResult(const PersistLanguageResult& other);
~PersistLanguageResult();
// If true, navigation request needs to resend the requests with the
// modified accept language header.
bool should_resend_request = false;
std::optional<std::string> language_to_persist = std::nullopt;
};
// Returns whether to persist a language selection based on the given language
// information at response time, and also whether the request needs to be
// restarted.
PersistLanguageResult GetLanguageToPersist(
const std::string& initial_accept_language,
const std::vector<std::string>& content_languages,
const std::vector<std::string>& preferred_languages,
const std::vector<std::string>& available_languages);
// Return the origin to look up the persisted language.
//
// The reduced accept language should be based on the outermost main
// document's origin in most cases. If this call is being made for the
// outermost main document, then the NavigationRequest has not yet committed
// and we must use the origin from the in-flight NavigationRequest. Subframes
// and sub-pages (except Fenced Frames) can use the outermost main document's
// last committed origin. Otherwise, it will result in a nullopt return value.
//
// TODO(https://github.com/WICG/fenced-frame/issues/39) decide whether
// Fenced Frames should be treated as an internally-consistent Page, with
// language negotiation for the inner main document and/or subframes
// that match the main document.
static std::optional<url::Origin> GetOriginForLanguageLookup(
const url::Origin& request_origin,
FrameTreeNode* frame_tree_node);
// The delegate is owned by the BrowserContext, which should always outlive
// this utility class.
raw_ref<ReduceAcceptLanguageControllerDelegate, DanglingUntriaged> delegate_;
};
} // namespace content
#endif // CONTENT_BROWSER_REDUCE_ACCEPT_LANGUAGE_REDUCE_ACCEPT_LANGUAGE_UTILS_H_