summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorCronet Mainline Eng <cronet-mainline-eng+copybara@google.com>2023-04-18 07:37:34 -0800
committerPatrick Rohr <prohr@google.com>2023-04-18 08:40:26 -0700
commiteddec18c18cdbcbdbbe9bf3c0fa24cb7f8d768ae (patch)
tree2983326030c4b680835550dca47bc960e77c492f /net
parent41cb724250484f326b0bbd5f8b955eb37b3b83c6 (diff)
downloadcronet-eddec18c18cdbcbdbbe9bf3c0fa24cb7f8d768ae.tar.gz
Import Cronet version 114.0.5715.0
Project import generated by Copybara. FolderOrigin-RevId: /tmp/copybara-origin/src Test: none Change-Id: I15627f4badf0f6173d24f6c555169cc815a29fdd
Diffstat (limited to 'net')
-rw-r--r--net/BUILD.gn17
-rw-r--r--net/android/dummy_spnego_authenticator.h5
-rw-r--r--net/base/address_map_cache_linux.cc49
-rw-r--r--net/base/address_map_cache_linux.h51
-rw-r--r--net/base/address_map_linux.h14
-rw-r--r--net/base/address_tracker_linux.cc80
-rw-r--r--net/base/address_tracker_linux.h74
-rw-r--r--net/base/address_tracker_linux_fuzzer.cc2
-rw-r--r--net/base/address_tracker_linux_unittest.cc48
-rw-r--r--net/base/features.cc9
-rw-r--r--net/base/features.h11
-rw-r--r--net/base/ip_address.cc18
-rw-r--r--net/base/parse_number.h2
-rw-r--r--net/cert/cert_verifier.cc32
-rw-r--r--net/cert/cert_verifier.h8
-rw-r--r--net/cert/cert_verify_proc.cc17
-rw-r--r--net/cert/cert_verify_proc.h45
-rw-r--r--net/cert/cert_verify_proc_builtin.cc12
-rw-r--r--net/cert/cert_verify_proc_unittest.cc66
-rw-r--r--net/cert/multi_threaded_cert_verifier.cc8
-rw-r--r--net/cert/multi_threaded_cert_verifier.h4
-rw-r--r--net/cert/multi_threaded_cert_verifier_unittest.cc38
-rw-r--r--net/cert/pki/string_util.h2
-rw-r--r--net/cert/trial_comparison_cert_verifier.cc108
-rw-r--r--net/cert/trial_comparison_cert_verifier.h50
-rw-r--r--net/cert/trial_comparison_cert_verifier_unittest.cc420
-rw-r--r--net/cookies/cookie_inclusion_status.h3
-rw-r--r--net/cookies/cookie_monster_change_dispatcher.cc38
-rw-r--r--net/cookies/cookie_monster_change_dispatcher.h6
-rw-r--r--net/cookies/cookie_store_change_unittest.h155
-rw-r--r--net/data/ssl/certificates/README2
-rw-r--r--net/data/ssl/certificates/vrk_gov_root.pem84
-rw-r--r--net/data/test_support_bundle_data.filelist1
-rw-r--r--net/dns/address_sorter_posix.cc28
-rw-r--r--net/first_party_sets/addition_overlaps_union_find.h2
-rw-r--r--net/first_party_sets/global_first_party_sets.cc51
-rw-r--r--net/first_party_sets/global_first_party_sets.h4
-rw-r--r--net/http/http_cache.cc2
-rw-r--r--net/http/http_cache.h2
-rw-r--r--net/http/http_network_transaction.cc205
-rw-r--r--net/http/http_network_transaction.h50
-rw-r--r--net/http/http_status_code_list.h1
-rw-r--r--net/http/http_stream.cc18
-rw-r--r--net/http/http_stream.h11
-rw-r--r--net/http/transport_security_state_static.pins4
-rw-r--r--net/log/net_log_event_type_list.h29
-rw-r--r--net/nqe/network_quality_estimator.cc106
-rw-r--r--net/nqe/network_quality_estimator.h21
-rw-r--r--net/nqe/network_quality_estimator_unittest.cc149
-rw-r--r--net/quic/quic_http_stream.cc17
-rw-r--r--net/quic/quic_http_stream.h6
-rw-r--r--net/socket/ssl_client_socket_impl.cc28
-rw-r--r--net/socket/udp_socket_posix.cc8
-rw-r--r--net/socket/udp_socket_posix.h4
-rw-r--r--net/socket/udp_socket_win.cc8
-rw-r--r--net/socket/udp_socket_win.h6
-rw-r--r--net/ssl/ssl_config_service.cc19
-rw-r--r--net/ssl/ssl_config_service.h16
-rw-r--r--net/test/embedded_test_server/http_request.cc3
-rw-r--r--net/third_party/quiche/src/WORKSPACE.bazel12
-rw-r--r--net/third_party/quiche/src/build/source_list.bzl3
-rw-r--r--net/third_party/quiche/src/build/source_list.gni3
-rw-r--r--net/third_party/quiche/src/build/source_list.json3
-rw-r--r--net/third_party/quiche/src/quiche/BUILD.bazel1
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc51
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h2
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h2
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_ssa_pss_verifier.h2
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/testing/utils.cc12
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth.cc19
-rw-r--r--net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth_test.cc2
-rw-r--r--net/third_party/quiche/src/quiche/common/btree_scheduler.h297
-rw-r--r--net/third_party/quiche/src/quiche/common/btree_scheduler_fuzzer.cc46
-rw-r--r--net/third_party/quiche/src/quiche/common/btree_scheduler_test.cc281
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/chlo_extractor.cc2
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/chlo_extractor.h2
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/http/end_to_end_test.cc34
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_connection.cc46
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_connection.h25
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_connection_test.cc55
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.cc1
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_dispatcher_test.cc6
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_types.cc14
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_types.h2
-rw-r--r--net/third_party/quiche/src/quiche/quic/core/quic_utils_test.cc7
-rw-r--r--net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc6
-rw-r--r--net/third_party/quiche/src/quiche/quic/masque/masque_client_session.h6
-rw-r--r--net/third_party/quiche/src/quiche/quic/masque/masque_client_tools.cc37
-rw-r--r--net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.cc6
-rw-r--r--net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h3
-rw-r--r--net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.cc3
-rw-r--r--net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h3
-rw-r--r--net/url_request/url_request_test_job.cc2
-rw-r--r--net/url_request/url_request_test_job.h2
-rw-r--r--net/url_request/url_request_unittest.cc12
95 files changed, 2380 insertions, 907 deletions
diff --git a/net/BUILD.gn b/net/BUILD.gn
index e2953c9b4..ade5bfdff 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -660,6 +660,7 @@ component("net") {
"http/http_status_code.cc",
"http/http_status_code.h",
"http/http_status_code_list.h",
+ "http/http_stream.cc",
"http/http_stream.h",
"http/http_stream_factory.cc",
"http/http_stream_factory.h",
@@ -1218,6 +1219,13 @@ component("net") {
]
}
+ if (is_linux) {
+ sources += [
+ "base/address_map_cache_linux.cc",
+ "base/address_map_cache_linux.h",
+ ]
+ }
+
if (is_chromeos) {
deps += [ "//third_party/xdg_shared_mime_info" ]
}
@@ -3060,7 +3068,6 @@ test("net_unittests") {
"websockets/websocket_deflate_predictor_impl_test.cc",
"websockets/websocket_deflate_stream_test.cc",
"websockets/websocket_deflater_test.cc",
- "websockets/websocket_end_to_end_test.cc",
"websockets/websocket_errors_test.cc",
"websockets/websocket_extension_parser_test.cc",
"websockets/websocket_extension_test.cc",
@@ -3076,6 +3083,14 @@ test("net_unittests") {
"websockets/websocket_test_util.cc",
"websockets/websocket_test_util.h",
]
+
+ if (!is_ios) {
+ # TODO(crbug.com/1281277): iOS does not have support for the spawned test
+ # server, which is used by this test. The long term plan is to add
+ # websocket support to the embedded test server and when that happens,
+ # this test could be enabled.
+ sources += [ "websockets/websocket_end_to_end_test.cc" ]
+ }
}
if (!disable_file_support) {
diff --git a/net/android/dummy_spnego_authenticator.h b/net/android/dummy_spnego_authenticator.h
index f2f22f667..6a3981db9 100644
--- a/net/android/dummy_spnego_authenticator.h
+++ b/net/android/dummy_spnego_authenticator.h
@@ -12,6 +12,7 @@
#include <string>
#include "base/android/scoped_java_ref.h"
+#include "base/memory/raw_ptr_exclusion.h"
// Provides an interface for controlling the DummySpnegoAuthenticator service.
// This includes a basic stub of the Mock GSSAPI library, so that OS independent
@@ -26,7 +27,9 @@ namespace net {
typedef struct gss_OID_desc_struct {
uint32_t length;
- void* elements;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #global-scope
+ RAW_PTR_EXCLUSION void* elements;
} gss_OID_desc, *gss_OID;
extern gss_OID CHROME_GSS_SPNEGO_MECH_OID_DESC;
diff --git a/net/base/address_map_cache_linux.cc b/net/base/address_map_cache_linux.cc
new file mode 100644
index 000000000..13aefdc22
--- /dev/null
+++ b/net/base/address_map_cache_linux.cc
@@ -0,0 +1,49 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/address_map_cache_linux.h"
+
+#include <linux/rtnetlink.h>
+
+#include "base/synchronization/lock.h"
+
+namespace net {
+
+AddressMapCacheLinux::AddressMapCacheLinux() = default;
+AddressMapCacheLinux::~AddressMapCacheLinux() = default;
+
+AddressMapOwnerLinux::AddressMap AddressMapCacheLinux::GetAddressMap() const {
+ base::AutoLock autolock(lock_);
+ return cached_address_map_;
+}
+
+std::unordered_set<int> AddressMapCacheLinux::GetOnlineLinks() const {
+ base::AutoLock autolock(lock_);
+ return cached_online_links_;
+}
+
+void AddressMapCacheLinux::ApplyDiffs(const AddressMapDiff& addr_diff,
+ const OnlineLinksDiff& links_diff) {
+ base::AutoLock autolock(lock_);
+ for (const auto& [address, msg_opt] : addr_diff) {
+ if (msg_opt.has_value()) {
+ cached_address_map_[address] = msg_opt.value();
+ } else {
+ DCHECK(cached_address_map_.count(address));
+ cached_address_map_.erase(address);
+ }
+ }
+
+ for (const auto& [if_index, is_now_online] : links_diff) {
+ if (is_now_online) {
+ DCHECK_EQ(cached_online_links_.count(if_index), 0u);
+ cached_online_links_.insert(if_index);
+ } else {
+ DCHECK_EQ(cached_online_links_.count(if_index), 1u);
+ cached_online_links_.erase(if_index);
+ }
+ }
+}
+
+} // namespace net
diff --git a/net/base/address_map_cache_linux.h b/net/base/address_map_cache_linux.h
new file mode 100644
index 000000000..8c45c6c87
--- /dev/null
+++ b/net/base/address_map_cache_linux.h
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_ADDRESS_MAP_CACHE_LINUX_H_
+#define NET_BASE_ADDRESS_MAP_CACHE_LINUX_H_
+
+#include <map>
+#include <string>
+#include <unordered_set>
+
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "net/base/address_map_linux.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// This caches AddressMap and the set of online links (see AddressMapOwnerLinux)
+// so AddressTrackerLinux doesn't need to always be running in every process.
+// This class is thread-safe.
+class NET_EXPORT AddressMapCacheLinux : public AddressMapOwnerLinux {
+ public:
+ AddressMapCacheLinux();
+
+ AddressMapCacheLinux(const AddressMapCacheLinux&) = delete;
+ AddressMapCacheLinux& operator=(const AddressMapCacheLinux&) = delete;
+
+ ~AddressMapCacheLinux() override;
+
+ // AddressMapOwnerLinux implementation:
+ AddressMap GetAddressMap() const override;
+ std::unordered_set<int> GetOnlineLinks() const override;
+
+ // Takes the diffs and applies them (atomically) to `cached_address_map_` and
+ // `cached_online_links_`.
+ // Once this method returns, calls on other threads to GetAddressMap() and
+ // GetOnlineLinks() that happen-after this call should return the updated
+ // data.
+ void ApplyDiffs(const AddressMapDiff& addr_diff,
+ const OnlineLinksDiff& links_diff);
+
+ private:
+ mutable base::Lock lock_;
+ AddressMap cached_address_map_ GUARDED_BY(lock_);
+ std::unordered_set<int> cached_online_links_ GUARDED_BY(lock_);
+};
+
+} // namespace net
+
+#endif // NET_BASE_ADDRESS_MAP_CACHE_LINUX_H_
diff --git a/net/base/address_map_linux.h b/net/base/address_map_linux.h
index 49bc35bb9..6f10b112b 100644
--- a/net/base/address_map_linux.h
+++ b/net/base/address_map_linux.h
@@ -29,6 +29,20 @@ class NET_EXPORT AddressMapOwnerLinux {
// with (e.g. interface index).
using AddressMap = std::map<IPAddress, struct ifaddrmsg>;
+ // Represents a diff between one AddressMap and a new one. IPAddresses that
+ // map to absl::nullopt have been deleted from the map, and IPAddresses that
+ // map to non-nullopt have been added or updated.
+ using AddressMapDiff =
+ base::flat_map<IPAddress, absl::optional<struct ifaddrmsg>>;
+ // Represents a diff between one set of online links and new one. Interface
+ // indices that map to true are newly online and indices that map to false are
+ // newly offline.
+ using OnlineLinksDiff = base::flat_map<int, bool>;
+ // A callback for diffs, to be used by AddressTrackerLinux.
+ using DiffCallback =
+ base::RepeatingCallback<void(const AddressMapDiff& addr_diff,
+ const OnlineLinksDiff&)>;
+
AddressMapOwnerLinux() = default;
AddressMapOwnerLinux(const AddressMapOwnerLinux&) = delete;
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc
index d90e022b2..431820f20 100644
--- a/net/base/address_tracker_linux.cc
+++ b/net/base/address_tracker_linux.cc
@@ -15,6 +15,7 @@
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/sequence_checker.h"
#include "base/task/current_thread.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/thread_restrictions.h"
@@ -172,11 +173,13 @@ AddressTrackerLinux::AddressTrackerLinux(
tracking_(true) {
DCHECK(!address_callback.is_null());
DCHECK(!link_callback.is_null());
+ DETACH_FROM_SEQUENCE(sequence_checker_);
}
AddressTrackerLinux::~AddressTrackerLinux() = default;
void AddressTrackerLinux::Init() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
#if BUILDFLAG(IS_ANDROID)
// RTM_GETLINK stopped working in Android 11 (see
// https://developer.android.com/preview/privacy/mac-address),
@@ -241,7 +244,8 @@ void AddressTrackerLinux::Init() {
bool address_changed;
bool link_changed;
bool tunnel_changed;
- ReadMessages(&address_changed, &link_changed, &tunnel_changed);
+ ReadMessages(&address_changed, &link_changed, &tunnel_changed, nullptr,
+ nullptr);
// Request dump of link state
request.header.nlmsg_type = RTM_GETLINK;
@@ -256,7 +260,8 @@ void AddressTrackerLinux::Init() {
}
// Consume pending message to populate links_online_, but don't notify.
- ReadMessages(&address_changed, &link_changed, &tunnel_changed);
+ ReadMessages(&address_changed, &link_changed, &tunnel_changed, nullptr,
+ nullptr);
{
AddressTrackerAutoLock lock(*this, connection_type_lock_);
connection_type_initialized_ = true;
@@ -272,11 +277,13 @@ void AddressTrackerLinux::Init() {
}
bool AddressTrackerLinux::DidTrackingInitSucceedForTesting() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(tracking_);
return watcher_ != nullptr;
}
void AddressTrackerLinux::AbortAndForceOnline() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
watcher_.reset();
netlink_fd_.reset();
AddressTrackerAutoLock lock(*this, connection_type_lock_);
@@ -295,7 +302,28 @@ std::unordered_set<int> AddressTrackerLinux::GetOnlineLinks() const {
return online_links_;
}
+void AddressTrackerLinux::SetDiffCallback(DiffCallback diff_callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ diff_callback_ = std::move(diff_callback);
+
+ // Send the initial configuration to the diff callback.
+ AddressMap address_map = GetAddressMap();
+ AddressMapDiff address_map_diff;
+ for (const std::pair<const IPAddress, struct ifaddrmsg>& it : address_map) {
+ address_map_diff[it.first] = it.second;
+ }
+
+ std::unordered_set<int> online_links = GetOnlineLinks();
+ OnlineLinksDiff online_links_diff;
+ for (int online_link : online_links) {
+ online_links_diff[online_link] = true;
+ }
+
+ diff_callback_.Run(address_map_diff, online_links_diff);
+}
+
bool AddressTrackerLinux::IsInterfaceIgnored(int interface_index) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (ignored_interfaces_.empty())
return false;
@@ -320,7 +348,10 @@ AddressTrackerLinux::GetCurrentConnectionType() {
void AddressTrackerLinux::ReadMessages(bool* address_changed,
bool* link_changed,
- bool* tunnel_changed) {
+ bool* tunnel_changed,
+ AddressMapDiff* address_map_diff,
+ OnlineLinksDiff* online_links_diff) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
*address_changed = false;
*link_changed = false;
*tunnel_changed = false;
@@ -349,7 +380,8 @@ void AddressTrackerLinux::ReadMessages(bool* address_changed,
PLOG(ERROR) << "Failed to recv from netlink socket";
return;
}
- HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed);
+ HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed,
+ address_map_diff, online_links_diff);
}
}
if (*link_changed || *address_changed)
@@ -360,7 +392,10 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
int length,
bool* address_changed,
bool* link_changed,
- bool* tunnel_changed) {
+ bool* tunnel_changed,
+ AddressMapDiff* address_map_diff,
+ OnlineLinksDiff* online_links_diff) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(buffer);
// Note that NLMSG_NEXT decrements |length| to reflect the number of bytes
// remaining in |buffer|.
@@ -411,6 +446,9 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
it->second = msg_copy;
*address_changed = true;
}
+ if (*address_changed && address_map_diff) {
+ (*address_map_diff)[address] = msg_copy;
+ }
}
} break;
case RTM_DELADDR: {
@@ -423,8 +461,12 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
break;
if (GetAddress(header, length, &address, nullptr)) {
AddressTrackerAutoLock lock(*this, address_map_lock_);
- if (address_map_.erase(address))
+ if (address_map_.erase(address)) {
*address_changed = true;
+ if (address_map_diff) {
+ (*address_map_diff)[address] = absl::nullopt;
+ }
+ }
}
} break;
case RTM_NEWLINK: {
@@ -443,6 +485,9 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
AddressTrackerAutoLock lock(*this, online_links_lock_);
if (online_links_.insert(msg->ifi_index).second) {
*link_changed = true;
+ if (online_links_diff) {
+ (*online_links_diff)[msg->ifi_index] = true;
+ }
if (IsTunnelInterface(msg->ifi_index))
*tunnel_changed = true;
}
@@ -450,6 +495,9 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
AddressTrackerAutoLock lock(*this, online_links_lock_);
if (online_links_.erase(msg->ifi_index)) {
*link_changed = true;
+ if (online_links_diff) {
+ (*online_links_diff)[msg->ifi_index] = false;
+ }
if (IsTunnelInterface(msg->ifi_index))
*tunnel_changed = true;
}
@@ -465,6 +513,9 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
AddressTrackerAutoLock lock(*this, online_links_lock_);
if (online_links_.erase(msg->ifi_index)) {
*link_changed = true;
+ if (online_links_diff) {
+ (*online_links_diff)[msg->ifi_index] = false;
+ }
if (IsTunnelInterface(msg->ifi_index))
*tunnel_changed = true;
}
@@ -476,10 +527,20 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
}
void AddressTrackerLinux::OnFileCanReadWithoutBlocking() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
bool address_changed;
bool link_changed;
bool tunnel_changed;
- ReadMessages(&address_changed, &link_changed, &tunnel_changed);
+ if (diff_callback_) {
+ AddressMapDiff address_map_diff;
+ OnlineLinksDiff online_links_diff;
+ ReadMessages(&address_changed, &link_changed, &tunnel_changed,
+ &address_map_diff, &online_links_diff);
+ diff_callback_.Run(address_map_diff, online_links_diff);
+ } else {
+ ReadMessages(&address_changed, &link_changed, &tunnel_changed, nullptr,
+ nullptr);
+ }
if (address_changed)
address_callback_.Run();
if (link_changed)
@@ -500,6 +561,7 @@ bool AddressTrackerLinux::IsTunnelInterfaceName(const char* name) {
}
void AddressTrackerLinux::UpdateCurrentConnectionType() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddressTrackerLinux::AddressMap address_map = GetAddressMap();
std::unordered_set<int> online_links = GetOnlineLinks();
@@ -539,7 +601,7 @@ AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock(
if (tracker_->tracking_) {
lock_->Acquire();
} else {
- DCHECK(tracker_->thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(tracker_->sequence_checker_);
}
}
@@ -547,6 +609,8 @@ AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() {
if (tracker_->tracking_) {
lock_->AssertAcquired();
lock_->Release();
+ } else {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(tracker_->sequence_checker_);
}
}
diff --git a/net/base/address_tracker_linux.h b/net/base/address_tracker_linux.h
index 3ac4f30a5..dea5f2057 100644
--- a/net/base/address_tracker_linux.h
+++ b/net/base/address_tracker_linux.h
@@ -25,9 +25,10 @@
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ref.h"
+#include "base/sequence_checker.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
+#include "base/thread_annotations.h"
#include "net/base/address_map_linux.h"
#include "net/base/ip_address.h"
#include "net/base/net_export.h"
@@ -79,6 +80,17 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux : public AddressMapOwnerLinux {
// Returns set of interface indices for online interfaces.
std::unordered_set<int> GetOnlineLinks() const override;
+ // Whenever the AddressMap or the set of online links (returned by the above
+ // two methods) changes, this callback is called on AddressTrackerLinux's
+ // sequence. On the first call, |diff_callback| is called synchronously with
+ // the current AddressMap and set of online links.
+ //
+ // This is only available in tracking mode, and must be called on
+ // AddressTrackerLinux's sequence. Note that other threads may see updated
+ // AddressMaps by calling GetAddressMap() before |diff_callback| is ever
+ // called.
+ void SetDiffCallback(DiffCallback diff_callback);
+
// Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
// Safe to call from any thread, but will block until Init() has completed.
NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();
@@ -103,13 +115,13 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux : public AddressMapOwnerLinux {
// In tracking mode, holds |lock| while alive. In non-tracking mode,
// enforces single-threaded access.
- class AddressTrackerAutoLock {
+ class SCOPED_LOCKABLE AddressTrackerAutoLock {
public:
- AddressTrackerAutoLock(const AddressTrackerLinux& tracker,
- base::Lock& lock);
+ AddressTrackerAutoLock(const AddressTrackerLinux& tracker, base::Lock& lock)
+ EXCLUSIVE_LOCK_FUNCTION(lock);
AddressTrackerAutoLock(const AddressTrackerAutoLock&) = delete;
AddressTrackerAutoLock& operator=(const AddressTrackerAutoLock&) = delete;
- ~AddressTrackerAutoLock();
+ ~AddressTrackerAutoLock() UNLOCK_FUNCTION();
private:
const raw_ref<const AddressTrackerLinux> tracker_;
@@ -125,19 +137,35 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux : public AddressMapOwnerLinux {
// sets |*link_changed| to indicate if |online_links_| changed and sets
// |*tunnel_changed| to indicate if |online_links_| changed with regards to a
// tunnel interface while reading messages from |netlink_fd_|.
+ //
+ // If |address_map_| has changed and |address_map_diff| is not nullptr,
+ // |*address_map_diff| is populated with the changes to the AddressMap.
+ // Similarly, if |online_links_| has changed and |online_links_diff| is not
+ // nullptr, |*online_links_diff| is populated with the changes to the set of
+ // online links.
void ReadMessages(bool* address_changed,
bool* link_changed,
- bool* tunnel_changed);
+ bool* tunnel_changed,
+ AddressMapDiff* address_map_diff,
+ OnlineLinksDiff* online_links_diff);
// Sets |*address_changed| to true if |address_map_| changed, sets
// |*link_changed| to true if |online_links_| changed, sets |*tunnel_changed|
// to true if |online_links_| changed with regards to a tunnel interface while
// reading the message from |buffer|.
+ //
+ // If |address_map_| has changed and |address_map_diff| is not nullptr,
+ // |*address_map_diff| is populated with the changes to the AddressMap.
+ // Similarly, if |online_links_| has changed and |online_links_diff| is not
+ // nullptr, |*online_links_diff| is populated with the changes to the set of
+ // online links.
void HandleMessage(const char* buffer,
int length,
bool* address_changed,
bool* link_changed,
- bool* tunnel_changed);
+ bool* tunnel_changed,
+ AddressMapDiff* address_map_diff,
+ OnlineLinksDiff* online_links_diff);
// Call when some part of initialization failed; forces online and unblocks.
void AbortAndForceOnline();
@@ -167,34 +195,38 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux : public AddressMapOwnerLinux {
// overridden by tests.
GetInterfaceNameFunction get_interface_name_;
- base::RepeatingClosure address_callback_;
- base::RepeatingClosure link_callback_;
- base::RepeatingClosure tunnel_callback_;
+ DiffCallback diff_callback_ GUARDED_BY_CONTEXT(sequence_checker_);
+ base::RepeatingClosure address_callback_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+ base::RepeatingClosure link_callback_ GUARDED_BY_CONTEXT(sequence_checker_);
+ base::RepeatingClosure tunnel_callback_ GUARDED_BY_CONTEXT(sequence_checker_);
// Note that |watcher_| must be inactive when |netlink_fd_| is closed.
- base::ScopedFD netlink_fd_;
- std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
+ base::ScopedFD netlink_fd_ GUARDED_BY_CONTEXT(sequence_checker_);
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_
+ GUARDED_BY_CONTEXT(sequence_checker_);
mutable base::Lock address_map_lock_;
- AddressMap address_map_;
+ AddressMap address_map_ GUARDED_BY(address_map_lock_);
// Set of interface indices for links that are currently online.
mutable base::Lock online_links_lock_;
- std::unordered_set<int> online_links_;
+ std::unordered_set<int> online_links_ GUARDED_BY(online_links_lock_);
// Set of interface names that should be ignored.
const std::unordered_set<std::string> ignored_interfaces_;
base::Lock connection_type_lock_;
- bool connection_type_initialized_ = false;
+ bool connection_type_initialized_ GUARDED_BY(connection_type_lock_) = false;
base::ConditionVariable connection_type_initialized_cv_;
- NetworkChangeNotifier::ConnectionType current_connection_type_ =
- NetworkChangeNotifier::CONNECTION_NONE;
- bool tracking_;
- int threads_waiting_for_connection_type_initialization_ = 0;
+ NetworkChangeNotifier::ConnectionType current_connection_type_ GUARDED_BY(
+ connection_type_lock_) = NetworkChangeNotifier::CONNECTION_NONE;
+ int threads_waiting_for_connection_type_initialization_
+ GUARDED_BY(connection_type_lock_) = 0;
+
+ const bool tracking_;
- // Used to verify single-threaded access in non-tracking mode.
- base::ThreadChecker thread_checker_;
+ SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace net::internal
diff --git a/net/base/address_tracker_linux_fuzzer.cc b/net/base/address_tracker_linux_fuzzer.cc
index 7a0fd530a..0013d88e9 100644
--- a/net/base/address_tracker_linux_fuzzer.cc
+++ b/net/base/address_tracker_linux_fuzzer.cc
@@ -18,7 +18,7 @@ class AddressTrackerLinuxTest {
base::DoNothing(), ignored_interfaces);
bool address_changed, link_changed, tunnel_changed;
tracker.HandleMessage(buffer, length, &address_changed, &link_changed,
- &tunnel_changed);
+ &tunnel_changed, nullptr, nullptr);
}
};
diff --git a/net/base/address_tracker_linux_unittest.cc b/net/base/address_tracker_linux_unittest.cc
index 00a0bc7be..2a83474bb 100644
--- a/net/base/address_tracker_linux_unittest.cc
+++ b/net/base/address_tracker_linux_unittest.cc
@@ -5,6 +5,7 @@
#include "net/base/address_tracker_linux.h"
#include <linux/if.h>
+#include <linux/rtnetlink.h>
#include <sched.h>
#include <memory>
@@ -18,12 +19,14 @@
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/bind.h"
#include "base/test/multiprocess_test.h"
#include "base/test/spin_wait.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/simple_thread.h"
#include "build/build_config.h"
+#include "net/base/address_map_cache_linux.h"
#include "net/base/ip_address.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -36,6 +39,10 @@
#define IFA_F_HOMEADDRESS 0x10
#endif
+bool operator==(const struct ifaddrmsg& lhs, const struct ifaddrmsg& rhs) {
+ return memcmp(&lhs, &rhs, sizeof(struct ifaddrmsg)) == 0;
+}
+
namespace net::internal {
namespace {
@@ -84,8 +91,12 @@ class AddressTrackerLinuxTest : public testing::Test {
bool address_changed = false;
bool link_changed = false;
bool tunnel_changed = false;
- tracker_->HandleMessage(&writable_buf[0], buf.size(),
- &address_changed, &link_changed, &tunnel_changed);
+ AddressMapOwnerLinux::AddressMapDiff address_map_diff_;
+ AddressMapOwnerLinux::OnlineLinksDiff online_links_diff_;
+ tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_changed,
+ &link_changed, &tunnel_changed, &address_map_diff_,
+ &online_links_diff_);
+ UpdateCache(address_map_diff_, online_links_diff_);
EXPECT_FALSE(link_changed);
return address_changed;
}
@@ -95,8 +106,12 @@ class AddressTrackerLinuxTest : public testing::Test {
bool address_changed = false;
bool link_changed = false;
bool tunnel_changed = false;
- tracker_->HandleMessage(&writable_buf[0], buf.size(),
- &address_changed, &link_changed, &tunnel_changed);
+ AddressMapOwnerLinux::AddressMapDiff address_map_diff_;
+ AddressMapOwnerLinux::OnlineLinksDiff online_links_diff_;
+ tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_changed,
+ &link_changed, &tunnel_changed, &address_map_diff_,
+ &online_links_diff_);
+ UpdateCache(address_map_diff_, online_links_diff_);
EXPECT_FALSE(address_changed);
return link_changed;
}
@@ -106,8 +121,12 @@ class AddressTrackerLinuxTest : public testing::Test {
bool address_changed = false;
bool link_changed = false;
bool tunnel_changed = false;
- tracker_->HandleMessage(&writable_buf[0], buf.size(),
- &address_changed, &link_changed, &tunnel_changed);
+ AddressMapOwnerLinux::AddressMapDiff address_map_diff_;
+ AddressMapOwnerLinux::OnlineLinksDiff online_links_diff_;
+ tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_changed,
+ &link_changed, &tunnel_changed, &address_map_diff_,
+ &online_links_diff_);
+ UpdateCache(address_map_diff_, online_links_diff_);
EXPECT_FALSE(address_changed);
return tunnel_changed;
}
@@ -131,6 +150,23 @@ class AddressTrackerLinuxTest : public testing::Test {
std::unordered_set<std::string> ignored_interfaces_;
std::unique_ptr<AddressTrackerLinux> tracker_;
AddressTrackerLinux::GetInterfaceNameFunction original_get_interface_name_;
+
+ private:
+ // Checks that applying the generated diff to `address_map_cache_` results in
+ // the same AddressMap and set of online links that `tracker_` maintains.
+ void UpdateCache(
+ const AddressMapOwnerLinux::AddressMapDiff& address_map_diff,
+ const AddressMapOwnerLinux::OnlineLinksDiff& online_links_diff) {
+#if BUILDFLAG(IS_LINUX)
+ address_map_cache_.ApplyDiffs(address_map_diff, online_links_diff);
+ EXPECT_EQ(address_map_cache_.GetAddressMap(), tracker_->GetAddressMap());
+ EXPECT_EQ(address_map_cache_.GetOnlineLinks(), tracker_->GetOnlineLinks());
+#endif // BUILDFLAG(IS_LINUX)
+ }
+
+#if BUILDFLAG(IS_LINUX)
+ AddressMapCacheLinux address_map_cache_;
+#endif
};
namespace {
diff --git a/net/base/features.cc b/net/base/features.cc
index f4b8dbc6a..5d5178bc0 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -134,15 +134,6 @@ BASE_FEATURE(kPostQuantumKyber,
"PostQuantumKyber",
base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kPostQuantumCECPQ2,
- "PostQuantumCECPQ2",
- base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kPostQuantumCECPQ2SomeDomains,
- "PostQuantumCECPQ2SomeDomains",
- base::FEATURE_DISABLED_BY_DEFAULT);
-const base::FeatureParam<std::string>
- kPostQuantumCECPQ2Prefix(&kPostQuantumCECPQ2SomeDomains, "prefix", "a");
-
BASE_FEATURE(kNetUnusedIdleSocketTimeout,
"NetUnusedIdleSocketTimeout",
base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/net/base/features.h b/net/base/features.h
index 0ba56e82b..bf578bebb 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -175,17 +175,6 @@ NET_EXPORT BASE_DECLARE_FEATURE(kPermuteTLSExtensions);
// Enables Kyber-based post-quantum key-agreements in TLS 1.3 connections.
NET_EXPORT BASE_DECLARE_FEATURE(kPostQuantumKyber);
-// Enables CECPQ2, a post-quantum key-agreement, in TLS 1.3 connections.
-// Ineffective if kPostQuantumKyber is enabled.
-NET_EXPORT BASE_DECLARE_FEATURE(kPostQuantumCECPQ2);
-
-// Enables CECPQ2, a post-quantum key-agreement, in TLS 1.3 connections for a
-// subset of domains. (This is intended as Finch kill-switch. For testing
-// compatibility with large ClientHello messages, use |kPostQuantumCECPQ2|.)
-NET_EXPORT BASE_DECLARE_FEATURE(kPostQuantumCECPQ2SomeDomains);
-NET_EXPORT extern const base::FeatureParam<std::string>
- kPostQuantumCECPQ2Prefix;
-
// Changes the timeout after which unused sockets idle sockets are cleaned up.
NET_EXPORT BASE_DECLARE_FEATURE(kNetUnusedIdleSocketTimeout);
diff --git a/net/base/ip_address.cc b/net/base/ip_address.cc
index 45a915c19..eb0a7094c 100644
--- a/net/base/ip_address.cc
+++ b/net/base/ip_address.cc
@@ -419,17 +419,7 @@ std::string IPAddressToPackedString(const IPAddress& address) {
}
IPAddress ConvertIPv4ToIPv4MappedIPv6(const IPAddress& address) {
- // TODO(https://crbug.com/1414007): Remove crash key and use DCHECK() when
- // the cause is identified.
- if (!address.IsIPv4()) {
- static base::debug::CrashKeyString* crash_key =
- base::debug::AllocateCrashKeyString("ipaddress",
- base::debug::CrashKeySize::Size64);
- base::debug::ScopedCrashKeyString addr(crash_key, address.ToString());
- bool is_valid = address.IsValid();
- base::debug::Alias(&is_valid);
- LOG(FATAL) << "expected an IPv4 address but got " << address.ToString();
- }
+ CHECK(address.IsIPv4());
// IPv4-mapped addresses are formed by:
// <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
base::StackVector<uint8_t, 16> bytes;
@@ -454,10 +444,10 @@ bool IPAddressMatchesPrefix(const IPAddress& ip_address,
size_t prefix_length_in_bits) {
// Both the input IP address and the prefix IP address should be either IPv4
// or IPv6.
- DCHECK(ip_address.IsValid());
- DCHECK(ip_prefix.IsValid());
+ CHECK(ip_address.IsValid());
+ CHECK(ip_prefix.IsValid());
- DCHECK_LE(prefix_length_in_bits, ip_prefix.size() * 8);
+ CHECK_LE(prefix_length_in_bits, ip_prefix.size() * 8);
// In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
// IPv6 addresses in order to do the comparison.
diff --git a/net/base/parse_number.h b/net/base/parse_number.h
index f4827f7a7..f923b18a7 100644
--- a/net/base/parse_number.h
+++ b/net/base/parse_number.h
@@ -5,6 +5,8 @@
#ifndef NET_BASE_PARSE_NUMBER_H_
#define NET_BASE_PARSE_NUMBER_H_
+#include <cstdint>
+
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
diff --git a/net/cert/cert_verifier.cc b/net/cert/cert_verifier.cc
index f87fc159d..cfb73ea63 100644
--- a/net/cert/cert_verifier.cc
+++ b/net/cert/cert_verifier.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/strings/string_util.h"
+#include "base/types/optional_util.h"
#include "build/build_config.h"
#include "net/base/features.h"
#include "net/cert/caching_cert_verifier.h"
@@ -27,29 +28,25 @@ class DefaultCertVerifyProcFactory : public net::CertVerifyProcFactory {
public:
scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc(
scoped_refptr<net::CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const net::ChromeRootStoreData* root_store_data) override {
- scoped_refptr<net::CertVerifyProc> verify_proc;
+ const CertVerifyProcFactory::ImplParams& impl_params) override {
#if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
- if (!verify_proc &&
- base::FeatureList::IsEnabled(features::kChromeRootStoreUsed)) {
- verify_proc = CertVerifyProc::CreateBuiltinWithChromeRootStore(
- std::move(cert_net_fetcher), std::move(crl_set), root_store_data);
+ if (impl_params.use_chrome_root_store) {
+ return CertVerifyProc::CreateBuiltinWithChromeRootStore(
+ std::move(cert_net_fetcher), impl_params.crl_set,
+ base::OptionalToPtr(impl_params.root_store_data));
}
#endif
- if (!verify_proc) {
#if BUILDFLAG(CHROME_ROOT_STORE_ONLY)
- verify_proc = CertVerifyProc::CreateBuiltinWithChromeRootStore(
- std::move(cert_net_fetcher), std::move(crl_set), root_store_data);
+ return CertVerifyProc::CreateBuiltinWithChromeRootStore(
+ std::move(cert_net_fetcher), impl_params.crl_set,
+ base::OptionalToPtr(impl_params.root_store_data));
#elif BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- verify_proc = CertVerifyProc::CreateBuiltinVerifyProc(
- std::move(cert_net_fetcher), std::move(crl_set));
+ return CertVerifyProc::CreateBuiltinVerifyProc(std::move(cert_net_fetcher),
+ impl_params.crl_set);
#else
- verify_proc = CertVerifyProc::CreateSystemVerifyProc(
- std::move(cert_net_fetcher), std::move(crl_set));
+ return CertVerifyProc::CreateSystemVerifyProc(std::move(cert_net_fetcher),
+ impl_params.crl_set);
#endif
- }
- return verify_proc;
}
private:
@@ -119,8 +116,7 @@ CertVerifier::CreateDefaultWithoutCaching(
scoped_refptr<CertNetFetcher> cert_net_fetcher) {
auto proc_factory = base::MakeRefCounted<DefaultCertVerifyProcFactory>();
return std::make_unique<MultiThreadedCertVerifier>(
- proc_factory->CreateCertVerifyProc(std::move(cert_net_fetcher),
- net::CRLSet::BuiltinCRLSet(), nullptr),
+ proc_factory->CreateCertVerifyProc(std::move(cert_net_fetcher), {}),
proc_factory);
}
diff --git a/net/cert/cert_verifier.h b/net/cert/cert_verifier.h
index 19b2520c1..026ffc8ec 100644
--- a/net/cert/cert_verifier.h
+++ b/net/cert/cert_verifier.h
@@ -16,15 +16,14 @@
#include "net/base/hash_value.h"
#include "net/base/net_export.h"
#include "net/cert/cert_net_fetcher.h"
+#include "net/cert/cert_verify_proc.h"
#include "net/cert/x509_certificate.h"
namespace net {
class CertVerifyResult;
class CertVerifierWithUpdatableProc;
-class CRLSet;
class NetLogWithSource;
-class ChromeRootStoreData;
// CertVerifier represents a service for verifying certificates.
//
@@ -239,11 +238,10 @@ NET_EXPORT bool operator!=(const CertVerifier::Config& lhs,
// A CertVerifier that can update its CertVerifyProc while it is running.
class NET_EXPORT CertVerifierWithUpdatableProc : public CertVerifier {
public:
- // Update the CertVerifyProc with new CRLSet and ChromeRootStoreData.
+ // Update the CertVerifyProc with a new set of parameters.
virtual void UpdateVerifyProcData(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) = 0;
+ const net::CertVerifyProcFactory::ImplParams& impl_params) = 0;
};
} // namespace net
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index a9b1d6de4..8f4ed6e1b 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -892,4 +892,21 @@ bool CertVerifyProc::HasTooLongValidity(const X509Certificate& cert) {
return false;
}
+CertVerifyProcFactory::ImplParams::ImplParams() {
+ crl_set = net::CRLSet::BuiltinCRLSet();
+#if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+ use_chrome_root_store =
+ base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed);
+#endif
+}
+
+CertVerifyProcFactory::ImplParams::~ImplParams() = default;
+
+CertVerifyProcFactory::ImplParams::ImplParams(const ImplParams&) = default;
+CertVerifyProcFactory::ImplParams& CertVerifyProcFactory::ImplParams::operator=(
+ const ImplParams& other) = default;
+CertVerifyProcFactory::ImplParams::ImplParams(ImplParams&&) = default;
+CertVerifyProcFactory::ImplParams& CertVerifyProcFactory::ImplParams::operator=(
+ ImplParams&& other) = default;
+
} // namespace net
diff --git a/net/cert/cert_verify_proc.h b/net/cert/cert_verify_proc.h
index f1d698f82..31401d45f 100644
--- a/net/cert/cert_verify_proc.h
+++ b/net/cert/cert_verify_proc.h
@@ -17,6 +17,10 @@
#include "net/base/net_export.h"
#include "net/net_buildflags.h"
+#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+#include "net/cert/internal/trust_store_chrome.h"
+#endif
+
namespace net {
class CertNetFetcher;
@@ -24,7 +28,6 @@ class CertVerifyResult;
class CRLSet;
class NetLogWithSource;
class X509Certificate;
-class ChromeRootStoreData;
typedef std::vector<scoped_refptr<X509Certificate>> CertificateList;
// Class to perform certificate path building and verification for various
@@ -36,17 +39,14 @@ class NET_EXPORT CertVerifyProc
enum VerifyFlags {
// If set, enables online revocation checking via CRLs and OCSP for the
// certificate chain.
+ // Note: has no effect if VERIFY_DISABLE_NETWORK_FETCHES is set.
VERIFY_REV_CHECKING_ENABLED = 1 << 0,
// If set, this is equivalent to VERIFY_REV_CHECKING_ENABLED, in that it
// enables online revocation checking via CRLs or OCSP, but only
// for certificates issued by non-public trust anchors. Failure to check
// revocation is treated as a hard failure.
- // Note: If VERIFY_CERT_IO_ENABLE is not also supplied, certificates
- // that chain to local trust anchors will likely fail - for example, due to
- // lacking fresh cached revocation issue (Windows) or because OCSP stapling
- // can only provide information for the leaf, and not for any
- // intermediates.
+ // Note: has no effect if VERIFY_DISABLE_NETWORK_FETCHES is set.
VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS = 1 << 1,
// If set, certificates with SHA-1 signatures will be allowed, but only if
@@ -56,6 +56,12 @@ class NET_EXPORT CertVerifyProc
// If set, disables the policy enforcement described at
// https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html
VERIFY_DISABLE_SYMANTEC_ENFORCEMENT = 1 << 3,
+
+ // Disable network fetches during verification. This will override
+ // VERIFY_REV_CHECKING_ENABLED and
+ // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS if they are also specified.
+ // TODO(https://crbug.com/1432793): This should also disable AIA fetching.
+ VERIFY_DISABLE_NETWORK_FETCHES = 1 << 4,
};
// These values are persisted to logs. Entries should not be renumbered and
@@ -213,12 +219,35 @@ class NET_EXPORT CertVerifyProc
class NET_EXPORT CertVerifyProcFactory
: public base::RefCountedThreadSafe<CertVerifyProcFactory> {
public:
+ // The set of factory parameters that are variable over time, but are
+ // expected to be consistent between multiple verifiers that are created. For
+ // example, CertNetFetcher is not in this struct as it is expected that
+ // different verifiers will have different net fetchers. (There is no
+ // technical restriction against creating different verifiers with different
+ // ImplParams, structuring the parameters this way just makes some APIs more
+ // convenient for the common case.)
+ struct NET_EXPORT ImplParams {
+ ImplParams();
+ ~ImplParams();
+ ImplParams(const ImplParams&);
+ ImplParams& operator=(const ImplParams& other);
+ ImplParams(ImplParams&&);
+ ImplParams& operator=(ImplParams&& other);
+
+ scoped_refptr<CRLSet> crl_set;
+#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+ absl::optional<net::ChromeRootStoreData> root_store_data;
+#endif
+#if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+ bool use_chrome_root_store;
+#endif
+ };
+
// Create a new CertVerifyProc that uses the passed in CRLSet and
// ChromeRootStoreData.
virtual scoped_refptr<CertVerifyProc> CreateCertVerifyProc(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) = 0;
+ const ImplParams& impl_params) = 0;
protected:
virtual ~CertVerifyProcFactory() = default;
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc
index 907f295e7..dd9d25b89 100644
--- a/net/cert/cert_verify_proc_builtin.cc
+++ b/net/cert/cert_verify_proc_builtin.cc
@@ -314,6 +314,18 @@ class PathBuilderDelegateImpl : public SimplePathBuilderDelegate {
// Selects a revocation policy based on the CertVerifier flags and the given
// certificate chain.
RevocationPolicy ChooseRevocationPolicy(const ParsedCertificateList& certs) {
+ if (flags_ & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES) {
+ // In theory when network fetches are disabled but revocation is enabled
+ // we could continue with networking_allowed=false (and
+ // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS would also have to change
+ // allow_missing_info and allow_unable_to_check to true).
+ // That theoretically could allow still consulting any cached CRLs/etc.
+ // However in the way things are currently implemented in the builtin
+ // verifier there really is no point to bothering, just disable
+ // revocation checking if network fetches are disabled.
+ return NoRevocationChecking();
+ }
+
// Use hard-fail revocation checking for local trust anchors, if requested
// by the load flag and the chain uses a non-public root.
if ((flags_ & CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 784a7d0f8..d93de8aa7 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -3299,6 +3299,36 @@ TEST_P(CertVerifyProcInternalWithNetFetchingTest, RevocationHardFailNoCrls) {
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
}
+TEST_P(CertVerifyProcInternalWithNetFetchingTest,
+ RevocationHardFailNoCrlsDisableNetworkFetches) {
+ if (!SupportsRevCheckingRequiredLocalAnchors()) {
+ LOG(INFO) << "Skipping test as verifier doesn't support "
+ "VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS";
+ return;
+ }
+
+ // Create certs which have no AIA or CRL distribution points.
+ const char kHostname[] = "www.example.com";
+ auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3();
+
+ // Trust the root and build a chain to verify that includes the intermediate.
+ ScopedTestRoot scoped_root(root->GetX509Certificate().get());
+ scoped_refptr<X509Certificate> chain = leaf->GetX509CertificateChain();
+ ASSERT_TRUE(chain.get());
+
+ // Verify with flags for both hard-fail revocation checking for local anchors
+ // and disabling network fetches.
+ const int flags = CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS |
+ CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES;
+ CertVerifyResult verify_result;
+ int error =
+ Verify(chain.get(), kHostname, flags, CertificateList(), &verify_result);
+
+ // Should succeed, VERIFY_DISABLE_NETWORK_FETCHES takes priority.
+ EXPECT_THAT(error, IsOk());
+ EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
// CRL hard fail test where both leaf and intermediate are covered by valid
// CRLs which have empty (non-present) revokedCertificates list. Verification
// should succeed.
@@ -3656,6 +3686,42 @@ TEST_P(CertVerifyProcInternalWithNetFetchingTest,
}
TEST_P(CertVerifyProcInternalWithNetFetchingTest,
+ RevocationSoftFailLeafRevokedByCrlDisableNetworkFetches) {
+ if (!SupportsSoftFailRevChecking()) {
+ LOG(INFO) << "Skipping test as verifier doesn't support "
+ "VERIFY_REV_CHECKING_ENABLED";
+ return;
+ }
+
+ const char kHostname[] = "www.example.com";
+ auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3();
+
+ // Root-issued CRL which does not revoke intermediate.
+ intermediate->SetCrlDistributionPointUrl(CreateAndServeCrl(root.get(), {}));
+
+ // Leaf is revoked by intermediate issued CRL.
+ leaf->SetCrlDistributionPointUrl(
+ CreateAndServeCrl(intermediate.get(), {leaf->GetSerialNumber()}));
+
+ // Trust the root and build a chain to verify that includes the intermediate.
+ ScopedTestRoot scoped_root(root->GetX509Certificate().get());
+ scoped_refptr<X509Certificate> chain = leaf->GetX509CertificateChain();
+ ASSERT_TRUE(chain.get());
+
+ // Verify with flags for both soft-fail revocation checking and disabling
+ // network fetches.
+ const int flags = CertVerifyProc::VERIFY_REV_CHECKING_ENABLED |
+ CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES;
+ CertVerifyResult verify_result;
+ int error =
+ Verify(chain.get(), kHostname, flags, CertificateList(), &verify_result);
+
+ // Should succeed, VERIFY_DISABLE_NETWORK_FETCHES takes priority.
+ EXPECT_THAT(error, IsOk());
+ EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
+TEST_P(CertVerifyProcInternalWithNetFetchingTest,
RevocationSoftFailIntermediateRevokedByCrl) {
if (!SupportsSoftFailRevChecking()) {
LOG(INFO) << "Skipping test as verifier doesn't support "
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc
index 13cd5f040..0ac8dfc5f 100644
--- a/net/cert/multi_threaded_cert_verifier.cc
+++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -149,8 +149,7 @@ void MultiThreadedCertVerifier::InternalRequest::Start(
int flags = GetFlagsForConfig(config);
if (params.flags() & CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES) {
- flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_ENABLED;
- flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
+ flags |= CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES;
}
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
@@ -236,11 +235,10 @@ int MultiThreadedCertVerifier::Verify(const RequestParams& params,
void MultiThreadedCertVerifier::UpdateVerifyProcData(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) {
+ const net::CertVerifyProcFactory::ImplParams& impl_params) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
verify_proc_ = verify_proc_factory_->CreateCertVerifyProc(
- std::move(cert_net_fetcher), std::move(crl_set), root_store_data);
+ std::move(cert_net_fetcher), impl_params);
NotifyCertVerifierChanged();
}
diff --git a/net/cert/multi_threaded_cert_verifier.h b/net/cert/multi_threaded_cert_verifier.h
index d5a01a1cd..368368cfc 100644
--- a/net/cert/multi_threaded_cert_verifier.h
+++ b/net/cert/multi_threaded_cert_verifier.h
@@ -28,7 +28,6 @@ namespace net {
class CertVerifyProc;
class CertNetFetcher;
class CertVerifyProcFactory;
-class ChromeRootStoreData;
// MultiThreadedCertVerifier is a CertVerifier implementation that runs
// synchronous CertVerifier implementations on worker threads.
@@ -58,8 +57,7 @@ class NET_EXPORT_PRIVATE MultiThreadedCertVerifier
void RemoveObserver(Observer* observer) override;
void UpdateVerifyProcData(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) override;
+ const net::CertVerifyProcFactory::ImplParams& impl_params) override;
private:
class InternalRequest;
diff --git a/net/cert/multi_threaded_cert_verifier_unittest.cc b/net/cert/multi_threaded_cert_verifier_unittest.cc
index ce6577fb4..05fcc9fd9 100644
--- a/net/cert/multi_threaded_cert_verifier_unittest.cc
+++ b/net/cert/multi_threaded_cert_verifier_unittest.cc
@@ -83,8 +83,7 @@ class SwapWithNewProcFactory : public CertVerifyProcFactory {
scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) override {
+ const ImplParams& impl_params) override {
return mock_verify_proc_;
}
@@ -299,6 +298,37 @@ TEST_F(MultiThreadedCertVerifierTest, ConvertsConfigToFlags) {
}
}
+// Tests propagation of CertVerifier flags into CertVerifyProc flags
+TEST_F(MultiThreadedCertVerifierTest, ConvertsFlagsToFlags) {
+ scoped_refptr<X509Certificate> test_cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
+ ASSERT_TRUE(test_cert);
+
+ EXPECT_CALL(
+ *mock_verify_proc_,
+ VerifyInternal(_, _, _, _, CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES,
+ _, _, _))
+ .WillRepeatedly(
+ DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED)));
+
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+ int error = verifier_->Verify(
+ CertVerifier::RequestParams(test_cert, "www.example.com",
+ CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES,
+ /*ocsp_response=*/std::string(),
+ /*sct_list=*/std::string()),
+ &verify_result, callback.callback(), &request, NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_TRUE(IsCertificateError(error));
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
+
+ testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get());
+}
+
// Tests swapping in new Chrome Root Store Data.
TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeChromeRootStore) {
CertVerifierObserverCounter observer_counter(verifier_.get());
@@ -313,7 +343,7 @@ TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeChromeRootStore) {
EXPECT_CALL(*mock_new_verify_proc_, VerifyInternal(_, _, _, _, _, _, _, _))
.WillRepeatedly(
DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED)));
- verifier_->UpdateVerifyProcData(nullptr, nullptr, nullptr);
+ verifier_->UpdateVerifyProcData(nullptr, {});
EXPECT_EQ(observer_counter.change_count(), 1u);
@@ -353,7 +383,7 @@ TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeRequest) {
&verify_result, callback.callback(), &request, NetLogWithSource());
ASSERT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request);
- verifier_->UpdateVerifyProcData(nullptr, nullptr, nullptr);
+ verifier_->UpdateVerifyProcData(nullptr, {});
error = callback.WaitForResult();
EXPECT_TRUE(IsCertificateError(error));
EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID));
diff --git a/net/cert/pki/string_util.h b/net/cert/pki/string_util.h
index 1687b0886..b18f716f4 100644
--- a/net/cert/pki/string_util.h
+++ b/net/cert/pki/string_util.h
@@ -7,6 +7,8 @@
#include "net/base/net_export.h"
+#include <stdint.h>
+
#include <string_view>
#include <vector>
diff --git a/net/cert/trial_comparison_cert_verifier.cc b/net/cert/trial_comparison_cert_verifier.cc
index 2e7070c34..94d80b2b1 100644
--- a/net/cert/trial_comparison_cert_verifier.cc
+++ b/net/cert/trial_comparison_cert_verifier.cc
@@ -468,21 +468,29 @@ void TrialComparisonCertVerifier::Job::Request::OnJobAborted() {
}
TrialComparisonCertVerifier::TrialComparisonCertVerifier(
- scoped_refptr<CertVerifyProc> primary_verify_proc,
- scoped_refptr<CertVerifyProcFactory> primary_verify_proc_factory,
- scoped_refptr<CertVerifyProc> trial_verify_proc,
- scoped_refptr<CertVerifyProcFactory> trial_verify_proc_factory,
+ scoped_refptr<CertVerifyProcFactory> verify_proc_factory,
+ scoped_refptr<CertNetFetcher> cert_net_fetcher,
+ const CertVerifyProcFactory::ImplParams& impl_params,
ReportCallback report_callback)
- : report_callback_(std::move(report_callback)),
- primary_verifier_(std::make_unique<MultiThreadedCertVerifier>(
- primary_verify_proc,
- primary_verify_proc_factory)),
- primary_reverifier_(std::make_unique<MultiThreadedCertVerifier>(
- primary_verify_proc,
- primary_verify_proc_factory)),
- trial_verifier_(std::make_unique<MultiThreadedCertVerifier>(
- trial_verify_proc,
- trial_verify_proc_factory)) {
+ : report_callback_(std::move(report_callback)) {
+ auto [primary_impl_params, trial_impl_params] =
+ ProcessImplParams(impl_params);
+
+ primary_verifier_ = std::make_unique<MultiThreadedCertVerifier>(
+ verify_proc_factory->CreateCertVerifyProc(cert_net_fetcher,
+ primary_impl_params),
+ verify_proc_factory);
+
+ primary_reverifier_ = std::make_unique<MultiThreadedCertVerifier>(
+ verify_proc_factory->CreateCertVerifyProc(cert_net_fetcher,
+ primary_impl_params),
+ verify_proc_factory);
+
+ trial_verifier_ = std::make_unique<MultiThreadedCertVerifier>(
+ verify_proc_factory->CreateCertVerifyProc(cert_net_fetcher,
+ trial_impl_params),
+ verify_proc_factory);
+
primary_verifier_->AddObserver(this);
primary_reverifier_->AddObserver(this);
trial_verifier_->AddObserver(this);
@@ -501,9 +509,18 @@ int TrialComparisonCertVerifier::Verify(const RequestParams& params,
const NetLogWithSource& net_log) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!trial_allowed()) {
- return primary_verifier_->Verify(params, verify_result, std::move(callback),
+ // Technically, the trial could still be active when
+ // actual_use_chrome_root_store_=true, just by reversing everything. (Doing
+ // the trial verifier first and returning that result, then doing the primary
+ // verifier and comparing.) Probably not worth the trouble though.
+ if (!trial_allowed() || actual_use_chrome_root_store_) {
+ if (actual_use_chrome_root_store_) {
+ return trial_verifier_->Verify(params, verify_result, std::move(callback),
out_req, net_log);
+ } else {
+ return primary_verifier_->Verify(params, verify_result,
+ std::move(callback), out_req, net_log);
+ }
}
std::unique_ptr<Job> job =
@@ -527,32 +544,53 @@ void TrialComparisonCertVerifier::SetConfig(const Config& config) {
void TrialComparisonCertVerifier::AddObserver(
CertVerifier::Observer* observer) {
- // Let primary_verifier_ handle the observer lists rather than creating
- // another one in TrialComparisonCertVerifier. From the perspective of the
- // caller, the primary_verifier is the only one that it would care about
- // changes to.
+ // Delegate the notifications to the wrapped verifiers. We add the observer
+ // to both `primary_verifier_` and `trial_verifier_` since either one might
+ // be the one that matters depending on the configuration at the time. This
+ // does mean the caller will get double notified, but shouldn't really matter
+ // that much. It would be possible to avoid this by making a notification
+ // proxy that only forwards notifications from the verifier that is currently
+ // the "main" one, but it's probably not worth the trouble.
+ //
+ // Also this assumes that there is never a case where the
+ // TrialComparisonCertVerifier itself would change something without the
+ // wrapped verifiers also generating a notification.
primary_verifier_->AddObserver(observer);
+ trial_verifier_->AddObserver(observer);
}
void TrialComparisonCertVerifier::RemoveObserver(
CertVerifier::Observer* observer) {
+ trial_verifier_->RemoveObserver(observer);
primary_verifier_->RemoveObserver(observer);
}
void TrialComparisonCertVerifier::UpdateVerifyProcData(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) {
- primary_verifier_->UpdateVerifyProcData(cert_net_fetcher, crl_set,
- root_store_data);
- primary_reverifier_->UpdateVerifyProcData(cert_net_fetcher, crl_set,
- root_store_data);
- trial_verifier_->UpdateVerifyProcData(cert_net_fetcher, crl_set,
- root_store_data);
+ const CertVerifyProcFactory::ImplParams& impl_params) {
+ bool previous_actual_use_chrome_root_store = actual_use_chrome_root_store_;
+ auto [primary_impl_params, trial_impl_params] =
+ ProcessImplParams(impl_params);
+
+ // If the only change in the params was to switch the
+ // `actual_use_chrome_root_store_` value, updating the underlying verifiers
+ // is unnecessary, but it's probably not worth the trouble to try to avoid
+ // it.
+ primary_verifier_->UpdateVerifyProcData(cert_net_fetcher,
+ primary_impl_params);
+ primary_reverifier_->UpdateVerifyProcData(cert_net_fetcher,
+ primary_impl_params);
+
+ trial_verifier_->UpdateVerifyProcData(cert_net_fetcher, trial_impl_params);
+
// The TrialComparisonCertVerifier is registered as an observer of the
// underlying verifiers, and so the OnCertVerifierChanged method should be
// triggered to call NotifyJobsOfConfigChange, so it isn't explicitly called
- // here.
+ // here for cases other than the `actual_use_chrome_root_store_` changing.
+
+ if (previous_actual_use_chrome_root_store != actual_use_chrome_root_store_) {
+ NotifyJobsOfConfigChange();
+ }
}
void TrialComparisonCertVerifier::RemoveJob(Job* job_ptr) {
@@ -563,6 +601,18 @@ void TrialComparisonCertVerifier::RemoveJob(Job* job_ptr) {
jobs_.erase(it);
}
+std::tuple<CertVerifyProcFactory::ImplParams, CertVerifyProcFactory::ImplParams>
+TrialComparisonCertVerifier::ProcessImplParams(
+ const CertVerifyProcFactory::ImplParams& impl_params) {
+ actual_use_chrome_root_store_ = impl_params.use_chrome_root_store;
+
+ CertVerifyProcFactory::ImplParams primary_impl_params(impl_params);
+ primary_impl_params.use_chrome_root_store = false;
+ CertVerifyProcFactory::ImplParams trial_impl_params(impl_params);
+ trial_impl_params.use_chrome_root_store = true;
+ return {std::move(primary_impl_params), std::move(trial_impl_params)};
+}
+
void TrialComparisonCertVerifier::NotifyJobsOfConfigChange() {
for (auto& job : jobs_) {
job->OnConfigChanged();
diff --git a/net/cert/trial_comparison_cert_verifier.h b/net/cert/trial_comparison_cert_verifier.h
index b0306c255..1712a81b0 100644
--- a/net/cert/trial_comparison_cert_verifier.h
+++ b/net/cert/trial_comparison_cert_verifier.h
@@ -19,11 +19,8 @@
#include "net/cert/cert_verifier.h"
namespace net {
-class CertVerifyProc;
class CertVerifyProcFactory;
class CertNetFetcher;
-class ChromeRootStoreData;
-class CRLSet;
// TrialComparisonCertVerifier is a CertVerifier that can be used to compare
// the results between two different CertVerifyProcs. The results are reported
@@ -45,33 +42,35 @@ class NET_EXPORT TrialComparisonCertVerifier
const net::CertVerifyResult& primary_result,
const net::CertVerifyResult& trial_result)>;
- // Create a new TrialComparisonCertVerifier. Initially, no trial
- // verifications will actually be performed; that is, calls to Verify() will
- // be dispatched to the underlying |primary_verify_proc|. This can be changed
- // by calling set_trial_allowed().
+ // Create a new TrialComparisonCertVerifier. The `verify_proc_factory` will
+ // be used to create the underlying primary and trial verifiers.
+ //
+ // Initially, no trial verifications will actually be performed; that is,
+ // calls to Verify() will be dispatched to the underlying `primary_verifier_`
+ // or `trial_verifier_` depending on the `impl_params`. This can be changed
+ // by calling `set_trial_allowed()`.
//
// When trial verifications are enabled, calls to Verify() will first call
- // into |primary_verify_proc| to verify. The result of this verification will
+ // into `primary_verifier_` to verify. The result of this verification will
// be immediately returned to the caller of Verify, allowing them to proceed.
// However, the verifier will continue in the background, attempting to
- // verify the same RequestParams using |trial_verify_proc|. If there are
- // differences in the results, they will be reported via |report_callback|,
+ // verify the same RequestParams using `trial_verifier_`. If there are
+ // differences in the results, they will be reported via `report_callback`,
// allowing the creator to receive information about differences.
//
// If the caller abandons the CertVerifier::Request prior to the primary
// verification completed, no trial verification will be done. However, once
// the primary verifier has returned, the trial verifications will continue,
// provided that the underlying configuration has not been changed by
- // calling SetConfig().
+ // calling `SetConfig()` or `UpdateVerifyProcData()`.
//
- // Note that there may be multiple calls to both |primary_verify_proc| and
- // |trial_verify_proc|, using different parameters to account for platform
- // differences.
+ // Note that there may be multiple calls to both the primary CertVerifyProc
+ // and trial CertVerifyProc, using different parameters to account for
+ // platform differences.
TrialComparisonCertVerifier(
- scoped_refptr<CertVerifyProc> primary_verify_proc,
- scoped_refptr<CertVerifyProcFactory> primary_verify_proc_factory,
- scoped_refptr<CertVerifyProc> trial_verify_proc,
- scoped_refptr<CertVerifyProcFactory> trial_verify_proc_factory,
+ scoped_refptr<CertVerifyProcFactory> verify_proc_factory,
+ scoped_refptr<CertNetFetcher> cert_net_fetcher,
+ const CertVerifyProcFactory::ImplParams& impl_params,
ReportCallback report_callback);
TrialComparisonCertVerifier(const TrialComparisonCertVerifier&) = delete;
@@ -94,8 +93,7 @@ class NET_EXPORT TrialComparisonCertVerifier
void RemoveObserver(Observer* observer) override;
void UpdateVerifyProcData(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) override;
+ const CertVerifyProcFactory::ImplParams& impl_params) override;
private:
class Job;
@@ -108,6 +106,13 @@ class NET_EXPORT TrialComparisonCertVerifier
void RemoveJob(Job* job_ptr);
void NotifyJobsOfConfigChange();
+ // Processes the params from the caller, updates the state of the trial and
+ // returns the pair of {primary verifier params, trial verifier params} to
+ // be used in creating or updating the wrapped verifiers.
+ std::tuple<CertVerifyProcFactory::ImplParams,
+ CertVerifyProcFactory::ImplParams>
+ ProcessImplParams(const CertVerifyProcFactory::ImplParams& impl_params);
+
// CertVerifier::Observer methods:
void OnCertVerifierChanged() override;
@@ -116,6 +121,11 @@ class NET_EXPORT TrialComparisonCertVerifier
// Callback that reports are sent to.
ReportCallback report_callback_;
+ // The actual `use_chrome_root_store` value that is requested by the caller.
+ // This determines which verifier's result is returned to the caller as the
+ // actual verification result.
+ bool actual_use_chrome_root_store_;
+
CertVerifier::Config config_;
std::unique_ptr<CertVerifierWithUpdatableProc> primary_verifier_;
diff --git a/net/cert/trial_comparison_cert_verifier_unittest.cc b/net/cert/trial_comparison_cert_verifier_unittest.cc
index ece77e860..859ee6eb8 100644
--- a/net/cert/trial_comparison_cert_verifier_unittest.cc
+++ b/net/cert/trial_comparison_cert_verifier_unittest.cc
@@ -205,6 +205,10 @@ int NotCalledCertVerifyProc::VerifyInternal(
return ERR_UNEXPECTED;
}
+scoped_refptr<CertVerifyProc> MakeNotCalledProc() {
+ return base::MakeRefCounted<NotCalledCertVerifyProc>();
+}
+
void NotCalledCallback(int error) {
ADD_FAILURE() << "NotCalledCallback was called with error code " << error;
}
@@ -232,27 +236,42 @@ class MockCertVerifyProc : public CertVerifyProc {
~MockCertVerifyProc() override = default;
};
-class SwapWithNewProcFactory : public CertVerifyProcFactory {
+class TestProcFactory : public CertVerifyProcFactory {
public:
- explicit SwapWithNewProcFactory(scoped_refptr<CertVerifyProc> new_proc)
- : verify_proc_(std::move(new_proc)) {}
+ explicit TestProcFactory(
+ std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs,
+ std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs)
+ : primary_verify_procs_(std::move(primary_verify_procs)),
+ trial_verify_procs_(std::move(trial_verify_procs)) {}
scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
- scoped_refptr<CRLSet> crl_set,
- const ChromeRootStoreData* root_store_data) override {
- return verify_proc_;
+ const ImplParams& impl_params) override {
+ std::deque<scoped_refptr<CertVerifyProc>>* procs =
+ impl_params.use_chrome_root_store ? &trial_verify_procs_
+ : &primary_verify_procs_;
+ if (procs->empty()) {
+ ADD_FAILURE() << "procs is empty for crs="
+ << impl_params.use_chrome_root_store;
+ return MakeNotCalledProc();
+ }
+ scoped_refptr<CertVerifyProc> r = procs->front();
+ procs->pop_front();
+ return r;
}
protected:
- ~SwapWithNewProcFactory() override = default;
+ ~TestProcFactory() override = default;
- scoped_refptr<CertVerifyProc> verify_proc_;
+ std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs_;
+ std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs_;
};
-scoped_refptr<CertVerifyProcFactory> SwapWithNotCalledProcFactory() {
- return base::MakeRefCounted<SwapWithNewProcFactory>(
- base::MakeRefCounted<NotCalledCertVerifyProc>());
+scoped_refptr<CertVerifyProcFactory> ProcFactory(
+ std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs,
+ std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs) {
+ return base::MakeRefCounted<TestProcFactory>(std::move(primary_verify_procs),
+ std::move(trial_verify_procs));
}
struct TrialReportInfo {
@@ -332,6 +351,9 @@ class TrialComparisonCertVerifierTest : public TestWithTaskEnvironment {
GetTestCertsDirectory(), "lets-encrypt-isrg-x1-root.pem",
X509Certificate::FORMAT_AUTO);
ASSERT_TRUE(lets_encrypt_isrg_x1_);
+
+ no_crs_impl_params_.use_chrome_root_store = false;
+ yes_crs_impl_params_.use_chrome_root_store = true;
}
protected:
@@ -340,22 +362,26 @@ class TrialComparisonCertVerifierTest : public TestWithTaskEnvironment {
scoped_refptr<X509Certificate> leaf_cert_1_;
scoped_refptr<X509Certificate> lets_encrypt_dst_x3_;
scoped_refptr<X509Certificate> lets_encrypt_isrg_x1_;
+ net::CertVerifyProcFactory::ImplParams no_crs_impl_params_;
+ net::CertVerifyProcFactory::ImplParams yes_crs_impl_params_;
base::HistogramTester histograms_;
};
-TEST_F(TrialComparisonCertVerifierTest, ObserverIsCalledOnCRSUpdate) {
+TEST_F(TrialComparisonCertVerifierTest, ObserverIsCalledOnVerifierUpdate) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({MakeNotCalledProc(), MakeNotCalledProc(),
+ MakeNotCalledProc(), MakeNotCalledProc()},
+ {MakeNotCalledProc(), MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
CertVerifierObserverCounter observer_(&verifier);
EXPECT_EQ(observer_.change_count(), 0u);
- verifier.UpdateVerifyProcData(nullptr, nullptr, nullptr);
- EXPECT_EQ(observer_.change_count(), 1u);
+ verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_);
+ // Observer is called twice since the TrialComparisonCertVerifier currently
+ // forwards notifications from both the primary and secondary verifiers.
+ EXPECT_EQ(observer_.change_count(), 2u);
}
TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowed) {
@@ -365,10 +391,10 @@ TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowed) {
auto verify_proc = base::MakeRefCounted<FakeCertVerifyProc>(OK, dummy_result);
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc, SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc, MakeNotCalledProc()}, {MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
+
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
/*ocsp_response=*/std::string(),
/*sct_list=*/std::string());
@@ -428,9 +454,8 @@ TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowedThenAllowed) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0,
/*ocsp_response=*/std::string(),
@@ -512,9 +537,8 @@ TEST_F(TrialComparisonCertVerifierTest, InitiallyAllowedThenDisallowed) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0,
@@ -565,6 +589,186 @@ TEST_F(TrialComparisonCertVerifierTest, InitiallyAllowedThenDisallowed) {
EXPECT_EQ("t0.test", report.hostname);
}
+TEST_F(TrialComparisonCertVerifierTest, InitiallyCRSEnabledThenDisabled) {
+ // Certificate that has multiple subjectAltName entries. This allows easily
+ // confirming which verification attempt the report was generated for without
+ // having to mock different CertVerifyProc results for each.
+ base::FilePath certs_dir =
+ GetTestNetDataDirectory()
+ .AppendASCII("verify_certificate_chain_unittest")
+ .AppendASCII("many-names");
+ scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile(
+ certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO);
+ ASSERT_TRUE(cert_chain);
+ ASSERT_EQ(2U, cert_chain->intermediate_buffers().size());
+
+ scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer(
+ bssl::UpRef(cert_chain->cert_buffer()), {});
+ ASSERT_TRUE(leaf);
+
+ CertVerifyResult primary_result;
+ primary_result.verified_cert = cert_chain;
+ scoped_refptr<FakeCertVerifyProc> verify_proc1 =
+ base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result);
+
+ // Trial verifier returns an error status.
+ CertVerifyResult secondary_result;
+ secondary_result.cert_status = CERT_STATUS_DATE_INVALID;
+ secondary_result.verified_cert = cert_chain;
+ scoped_refptr<FakeCertVerifyProc> verify_proc2 =
+ base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID,
+ secondary_result);
+
+ std::vector<TrialReportInfo> reports;
+ // Verifier created with ImplParams that have use_chrome_root_store=true.
+ TrialComparisonCertVerifier verifier(
+ ProcFactory({verify_proc1, MakeNotCalledProc(), verify_proc1,
+ MakeNotCalledProc()},
+ {verify_proc2, verify_proc2}),
+ nullptr, yes_crs_impl_params_,
+ base::BindRepeating(&RecordTrialReport, &reports));
+ verifier.set_trial_allowed(true);
+
+ CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0,
+ /*ocsp_response=*/std::string(),
+ /*sct_list=*/std::string());
+ CertVerifyResult result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+ int error = verifier.Verify(params, &result, callback.callback(), &request,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ // The actual result returned should be from the secondary verifier.
+ EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID));
+
+ // Turn chrome root store off and verify again.
+ verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_);
+ CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0,
+ /*ocsp_response=*/std::string(),
+ /*sct_list=*/std::string());
+ CertVerifyResult result2;
+ TestCompletionCallback callback2;
+ std::unique_ptr<CertVerifier::Request> request2;
+ error = verifier.Verify(params2, &result2, callback2.callback(), &request2,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
+ EXPECT_TRUE(request2);
+
+ // The actual result returned should now be from the primary verifier.
+ error = callback2.WaitForResult();
+ EXPECT_THAT(error, IsOk());
+
+ verify_proc2->WaitForVerifyCall();
+ RunUntilIdle();
+
+ // Primary verifier should have run once, secondary verifier should run twice.
+ EXPECT_EQ(1, verify_proc1->num_verifications());
+ EXPECT_EQ(2, verify_proc2->num_verifications());
+ // Trial comparison was only run once.
+ histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
+ histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
+ 1);
+ histograms_.ExpectUniqueSample(
+ "Net.CertVerifier_TrialComparisonResult",
+ TrialComparisonResult::kPrimaryValidSecondaryError, 1);
+
+ // Expect a report from the second verification.
+ ASSERT_EQ(1U, reports.size());
+ const TrialReportInfo& report = reports[0];
+ EXPECT_EQ("t1.test", report.hostname);
+}
+
+TEST_F(TrialComparisonCertVerifierTest, InitiallyAllowedThenCRSEnabled) {
+ // Certificate that has multiple subjectAltName entries. This allows easily
+ // confirming which verification attempt the report was generated for without
+ // having to mock different CertVerifyProc results for each.
+ base::FilePath certs_dir =
+ GetTestNetDataDirectory()
+ .AppendASCII("verify_certificate_chain_unittest")
+ .AppendASCII("many-names");
+ scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile(
+ certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO);
+ ASSERT_TRUE(cert_chain);
+ ASSERT_EQ(2U, cert_chain->intermediate_buffers().size());
+
+ scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer(
+ bssl::UpRef(cert_chain->cert_buffer()), {});
+ ASSERT_TRUE(leaf);
+
+ CertVerifyResult primary_result;
+ primary_result.verified_cert = cert_chain;
+ scoped_refptr<FakeCertVerifyProc> verify_proc1 =
+ base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result);
+
+ // Trial verifier returns an error status.
+ CertVerifyResult secondary_result;
+ secondary_result.cert_status = CERT_STATUS_DATE_INVALID;
+ secondary_result.verified_cert = cert_chain;
+ scoped_refptr<FakeCertVerifyProc> verify_proc2 =
+ base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID,
+ secondary_result);
+
+ std::vector<TrialReportInfo> reports;
+ TrialComparisonCertVerifier verifier(
+ ProcFactory({verify_proc1, MakeNotCalledProc(), verify_proc1,
+ MakeNotCalledProc()},
+ {verify_proc2, verify_proc2}),
+ nullptr, no_crs_impl_params_,
+ base::BindRepeating(&RecordTrialReport, &reports));
+ verifier.set_trial_allowed(true);
+
+ CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0,
+ /*ocsp_response=*/std::string(),
+ /*sct_list=*/std::string());
+ CertVerifyResult result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+ int error = verifier.Verify(params, &result, callback.callback(), &request,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_THAT(error, IsOk());
+
+ // Turn chrome root store on and verify again.
+ verifier.UpdateVerifyProcData(nullptr, yes_crs_impl_params_);
+ CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0,
+ /*ocsp_response=*/std::string(),
+ /*sct_list=*/std::string());
+ CertVerifyResult result2;
+ TestCompletionCallback callback2;
+ std::unique_ptr<CertVerifier::Request> request2;
+ error = verifier.Verify(params2, &result2, callback2.callback(), &request2,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
+ EXPECT_TRUE(request2);
+
+ // The actual result returned should now be from the secondary verifier.
+ error = callback2.WaitForResult();
+ EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID));
+
+ verify_proc2->WaitForVerifyCall();
+ RunUntilIdle();
+
+ // Primary verifier should have run once, secondary verifier should run twice.
+ EXPECT_EQ(1, verify_proc1->num_verifications());
+ EXPECT_EQ(2, verify_proc2->num_verifications());
+ // Trial comparison was only run once.
+ histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
+ histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
+ 1);
+ histograms_.ExpectUniqueSample(
+ "Net.CertVerifier_TrialComparisonResult",
+ TrialComparisonResult::kPrimaryValidSecondaryError, 1);
+
+ // Expect a report from the first verification.
+ ASSERT_EQ(1U, reports.size());
+ const TrialReportInfo& report = reports[0];
+ EXPECT_EQ("t0.test", report.hostname);
+}
+
TEST_F(TrialComparisonCertVerifierTest,
ConfigChangedDuringPrimaryVerification) {
CertVerifyResult primary_result;
@@ -574,9 +778,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
@@ -630,17 +833,18 @@ TEST_F(TrialComparisonCertVerifierTest, ConfigChangedBeforeVerification) {
// Both verifiers are initially NotCalledCertVerifyProc, but should swap to
// verify_proc1 and verify_proc2 when UpdateVerifyProcData is called.
TrialComparisonCertVerifier verifier(
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- base::MakeRefCounted<SwapWithNewProcFactory>(verify_proc1),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- base::MakeRefCounted<SwapWithNewProcFactory>(verify_proc2),
+ ProcFactory({MakeNotCalledProc(), MakeNotCalledProc(), verify_proc1,
+ MakeNotCalledProc()},
+ {MakeNotCalledProc(), verify_proc2}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
+
verifier.set_trial_allowed(true);
// Change the verifier Chrome Root Store data before verification, so the
// Verify should call the verifiers that were swapped in by the factories
// instead of the initial ones.
- verifier.UpdateVerifyProcData(nullptr, nullptr, nullptr);
+ verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
/*ocsp_response=*/std::string(),
@@ -696,9 +900,10 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc(), MakeNotCalledProc(),
+ MakeNotCalledProc()},
+ {MakeNotCalledProc(), MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
@@ -715,7 +920,7 @@ TEST_F(TrialComparisonCertVerifierTest,
// Change the verifier Chrome Root Store data before the primary verification
// finishes.
- verifier.UpdateVerifyProcData(nullptr, nullptr, nullptr);
+ verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_);
error = callback.WaitForResult();
EXPECT_THAT(error, IsOk());
@@ -749,9 +954,8 @@ TEST_F(TrialComparisonCertVerifierTest, ConfigChangedDuringTrialVerification) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -811,8 +1015,10 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc(), MakeNotCalledProc(),
+ MakeNotCalledProc()},
+ {verify_proc2, MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
@@ -831,7 +1037,7 @@ TEST_F(TrialComparisonCertVerifierTest,
EXPECT_THAT(error, IsOk());
// Change the verifier Chrome Root Store data during the trial verification.
- verifier.UpdateVerifyProcData(nullptr, nullptr, nullptr);
+ verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_);
RunUntilIdle();
@@ -864,9 +1070,8 @@ TEST_F(TrialComparisonCertVerifierTest, SameResult) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -914,9 +1119,8 @@ TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierErrorSecondaryOk) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -980,9 +1184,8 @@ TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierOkSecondaryError) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1045,9 +1248,8 @@ TEST_F(TrialComparisonCertVerifierTest, BothVerifiersDifferentErrors) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1106,9 +1308,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1170,9 +1371,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1238,9 +1438,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1335,9 +1534,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf, "test.example", /*flags=*/0,
@@ -1389,9 +1587,8 @@ TEST_F(TrialComparisonCertVerifierTest, BothVerifiersOkDifferentCertStatus) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::Config config;
@@ -1462,9 +1659,8 @@ TEST_F(TrialComparisonCertVerifierTest, CancelledDuringPrimaryVerification) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1522,9 +1718,8 @@ TEST_F(TrialComparisonCertVerifierTest, DeletedDuringPrimaryVerification) {
std::vector<TrialReportInfo> reports;
auto verifier = std::make_unique<TrialComparisonCertVerifier>(
- verify_proc1, SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
verifier->set_trial_allowed(true);
@@ -1571,9 +1766,8 @@ TEST_F(TrialComparisonCertVerifierTest, DeletedDuringVerificationResult) {
std::vector<TrialReportInfo> reports;
auto verifier = std::make_unique<TrialComparisonCertVerifier>(
- verify_proc1, SwapWithNotCalledProcFactory(),
- base::MakeRefCounted<NotCalledCertVerifyProc>(),
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}),
+ nullptr, no_crs_impl_params_,
base::BindRepeating(&RecordTrialReport, &reports));
verifier->set_trial_allowed(true);
@@ -1636,8 +1830,8 @@ TEST_F(TrialComparisonCertVerifierTest, DeletedDuringTrialReport) {
bool was_report_callback_called = false;
std::unique_ptr<TrialComparisonCertVerifier> verifier;
verifier = std::make_unique<TrialComparisonCertVerifier>(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_,
base::BindLambdaForTesting(
[&verifier, &was_report_callback_called](
const std::string& hostname,
@@ -1702,9 +1896,8 @@ TEST_F(TrialComparisonCertVerifierTest, DeletedAfterTrialVerificationStarted) {
std::vector<TrialReportInfo> reports;
auto verifier = std::make_unique<TrialComparisonCertVerifier>(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier->set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1769,9 +1962,8 @@ TEST_F(TrialComparisonCertVerifierTest, PrimaryRevokedSecondaryOk) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1842,9 +2034,8 @@ TEST_F(TrialComparisonCertVerifierTest, MultipleEVPolicies) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1908,9 +2099,8 @@ TEST_F(TrialComparisonCertVerifierTest, MultipleEVPoliciesNoneValidForRoot) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -1978,9 +2168,8 @@ TEST_F(TrialComparisonCertVerifierTest, MultiplePoliciesOnlyOneIsEV) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2031,9 +2220,8 @@ TEST_F(TrialComparisonCertVerifierTest, LocallyTrustedLeaf) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2085,9 +2273,8 @@ TEST_F(TrialComparisonCertVerifierTest, SHA1Ignored) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2140,9 +2327,8 @@ TEST_F(TrialComparisonCertVerifierTest, BothAuthorityInvalidIgnored) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2196,9 +2382,8 @@ TEST_F(TrialComparisonCertVerifierTest, BothKnownRootsIgnored) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2254,9 +2439,8 @@ TEST_F(TrialComparisonCertVerifierTest,
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2305,9 +2489,8 @@ TEST_F(TrialComparisonCertVerifierTest, LetsEncryptSpecialCase) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
@@ -2358,9 +2541,8 @@ TEST_F(TrialComparisonCertVerifierTest, AndroidPreferDate) {
std::vector<TrialReportInfo> reports;
TrialComparisonCertVerifier verifier(
- verify_proc1, SwapWithNotCalledProcFactory(), verify_proc2,
- SwapWithNotCalledProcFactory(),
- base::BindRepeating(&RecordTrialReport, &reports));
+ ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr,
+ no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports));
verifier.set_trial_allowed(true);
CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0,
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
index 51fb970be..129b13ab7 100644
--- a/net/cookies/cookie_inclusion_status.h
+++ b/net/cookies/cookie_inclusion_status.h
@@ -5,7 +5,10 @@
#ifndef NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
#define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
+#include <stdint.h>
+
#include <bitset>
+#include <cstdint>
#include <ostream>
#include <string>
#include <vector>
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
index e1eb9d0f7..36dd9f96c 100644
--- a/net/cookies/cookie_monster_change_dispatcher.cc
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
@@ -36,14 +36,15 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
std::string domain_key,
std::string name_key,
GURL url,
- absl::optional<CookiePartitionKey> cookie_partition_key,
+ CookiePartitionKeyCollection cookie_partition_key_collection,
bool same_party_attribute_enabled,
net::CookieChangeCallback callback)
: change_dispatcher_(std::move(change_dispatcher)),
domain_key_(std::move(domain_key)),
name_key_(std::move(name_key)),
url_(std::move(url)),
- cookie_partition_key_(std::move(cookie_partition_key)),
+ cookie_partition_key_collection_(
+ std::move(cookie_partition_key_collection)),
callback_(std::move(callback)),
same_party_attribute_enabled_(same_party_attribute_enabled),
task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
@@ -87,14 +88,22 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange(
}
}
- if (!change.cookie.IsPartitioned() &&
- net::CookiePartitionKey::HasNonce(cookie_partition_key_)) {
- return;
- }
-
- if (change.cookie.IsPartitioned() &&
- change.cookie.PartitionKey() != cookie_partition_key_) {
- return;
+ if (!cookie_partition_key_collection_.ContainsAllKeys()) {
+ if (cookie_partition_key_collection_.PartitionKeys().empty()) {
+ if (cookie.IsPartitioned()) {
+ return;
+ }
+ } else {
+ DCHECK_EQ(1u, cookie_partition_key_collection_.PartitionKeys().size());
+ const CookiePartitionKey& key =
+ *cookie_partition_key_collection_.PartitionKeys().begin();
+ if (CookiePartitionKey::HasNonce(key) && !cookie.IsPartitioned()) {
+ return;
+ }
+ if (cookie.IsPartitioned() && key != *cookie.PartitionKey()) {
+ return;
+ }
+ }
}
// TODO(mmenke, pwnall): Run callbacks synchronously?
@@ -155,7 +164,8 @@ CookieMonsterChangeDispatcher::AddCallbackForCookie(
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
weak_ptr_factory_.GetWeakPtr(), DomainKey(url), NameKey(name), url,
- cookie_partition_key, same_party_attribute_enabled_, std::move(callback));
+ CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
+ same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
return subscription;
@@ -170,7 +180,8 @@ CookieMonsterChangeDispatcher::AddCallbackForUrl(
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
weak_ptr_factory_.GetWeakPtr(), DomainKey(url),
- std::string(kGlobalNameKey), url, cookie_partition_key,
+ std::string(kGlobalNameKey), url,
+ CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
@@ -184,7 +195,8 @@ CookieMonsterChangeDispatcher::AddCallbackForAllChanges(
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
weak_ptr_factory_.GetWeakPtr(), std::string(kGlobalDomainKey),
- std::string(kGlobalNameKey), GURL(""), absl::nullopt,
+ std::string(kGlobalNameKey), GURL(""),
+ CookiePartitionKeyCollection::ContainsAll(),
same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
diff --git a/net/cookies/cookie_monster_change_dispatcher.h b/net/cookies/cookie_monster_change_dispatcher.h
index dd022adb2..31ca1e979 100644
--- a/net/cookies/cookie_monster_change_dispatcher.h
+++ b/net/cookies/cookie_monster_change_dispatcher.h
@@ -18,6 +18,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "net/cookies/cookie_change_dispatcher.h"
+#include "net/cookies/cookie_partition_key_collection.h"
#include "url/gurl.h"
namespace net {
@@ -77,7 +78,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
std::string domain_key,
std::string name_key,
GURL url,
- absl::optional<CookiePartitionKey> cookie_partition_key,
+ CookiePartitionKeyCollection cookie_partition_key_collection,
bool same_party_attribute_enabled,
net::CookieChangeCallback callback);
@@ -104,8 +105,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
const std::string domain_key_; // kGlobalDomainKey means no filtering.
const std::string name_key_; // kGlobalNameKey means no filtering.
const GURL url_; // empty() means no URL-based filtering.
- // nullopt means all Partitioned cookies will be ignored.
- const absl::optional<CookiePartitionKey> cookie_partition_key_;
+ const CookiePartitionKeyCollection cookie_partition_key_collection_;
const net::CookieChangeCallback callback_;
bool same_party_attribute_enabled_;
diff --git a/net/cookies/cookie_store_change_unittest.h b/net/cookies/cookie_store_change_unittest.h
index 08b0d0643..be89df1f3 100644
--- a/net/cookies/cookie_store_change_unittest.h
+++ b/net/cookies/cookie_store_change_unittest.h
@@ -707,6 +707,38 @@ TYPED_TEST_P(CookieStoreChangeGlobalTest, ChangeIncludesCookieAccessSemantics) {
cookie_changes[3].access_result.access_semantics));
}
+TYPED_TEST_P(CookieStoreChangeGlobalTest, PartitionedCookies) {
+ if (!TypeParam::supports_named_cookie_tracking ||
+ !TypeParam::supports_partitioned_cookies) {
+ return;
+ }
+
+ CookieStore* cs = this->GetCookieStore();
+
+ // Test that all partitioned cookies are visible to global change listeners.
+ std::vector<CookieChangeInfo> all_cookie_changes;
+ std::unique_ptr<CookieChangeSubscription> global_subscription =
+ cs->GetChangeDispatcher().AddCallbackForAllChanges(base::BindRepeating(
+ &CookieStoreChangeTestBase<TypeParam>::OnCookieChange,
+ base::Unretained(&all_cookie_changes)));
+ // Set two cookies in two separate partitions, one with nonce.
+ this->CreateAndSetCookie(
+ cs, GURL("https://www.example2.com"),
+ "__Host-a=1; Secure; Path=/; Partitioned",
+ CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
+ this->CreateAndSetCookie(
+ cs, GURL("https://www.example2.com"),
+ "__Host-a=2; Secure; Path=/; Partitioned; Max-Age=7200",
+ CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"),
+ base::UnguessableToken::Create()));
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(2u, all_cookie_changes.size());
+}
+
TYPED_TEST_P(CookieStoreChangeUrlTest, NoCookie) {
if (!TypeParam::supports_url_cookie_tracking)
return;
@@ -1748,16 +1780,14 @@ TYPED_TEST_P(CookieStoreChangeUrlTest, PartitionedCookies) {
"__Host-b=2; Secure; Path=/; Partitioned",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://sub.foo.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://sub.foo.com")));
// Partitioned cookie with a different partition key
this->CreateAndSetCookie(
cs, GURL("https://www.example.com"),
"__Host-c=3; Secure; Path=/; Partitioned",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com")));
this->DeliverChangeNotifications();
ASSERT_EQ(2u, cookie_changes.size());
@@ -1785,14 +1815,61 @@ TYPED_TEST_P(CookieStoreChangeUrlTest, PartitionedCookies) {
"__Host-b=2; Secure; Path=/; Partitioned; Max-Age=7200",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
this->DeliverChangeNotifications();
ASSERT_EQ(0u, other_cookie_changes.size());
// Check that the other listener was invoked.
ASSERT_LT(2u, cookie_changes.size());
}
+TYPED_TEST_P(CookieStoreChangeUrlTest, PartitionedCookies_WithNonce) {
+ if (!TypeParam::supports_named_cookie_tracking ||
+ !TypeParam::supports_partitioned_cookies) {
+ return;
+ }
+
+ CookieStore* cs = this->GetCookieStore();
+ base::UnguessableToken nonce = base::UnguessableToken::Create();
+
+ std::vector<CookieChangeInfo> cookie_changes;
+ std::unique_ptr<CookieChangeSubscription> subscription =
+ cs->GetChangeDispatcher().AddCallbackForUrl(
+ GURL("https://www.example.com"),
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"),
+ nonce),
+ base::BindRepeating(
+ &CookieStoreChangeTestBase<TypeParam>::OnCookieChange,
+ base::Unretained(&cookie_changes)));
+
+ // Should not see changes to an unpartitioned cookie.
+ this->CreateAndSetCookie(cs, GURL("https://www.example.com"),
+ "__Host-a=1; Secure; Path=/",
+ CookieOptions::MakeAllInclusive());
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(0u, cookie_changes.size());
+
+ // Set partitioned cookie without nonce. Should not see the change.
+ this->CreateAndSetCookie(
+ cs, GURL("https://www.example.com"),
+ "__Host-a=2; Secure; Path=/; Partitioned",
+ CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(0u, cookie_changes.size());
+
+ // Set partitioned cookie with nonce.
+ this->CreateAndSetCookie(cs, GURL("https://www.example.com"),
+ "__Host-a=3; Secure; Path=/; Partitioned",
+ CookieOptions::MakeAllInclusive(),
+ absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(
+ GURL("https://www.foo.com"), nonce));
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(1u, cookie_changes.size());
+}
+
TYPED_TEST_P(CookieStoreChangeNamedTest, NoCookie) {
if (!TypeParam::supports_named_cookie_tracking)
return;
@@ -2987,16 +3064,14 @@ TYPED_TEST_P(CookieStoreChangeNamedTest, PartitionedCookies) {
"__Host-a=2; Secure; Path=/; Partitioned",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://sub.foo.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://sub.foo.com")));
// Partitioned cookie with a different partition key
this->CreateAndSetCookie(
cs, GURL("https://www.example.com"),
"__Host-a=3; Secure; Path=/; Partitioned",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com")));
this->DeliverChangeNotifications();
ASSERT_EQ(2u, cookie_changes.size());
@@ -3023,14 +3098,61 @@ TYPED_TEST_P(CookieStoreChangeNamedTest, PartitionedCookies) {
"__Host-a=2; Secure; Path=/; Partitioned; Max-Age=7200",
CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
absl::nullopt /* system_time */,
- absl::make_optional(
- CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
this->DeliverChangeNotifications();
ASSERT_EQ(0u, other_cookie_changes.size());
// Check that the other listener was invoked.
ASSERT_LT(2u, cookie_changes.size());
}
+TYPED_TEST_P(CookieStoreChangeNamedTest, PartitionedCookies_WithNonce) {
+ if (!TypeParam::supports_named_cookie_tracking ||
+ !TypeParam::supports_partitioned_cookies) {
+ return;
+ }
+
+ CookieStore* cs = this->GetCookieStore();
+ base::UnguessableToken nonce = base::UnguessableToken::Create();
+
+ std::vector<CookieChangeInfo> cookie_changes;
+ std::unique_ptr<CookieChangeSubscription> subscription =
+ cs->GetChangeDispatcher().AddCallbackForCookie(
+ GURL("https://www.example.com"), "__Host-a",
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"),
+ nonce),
+ base::BindRepeating(
+ &CookieStoreChangeTestBase<TypeParam>::OnCookieChange,
+ base::Unretained(&cookie_changes)));
+
+ // Should not see changes to an unpartitioned cookie.
+ this->CreateAndSetCookie(cs, GURL("https://www.example.com"),
+ "__Host-a=1; Secure; Path=/",
+ CookieOptions::MakeAllInclusive());
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(0u, cookie_changes.size());
+
+ // Set partitioned cookie without nonce. Should not see the change.
+ this->CreateAndSetCookie(
+ cs, GURL("https://www.example.com"),
+ "__Host-a=2; Secure; Path=/; Partitioned",
+ CookieOptions::MakeAllInclusive(), absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(0u, cookie_changes.size());
+
+ // Set partitioned cookie with nonce.
+ this->CreateAndSetCookie(cs, GURL("https://www.example.com"),
+ "__Host-a=3; Secure; Path=/; Partitioned",
+ CookieOptions::MakeAllInclusive(),
+ absl::nullopt /* server_time */,
+ absl::nullopt /* system_time */,
+ CookiePartitionKey::FromURLForTesting(
+ GURL("https://www.foo.com"), nonce));
+ this->DeliverChangeNotifications();
+ ASSERT_EQ(1u, cookie_changes.size());
+}
+
REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeGlobalTest,
NoCookie,
InitialCookie,
@@ -3046,7 +3168,8 @@ REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeGlobalTest,
DeregisterRace,
DeregisterRaceMultiple,
MultipleSubscriptions,
- ChangeIncludesCookieAccessSemantics);
+ ChangeIncludesCookieAccessSemantics,
+ PartitionedCookies);
REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeUrlTest,
NoCookie,
@@ -3071,7 +3194,8 @@ REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeUrlTest,
DifferentSubscriptionsFiltering,
MultipleSubscriptions,
ChangeIncludesCookieAccessSemantics,
- PartitionedCookies);
+ PartitionedCookies,
+ PartitionedCookies_WithNonce);
REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeNamedTest,
NoCookie,
@@ -3098,7 +3222,8 @@ REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeNamedTest,
MultipleSubscriptions,
SubscriptionOutlivesStore,
ChangeIncludesCookieAccessSemantics,
- PartitionedCookies);
+ PartitionedCookies,
+ PartitionedCookies_WithNonce);
} // namespace net
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index fc1523bd4..c56b7e18f 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -56,8 +56,6 @@ unit tests.
- lets-encrypt-isrg-x1-root.pem: A chain that ends in the Lets encrypt ISRG X1
root (https://crt.sh/?id=9314791). Has the same leaf as
lets-encrypt-dst-x3-root.pem.
-- vrk_gov_root.pem: A root certificate that is marked as a legacy CA in the
- known roots list.
===== Manually generated certificates
- client.p12 : A PKCS #12 file containing a client certificate and a private
diff --git a/net/data/ssl/certificates/vrk_gov_root.pem b/net/data/ssl/certificates/vrk_gov_root.pem
deleted file mode 100644
index 078dfc172..000000000
--- a/net/data/ssl/certificates/vrk_gov_root.pem
+++ /dev/null
@@ -1,84 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 100000 (0x186a0)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C = FI, ST = Finland, O = Vaestorekisterikeskus CA, OU = Certification Authority Services, OU = Varmennepalvelut, CN = VRK Gov. Root CA
- Validity
- Not Before: Dec 18 13:53:00 2002 GMT
- Not After : Dec 18 13:51:08 2023 GMT
- Subject: C = FI, ST = Finland, O = Vaestorekisterikeskus CA, OU = Certification Authority Services, OU = Varmennepalvelut, CN = VRK Gov. Root CA
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- RSA Public-Key: (2048 bit)
- Modulus:
- 00:b0:85:15:da:c8:03:37:d0:a3:46:37:6c:1b:1e:
- 96:30:c2:5a:85:12:67:23:f2:bb:9f:e7:8a:81:60:
- 27:f8:13:a9:3c:bc:f7:86:aa:aa:f4:f3:25:29:b4:
- fe:75:ae:1e:81:86:8a:05:b2:1d:65:b2:38:e8:b4:
- cc:28:9a:fb:17:36:f1:93:d5:79:ce:c1:83:8b:21:
- 4f:c3:0d:ad:41:df:78:9d:48:e3:1f:42:44:fc:3c:
- 6d:21:20:6b:ad:22:84:24:42:8f:17:4d:c2:50:1f:
- 64:cd:2d:39:22:56:88:fd:b2:63:9d:54:da:42:69:
- c0:c8:4f:d7:18:e2:3e:c8:69:84:94:3d:2c:80:c6:
- 7c:ce:bd:d7:53:1f:eb:88:b9:a6:cb:bb:85:57:ef:
- 57:76:5d:0c:8b:d3:5e:12:41:9f:21:c0:39:f4:26:
- 6d:08:fa:38:b3:a1:77:b1:ee:16:d8:d0:68:da:b4:
- 98:a5:a0:65:46:4a:6b:8d:7e:aa:4d:60:b8:f8:c8:
- 0d:fc:71:3e:ee:39:87:81:b4:d9:f8:6e:90:ee:3f:
- 0e:61:d7:1d:2b:68:e6:2e:e1:42:44:26:78:2c:58:
- f2:7d:16:7f:61:c0:49:24:2a:89:87:b6:5d:2f:29:
- 19:f8:a6:e7:8e:52:9e:41:4b:5a:0e:aa:b8:c2:66:
- 42:53
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- Netscape Cert Type:
- SSL CA, S/MIME CA, Object Signing CA
- X509v3 Key Usage: critical
- Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
- X509v3 Subject Key Identifier:
- DB:E9:E1:9B:D2:D1:24:0B:FC:AB:E3:A0:67:EA:AE:9C:4B:77:F4:B0
- Signature Algorithm: sha1WithRSAEncryption
- ad:7d:48:0f:54:11:9e:58:ee:af:0d:9b:12:2f:21:a4:cd:9b:
- ba:84:47:e6:c9:25:55:23:e3:df:18:58:2a:2c:db:5e:f7:cd:
- 54:f5:51:24:7b:62:67:e1:b1:1f:49:af:34:d0:eb:b1:cc:d9:
- a2:0d:52:7f:42:4b:88:60:97:cf:25:72:b7:4f:29:2d:62:9f:
- 4f:a1:c0:55:57:56:0e:c4:68:97:91:1f:9c:64:c2:29:32:01:
- e9:d4:c8:da:b8:81:98:28:2e:18:c7:2c:fc:eb:9b:52:96:df:
- f4:c8:90:19:2d:23:f3:f1:bb:71:da:9e:85:23:bd:1a:ef:2e:
- e4:7a:79:b7:c3:9d:86:49:2d:63:b9:2d:74:cf:65:0f:32:66:
- 89:df:3b:21:ee:29:6f:39:63:d9:15:c1:6e:f6:df:80:3e:50:
- 78:19:8a:dd:03:a3:14:a5:37:a7:b5:2c:7c:b6:11:87:e7:05:
- f2:bc:b6:de:d4:ff:97:81:28:84:fe:fe:6c:46:85:10:41:9f:
- 4d:75:8c:07:d4:99:67:6f:75:8a:6f:e4:50:92:f6:99:d5:10:
- b8:c4:a9:7b:f7:17:8d:4b:bf:d7:95:9f:09:dc:44:0f:1e:32:
- c3:c0:cf:d3:79:0d:e4:c7:3b:87:f0:90:34:88:21:62:49:92:
- 04:04:1f:bc
-
------BEGIN CERTIFICATE-----
-MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG
-STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz
-a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl
-czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g
-Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD
-VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0
-ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT
-ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL
-IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF
-FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG
-igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC
-jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7
-hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI
-DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim
-545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB
-hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr
-46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b
-uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy
-t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j
-8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q
-eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k
-UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA==
------END CERTIFICATE-----
-
diff --git a/net/data/test_support_bundle_data.filelist b/net/data/test_support_bundle_data.filelist
index 08d3390ad..a4f984cc6 100644
--- a/net/data/test_support_bundle_data.filelist
+++ b/net/data/test_support_bundle_data.filelist
@@ -205,7 +205,6 @@ data/ssl/certificates/unittest.key.bin
data/ssl/certificates/unittest.selfsigned.der
data/ssl/certificates/verisign_intermediate_ca_2011.pem
data/ssl/certificates/verisign_intermediate_ca_2016.pem
-data/ssl/certificates/vrk_gov_root.pem
data/ssl/certificates/weak_digest_md2_ee.pem
data/ssl/certificates/weak_digest_md2_intermediate.pem
data/ssl/certificates/weak_digest_md2_root.pem
diff --git a/net/dns/address_sorter_posix.cc b/net/dns/address_sorter_posix.cc
index 060e16d54..0f4afb748 100644
--- a/net/dns/address_sorter_posix.cc
+++ b/net/dns/address_sorter_posix.cc
@@ -278,18 +278,6 @@ class AddressSorterPosix::SortContext {
VLOG(1) << "Could not connect to " << dest.ToStringWithoutPort()
<< " reason " << rv;
sort_list_[info_index].failed = true;
- MaybeFinishSort();
- return;
- }
- // Filter out unusable destinations.
- IPEndPoint src;
- rv = sort_list_[info_index].socket->GetLocalAddress(&src);
- if (rv != OK) {
- LOG(WARNING) << "Could not get local address for "
- << dest.ToStringWithoutPort() << " reason " << rv;
- sort_list_[info_index].failed = true;
- MaybeFinishSort();
- return;
}
MaybeFinishSort();
@@ -303,10 +291,21 @@ class AddressSorterPosix::SortContext {
if (num_completed_ != num_endpoints_) {
return;
}
- base::EraseIf(sort_list_, [](auto& element) { return element.failed; });
for (auto& info : sort_list_) {
+ if (info.failed) {
+ continue;
+ }
+
IPEndPoint src;
- info.socket->GetLocalAddress(&src);
+ // Filter out unusable destinations.
+ int rv = info.socket->GetLocalAddress(&src);
+ if (rv != OK) {
+ LOG(WARNING) << "Could not get local address for "
+ << info.endpoint.ToStringWithoutPort() << " reason " << rv;
+ info.failed = true;
+ continue;
+ }
+
auto iter = sorter_->source_map_.find(src.address());
if (iter == sorter_->source_map_.end()) {
// |src.address| may not be in the map if |source_info_| has not been
@@ -327,6 +326,7 @@ class AddressSorterPosix::SortContext {
info.src.prefix_length);
}
}
+ base::EraseIf(sort_list_, [](auto& element) { return element.failed; });
std::stable_sort(sort_list_.begin(), sort_list_.end(), CompareDestinations);
std::vector<IPEndPoint> sorted_result;
diff --git a/net/first_party_sets/addition_overlaps_union_find.h b/net/first_party_sets/addition_overlaps_union_find.h
index eeabb6eb8..cd92802d6 100644
--- a/net/first_party_sets/addition_overlaps_union_find.h
+++ b/net/first_party_sets/addition_overlaps_union_find.h
@@ -28,7 +28,7 @@ class NET_EXPORT AdditionOverlapsUnionFind {
// Unions the two given sets together if they are in disjoint sets, and does
// nothing if they are non-disjoint.
// Unions are non-commutative for First-Party Sets; this method always chooses
- // the set with the lesser index as the owner.
+ // the set with the lesser index as the primary.
// Both set indices (set_x, set_y) must be in the range [0, num_sets) where
// num_sets is the argument given to the constructor.
// If Union is called when num_sets = 0, then this will crash.
diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc
index ad5d30fa3..51cb3422e 100644
--- a/net/first_party_sets/global_first_party_sets.cc
+++ b/net/first_party_sets/global_first_party_sets.cc
@@ -275,21 +275,22 @@ FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
FlattenedSets flattened_additions =
SetListToFlattenedSets(normalized_additions);
- // All of the custom sets are automatically inserted into site_to_owner.
+ // All of the custom sets are automatically inserted into site_to_entry.
UpdateCustomizations(replacement_sets, site_to_entry);
UpdateCustomizations(normalized_additions, site_to_entry);
- // Maps old owner to new entry.
- base::flat_map<SchemefulSite, FirstPartySetEntry> addition_intersected_owners;
+ // Maps old primary site to new entry.
+ base::flat_map<SchemefulSite, FirstPartySetEntry>
+ addition_intersected_primaries;
for (const auto& [new_member, new_entry] : flattened_additions) {
if (const auto entry = FindEntry(new_member, /*config=*/nullptr);
entry.has_value()) {
// Found an overlap with the existing list of sets.
- addition_intersected_owners.emplace(entry->primary(), new_entry);
+ addition_intersected_primaries.emplace(entry->primary(), new_entry);
}
}
- // Maps an existing owner to the members it lost due to replacement.
+ // Maps an existing primary site to the members it lost due to replacement.
base::flat_map<SchemefulSite, base::flat_set<SchemefulSite>>
potential_singletons;
for (const auto& [member, set_entry] : flattened_replacements) {
@@ -297,30 +298,30 @@ FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
continue;
if (const auto existing_entry = FindEntry(member, /*config=*/nullptr);
existing_entry.has_value() && existing_entry->primary() != member &&
- !addition_intersected_owners.contains(existing_entry->primary()) &&
+ !addition_intersected_primaries.contains(existing_entry->primary()) &&
!flattened_additions.contains(existing_entry->primary()) &&
!flattened_replacements.contains(existing_entry->primary())) {
potential_singletons[existing_entry->primary()].insert(member);
}
}
- // Find the existing owners that have left their existing sets, and whose
- // existing members should be removed from their set (excluding any custom
- // sets that those members are involved in).
- base::flat_set<SchemefulSite> replaced_existing_owners;
- for (const auto& [site, unused_owner] : flattened_replacements) {
+ // Find the existing primary sites that have left their existing sets, and
+ // whose existing members should be removed from their set (excluding any
+ // custom sets that those members are involved in).
+ base::flat_set<SchemefulSite> replaced_existing_primaries;
+ for (const auto& [site, unused_primary] : flattened_replacements) {
if (const auto entry = FindEntry(site, /*config=*/nullptr);
entry.has_value() && entry->primary() == site) {
- // Site was an owner in the existing sets.
- bool inserted = replaced_existing_owners.emplace(site).second;
+ // Site was an primary in the existing sets.
+ bool inserted = replaced_existing_primaries.emplace(site).second;
CHECK(inserted);
}
}
- if (!addition_intersected_owners.empty() || !potential_singletons.empty() ||
- !replaced_existing_owners.empty()) {
+ if (!addition_intersected_primaries.empty() ||
+ !potential_singletons.empty() || !replaced_existing_primaries.empty()) {
// Find out which potential singletons are actually singletons; delete
- // members whose owners left; and reparent the sets that intersected with
+ // members whose primaries left; and reparent the sets that intersected with
// an addition set.
// Note: use a null config here, to avoid taking unrelated policy sets into
// account.
@@ -329,8 +330,8 @@ FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
[&](const SchemefulSite& member, const FirstPartySetEntry& set_entry) {
// Reparent all sites in any intersecting addition sets.
if (const auto entry =
- addition_intersected_owners.find(set_entry.primary());
- entry != addition_intersected_owners.end() &&
+ addition_intersected_primaries.find(set_entry.primary());
+ entry != addition_intersected_primaries.end() &&
!flattened_replacements.contains(member)) {
site_to_entry.emplace_back(
member, FirstPartySetEntry(entry->second.primary(),
@@ -345,24 +346,24 @@ FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
if (const auto entry = potential_singletons.find(set_entry.primary());
entry != potential_singletons.end() &&
!entry->second.contains(member)) {
- // This owner lost members, but it still has at least one
+ // This primary lost members, but it still has at least one
// (`member`), so it's not a singleton.
potential_singletons.erase(entry);
}
- // Remove members from sets whose owner left.
- if (replaced_existing_owners.contains(set_entry.primary()) &&
+ // Remove members from sets whose primary left.
+ if (replaced_existing_primaries.contains(set_entry.primary()) &&
!flattened_replacements.contains(member) &&
- !addition_intersected_owners.contains(set_entry.primary())) {
+ !addition_intersected_primaries.contains(set_entry.primary())) {
site_to_entry.emplace_back(member, FirstPartySetEntryOverride());
}
return true;
});
- // Any owner remaining in `potential_singleton` is a real singleton, so
+ // Any primary remaining in `potential_singleton` is a real singleton, so
// delete it:
- for (const auto& [owner, members] : potential_singletons) {
- site_to_entry.emplace_back(owner, FirstPartySetEntryOverride());
+ for (const auto& [primary, members] : potential_singletons) {
+ site_to_entry.emplace_back(primary, FirstPartySetEntryOverride());
}
}
diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
index fdac238f9..cc2b42c89 100644
--- a/net/first_party_sets/global_first_party_sets.h
+++ b/net/first_party_sets/global_first_party_sets.h
@@ -168,8 +168,8 @@ class NET_EXPORT GlobalFirstPartySets {
addition_sets) const;
// Returns whether `site` is same-party with `party_context`, and
- // `top_frame_site` (if it is not nullptr). That is, is `site`'s owner the
- // same as the owners of every member of `party_context` and of
+ // `top_frame_site` (if it is not nullptr). That is, is `site`'s primary the
+ // same as the primaries of every member of `party_context` and of
// `top_frame_site`? Note: if `site` is not a member of a First-Party Set,
// then this returns false. If `top_frame_site` is nullptr, then it is
// ignored.
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 025869ad6..f6f9bf3c0 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -996,8 +996,6 @@ void HttpCache::WritersDoneWritingToEntry(ActiveEntry* entry,
DCHECK(entry->writers->IsEmpty());
DCHECK(success || make_readers.empty());
- entry->writers_done_writing_to_entry_history = absl::make_optional(success);
-
if (!success && should_keep_entry) {
// Restart already validated transactions so that they are able to read
// the truncated status of the entry.
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 52682432f..ddbcbab14 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -395,8 +395,6 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
// True if entry is doomed.
bool doomed = false;
-
- absl::optional<bool> writers_done_writing_to_entry_history;
};
using ActiveEntriesMap =
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index d8c1a38e2..d8bade0a8 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -124,6 +124,15 @@ HttpNetworkTransaction::~HttpNetworkTransaction() {
// this network transaction was prematurely cancelled.
GenerateNetworkErrorLoggingReport(ERR_ABORTED);
#endif // BUILDFLAG(ENABLE_REPORTING)
+
+ if (quic_protocol_error_retry_delay_) {
+ base::UmaHistogramTimes(
+ IsGoogleHostWithAlpnH3(url_.host())
+ ? "Net.QuicProtocolErrorRetryDelayH3SupportedGoogleHost.Failure"
+ : "Net.QuicProtocolErrorRetryDelay.Failure",
+ *quic_protocol_error_retry_delay_);
+ }
+
if (stream_.get()) {
// TODO(mbelshe): The stream_ should be able to compute whether or not the
// stream should be kept alive. No reason to compute here
@@ -164,8 +173,8 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
request_->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
&request_user_agent_);
request_reporting_upload_depth_ = request_->reporting_upload_depth;
- start_timeticks_ = base::TimeTicks::Now();
#endif // BUILDFLAG(ENABLE_REPORTING)
+ start_timeticks_ = base::TimeTicks::Now();
if (request_->load_flags & LOAD_DISABLE_CERT_NETWORK_FETCHES) {
server_ssl_config_.disable_cert_verification_network_fetches = true;
@@ -1175,7 +1184,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
response_.headers->response_code());
// This will close the socket - it would be weird to try and reuse it, even
// if the server doesn't actually close it.
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(RetryReason::kHttpRequestTimeout);
return OK;
}
@@ -1227,7 +1236,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
enable_alternative_services_ = false;
net_log_.AddEvent(
NetLogEventType::HTTP_TRANSACTION_RESTART_MISDIRECTED_REQUEST);
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(RetryReason::kHttpMisdirectedRequest);
return OK;
}
@@ -1341,6 +1350,15 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) {
#if BUILDFLAG(ENABLE_REPORTING)
GenerateNetworkErrorLoggingReport(result);
#endif // BUILDFLAG(ENABLE_REPORTING)
+
+ if (result == OK && quic_protocol_error_retry_delay_) {
+ base::UmaHistogramTimes(
+ IsGoogleHostWithAlpnH3(url_.host())
+ ? "Net.QuicProtocolErrorRetryDelayH3SupportedGoogleHost.Success"
+ : "Net.QuicProtocolErrorRetryDelay.Success",
+ *quic_protocol_error_retry_delay_);
+ quic_protocol_error_retry_delay_.reset();
+ }
}
// Clear these to avoid leaving around old state.
@@ -1522,7 +1540,7 @@ int HttpNetworkTransaction::HandleHttp11Required(int error) {
// HttpServerProperties should have been updated, so when the request is sent
// again, it will automatically use HTTP/1.1.
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(RetryReason::kHttp11Required);
return OK;
}
@@ -1569,7 +1587,8 @@ int HttpNetworkTransaction::HandleSSLClientAuthError(int error) {
retry_attempts_++;
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(
+ RetryReason::kSslClientAuthSignatureFailed);
return OK;
}
}
@@ -1577,6 +1596,44 @@ int HttpNetworkTransaction::HandleSSLClientAuthError(int error) {
return error;
}
+// static
+absl::optional<HttpNetworkTransaction::RetryReason>
+HttpNetworkTransaction::GetRetryReasonForIOError(int error) {
+ switch (error) {
+ case ERR_CONNECTION_RESET:
+ return RetryReason::kConnectionReset;
+ case ERR_CONNECTION_CLOSED:
+ return RetryReason::kConnectionClosed;
+ case ERR_CONNECTION_ABORTED:
+ return RetryReason::kConnectionAborted;
+ case ERR_SOCKET_NOT_CONNECTED:
+ return RetryReason::kSocketNotConnected;
+ case ERR_EMPTY_RESPONSE:
+ return RetryReason::kEmptyResponse;
+ case ERR_EARLY_DATA_REJECTED:
+ return RetryReason::kEarlyDataRejected;
+ case ERR_WRONG_VERSION_ON_EARLY_DATA:
+ return RetryReason::kWrongVersionOnEarlyData;
+ case ERR_HTTP2_PING_FAILED:
+ return RetryReason::kHttp2PingFailed;
+ case ERR_HTTP2_SERVER_REFUSED_STREAM:
+ return RetryReason::kHttp2ServerRefusedStream;
+ case ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE:
+ return RetryReason::kHttp2PushedStreamNotAvailable;
+ case ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER:
+ return RetryReason::kHttp2ClaimedPushedStreamResetByServer;
+ case ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH:
+ return RetryReason::kHttp2PushedResponseDoesNotMatch;
+ case ERR_QUIC_HANDSHAKE_FAILED:
+ return RetryReason::kQuicHandshakeFailed;
+ case ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED:
+ return RetryReason::kQuicGoawayRequestCanBeRetried;
+ case ERR_QUIC_PROTOCOL_ERROR:
+ return RetryReason::kQuicProtocolError;
+ }
+ return absl::nullopt;
+}
+
// This method determines whether it is safe to resend the request after an
// IO error. It should only be called in response to errors received before
// final set of response headers have been successfully parsed, that the
@@ -1591,14 +1648,19 @@ int HttpNetworkTransaction::HandleIOError(int error) {
GenerateNetworkErrorLoggingReportIfError(error);
#endif // BUILDFLAG(ENABLE_REPORTING)
- switch (error) {
+ absl::optional<HttpNetworkTransaction::RetryReason> retry_reason =
+ GetRetryReasonForIOError(error);
+ if (!retry_reason) {
+ return error;
+ }
+ switch (*retry_reason) {
// If we try to reuse a connection that the server is in the process of
// closing, we may end up successfully writing out our request (or a
// portion of our request) only to find a connection error when we try to
// read from (or finish writing to) the socket.
- case ERR_CONNECTION_RESET:
- case ERR_CONNECTION_CLOSED:
- case ERR_CONNECTION_ABORTED:
+ case RetryReason::kConnectionReset:
+ case RetryReason::kConnectionClosed:
+ case RetryReason::kConnectionAborted:
// There can be a race between the socket pool checking checking whether a
// socket is still connected, receiving the FIN, and sending/reading data
// on a reused socket. If we receive the FIN between the connectedness
@@ -1606,62 +1668,75 @@ int HttpNetworkTransaction::HandleIOError(int error) {
// is disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most
// likely happen when trying to retrieve its IP address.
// See http://crbug.com/105824 for more details.
- case ERR_SOCKET_NOT_CONNECTED:
+ case RetryReason::kSocketNotConnected:
// If a socket is closed on its initial request, HttpStreamParser returns
// ERR_EMPTY_RESPONSE. This may still be close/reuse race if the socket was
// preconnected but failed to be used before the server timed it out.
- case ERR_EMPTY_RESPONSE:
+ case RetryReason::kEmptyResponse:
if (ShouldResendRequest()) {
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(*retry_reason);
error = OK;
}
break;
- case ERR_EARLY_DATA_REJECTED:
- case ERR_WRONG_VERSION_ON_EARLY_DATA:
+ case RetryReason::kEarlyDataRejected:
+ case RetryReason::kWrongVersionOnEarlyData:
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
// Disable early data on the SSLConfig on a reset.
can_send_early_data_ = false;
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(*retry_reason);
error = OK;
break;
- case ERR_HTTP2_PING_FAILED:
- case ERR_HTTP2_SERVER_REFUSED_STREAM:
- case ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE:
- case ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER:
- case ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH:
- case ERR_QUIC_HANDSHAKE_FAILED:
- case ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED:
+ case RetryReason::kHttp2PingFailed:
+ case RetryReason::kHttp2ServerRefusedStream:
+ case RetryReason::kHttp2PushedStreamNotAvailable:
+ case RetryReason::kHttp2ClaimedPushedStreamResetByServer:
+ case RetryReason::kHttp2PushedResponseDoesNotMatch:
+ case RetryReason::kQuicHandshakeFailed:
+ case RetryReason::kQuicGoawayRequestCanBeRetried:
if (HasExceededMaxRetries())
break;
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
retry_attempts_++;
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(*retry_reason);
error = OK;
break;
- case ERR_QUIC_PROTOCOL_ERROR:
- if (GetResponseHeaders() != nullptr ||
- !stream_->GetAlternativeService(&retried_alternative_service_)) {
+ case RetryReason::kQuicProtocolError:
+ if (GetResponseHeaders() != nullptr) {
// If the response headers have already been received and passed up
- // then the request can not be retried. Also, if there was no
- // alternative service used for this request, then there is no
- // alternative service to be disabled.
+ // then the request can not be retried.
+ RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus::kNoRetryHeaderReceived);
break;
}
- if (HasExceededMaxRetries())
+ if (!stream_->GetAlternativeService(&retried_alternative_service_)) {
+ // If there was no alternative service used for this request, then there
+ // is no alternative service to be disabled. Note: We expect this
+ // doesn't happen. But records the UMA just in case.
+ RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus::kNoRetryNoAlternativeService);
break;
+ }
+ if (HasExceededMaxRetries()) {
+ RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus::kNoRetryExceededMaxRetries);
+ break;
+ }
+
if (session_->http_server_properties()->IsAlternativeServiceBroken(
retried_alternative_service_, network_anonymization_key_)) {
// If the alternative service was marked as broken while the request
// was in flight, retry the request which will not use the broken
// alternative service.
+ RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus::kRetryAltServiceBroken);
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
retry_attempts_++;
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(*retry_reason);
error = OK;
} else if (session_->context()
.quic_context->params()
@@ -1669,14 +1744,24 @@ int HttpNetworkTransaction::HandleIOError(int error) {
// Disable alternative services for this request and retry it. If the
// retry succeeds, then the alternative service will be marked as
// broken then.
+ RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus::kRetryAltServiceNotBroken);
enable_alternative_services_ = false;
net_log_.AddEventWithNetErrorCode(
NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
retry_attempts_++;
- ResetConnectionAndRequestForResend();
+ ResetConnectionAndRequestForResend(*retry_reason);
error = OK;
}
break;
+
+ // The following reasons are not covered here.
+ case RetryReason::kHttpRequestTimeout:
+ case RetryReason::kHttpMisdirectedRequest:
+ case RetryReason::kHttp11Required:
+ case RetryReason::kSslClientAuthSignatureFailed:
+ NOTREACHED();
+ break;
}
return error;
}
@@ -1707,8 +1792,8 @@ void HttpNetworkTransaction::ResetStateForAuthRestart() {
net_error_details_.quic_connection_error = quic::QUIC_NO_ERROR;
#if BUILDFLAG(ENABLE_REPORTING)
network_error_logging_report_generated_ = false;
- start_timeticks_ = base::TimeTicks::Now();
#endif // BUILDFLAG(ENABLE_REPORTING)
+ start_timeticks_ = base::TimeTicks::Now();
}
void HttpNetworkTransaction::CacheNetErrorDetailsAndResetStream() {
@@ -1740,7 +1825,18 @@ bool HttpNetworkTransaction::CheckMaxRestarts() {
return num_restarts_ < kMaxRestarts;
}
-void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
+void HttpNetworkTransaction::ResetConnectionAndRequestForResend(
+ RetryReason retry_reason) {
+ base::UmaHistogramEnumeration(
+ IsGoogleHostWithAlpnH3(url_.host())
+ ? "Net.NetworkTransactionH3SupportedGoogleHost.RetryReason"
+ : "Net.NetworkTransaction.RetryReason",
+ retry_reason);
+ if (retry_reason == RetryReason::kQuicProtocolError) {
+ quic_protocol_error_retry_delay_ =
+ base::TimeTicks::Now() - start_timeticks_;
+ }
+
if (stream_.get()) {
stream_->Close(true);
CacheNetErrorDetailsAndResetStream();
@@ -1755,8 +1851,8 @@ void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
#if BUILDFLAG(ENABLE_REPORTING)
// Reset for new request.
network_error_logging_report_generated_ = false;
- start_timeticks_ = base::TimeTicks::Now();
#endif // BUILDFLAG(ENABLE_REPORTING)
+ start_timeticks_ = base::TimeTicks::Now();
ResetStateForRestart();
}
@@ -1888,4 +1984,43 @@ bool HttpNetworkTransaction::ContentEncodingsValid() const {
return result;
}
+void HttpNetworkTransaction::RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus retry_status) {
+ std::string histogram = "Net.QuicProtocolError";
+ if (IsGoogleHostWithAlpnH3(url_.host())) {
+ histogram += "H3SupportedGoogleHost";
+ }
+ base::UmaHistogramEnumeration(histogram + ".RetryStatus", retry_status);
+
+ if (!stream_) {
+ return;
+ }
+ absl::optional<quic::QuicErrorCode> connection_error =
+ stream_->GetQuicErrorCode();
+ absl::optional<quic::QuicRstStreamErrorCode> stream_error =
+ stream_->GetQuicRstStreamErrorCode();
+ if (!connection_error || !stream_error) {
+ return;
+ }
+ switch (retry_status) {
+ case QuicProtocolErrorRetryStatus::kNoRetryExceededMaxRetries:
+ histogram += ".NoRetryExceededMaxRetries";
+ break;
+ case QuicProtocolErrorRetryStatus::kNoRetryHeaderReceived:
+ histogram += ".NoRetryHeaderReceived";
+ break;
+ case QuicProtocolErrorRetryStatus::kNoRetryNoAlternativeService:
+ histogram += ".NoRetryNoAlternativeService";
+ break;
+ case QuicProtocolErrorRetryStatus::kRetryAltServiceBroken:
+ histogram += ".RetryAltServiceBroken";
+ break;
+ case QuicProtocolErrorRetryStatus::kRetryAltServiceNotBroken:
+ histogram += ".RetryAltServiceNotBroken";
+ break;
+ }
+ base::UmaHistogramSparse(histogram + ".QuicErrorCode", *connection_error);
+ base::UmaHistogramSparse(histogram + ".QuicStreamErrorCode", *stream_error);
+}
+
} // namespace net
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 4ef51e66b..8e6ade134 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -34,6 +34,7 @@
#include "net/socket/connection_attempts.h"
#include "net/ssl/ssl_config_service.h"
#include "net/websockets/websocket_handshake_stream_base.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
@@ -261,9 +262,35 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// proceed.
bool CheckMaxRestarts();
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class RetryReason {
+ kHttpRequestTimeout = 0,
+ kHttpMisdirectedRequest = 1,
+ kHttp11Required = 2,
+ kSslClientAuthSignatureFailed = 3,
+ kConnectionReset = 4,
+ kConnectionClosed = 5,
+ kConnectionAborted = 6,
+ kSocketNotConnected = 7,
+ kEmptyResponse = 8,
+ kEarlyDataRejected = 9,
+ kWrongVersionOnEarlyData = 10,
+ kHttp2PingFailed = 11,
+ kHttp2ServerRefusedStream = 12,
+ kHttp2PushedStreamNotAvailable = 13,
+ kHttp2ClaimedPushedStreamResetByServer = 14,
+ kHttp2PushedResponseDoesNotMatch = 15,
+ kQuicHandshakeFailed = 16,
+ kQuicGoawayRequestCanBeRetried = 17,
+ kQuicProtocolError = 18,
+ kMaxValue = kQuicProtocolError,
+ };
+ static absl::optional<RetryReason> GetRetryReasonForIOError(int error);
+
// Resets the connection and the request headers for resend. Called when
// ShouldResendRequest() is true.
- void ResetConnectionAndRequestForResend();
+ void ResetConnectionAndRequestForResend(RetryReason retry_reason);
// Sets up the state machine to restart the transaction with auth.
void PrepareForAuthRestart(HttpAuth::Target target);
@@ -312,6 +339,23 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
void ResumeAfterConnected(int result);
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class QuicProtocolErrorRetryStatus {
+ kNoRetryExceededMaxRetries = 0,
+ kNoRetryHeaderReceived = 1,
+ kNoRetryNoAlternativeService = 2,
+ kRetryAltServiceBroken = 3,
+ kRetryAltServiceNotBroken = 4,
+ kMaxValue = kRetryAltServiceNotBroken,
+ };
+
+ void RecordQuicProtocolErrorMetrics(
+ QuicProtocolErrorRetryStatus retry_status);
+
+ void RecordMetricsIfError(int rv);
+ void RecordMetrics(int rv);
+
scoped_refptr<HttpAuthController>
auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
@@ -376,8 +420,8 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
std::string request_referrer_;
std::string request_user_agent_;
int request_reporting_upload_depth_ = 0;
- base::TimeTicks start_timeticks_;
#endif
+ base::TimeTicks start_timeticks_;
// The size in bytes of the buffer we use to drain the response body that
// we want to throw away. The response body is typically a small error
@@ -449,6 +493,8 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
size_t num_restarts_ = 0;
bool close_connection_on_destruction_ = false;
+
+ absl::optional<base::TimeDelta> quic_protocol_error_retry_delay_;
};
} // namespace net
diff --git a/net/http/http_status_code_list.h b/net/http/http_status_code_list.h
index 49ccb19bd..b954fbe04 100644
--- a/net/http/http_status_code_list.h
+++ b/net/http/http_status_code_list.h
@@ -70,6 +70,7 @@ HTTP_STATUS_ENUM_VALUE(REQUESTED_RANGE_NOT_SATISFIABLE,
HTTP_STATUS_ENUM_VALUE(EXPECTATION_FAILED, 417, "Expectation Failed")
// 418 returned by Cloud Print.
HTTP_STATUS_ENUM_VALUE(INVALID_XPRIVET_TOKEN, 418, "Invalid XPrivet Token")
+HTTP_STATUS_ENUM_VALUE(UNPROCESSABLE_CONTENT, 422, "Unprocessable Content")
HTTP_STATUS_ENUM_VALUE(TOO_EARLY, 425, "Too Early")
HTTP_STATUS_ENUM_VALUE(TOO_MANY_REQUESTS, 429, "Too Many Requests")
diff --git a/net/http/http_stream.cc b/net/http/http_stream.cc
new file mode 100644
index 000000000..d1e6acec5
--- /dev/null
+++ b/net/http/http_stream.cc
@@ -0,0 +1,18 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_stream.h"
+
+namespace net {
+
+absl::optional<quic::QuicErrorCode> HttpStream::GetQuicErrorCode() const {
+ return absl::nullopt;
+}
+
+absl::optional<quic::QuicRstStreamErrorCode>
+HttpStream::GetQuicRstStreamErrorCode() const {
+ return absl::nullopt;
+}
+
+} // namespace net
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index f8f40d216..7e373920e 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -24,6 +24,8 @@
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/http/http_raw_request_headers.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_error_codes.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
@@ -211,6 +213,15 @@ class NET_EXPORT_PRIVATE HttpStream {
// Accept-CH header fields received in HTTP responses, this value is available
// before any requests are made.
virtual base::StringPiece GetAcceptChViaAlps() const = 0;
+
+ // If `this` is using a Quic stream, set the `connection_error` of the Quic
+ // stream. Otherwise returns nullopt.
+ virtual absl::optional<quic::QuicErrorCode> GetQuicErrorCode() const;
+
+ // If `this` is using a Quic stream, set the `stream_error' status of the Quic
+ // stream. Otherwise returns nullopt.
+ virtual absl::optional<quic::QuicRstStreamErrorCode>
+ GetQuicRstStreamErrorCode() const;
};
} // namespace net
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 5f3c3a3fe..e39adae5c 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
# hash function for preloaded entries again (we have already done so once).
#
-# Last updated: 2023-04-10 12:55 UTC
+# Last updated: 2023-04-13 12:54 UTC
PinsListTimestamp
-1681131302
+1681390459
TestSPKI
sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 36ed21a38..c35221a45 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -4306,18 +4306,27 @@ EVENT_TYPE(TRANSPORT_SECURITY_STATE_SHOULD_UPGRADE_TO_SSL)
// Oblivious HTTP
// ------------------------------------------------------------------------
-// OBLIVIOUS_HTTP_REQUEST_START is emitted when an oblivious HTTP request is
-// started.
-EVENT_TYPE(OBLIVIOUS_HTTP_REQUEST_START)
-
-// OBLIVIOUS_HTTP_REQUEST_END is emitted when an oblivious HTTP request ends.
-// The net error "status" code for the request is attached.
-EVENT_TYPE(OBLIVIOUS_HTTP_REQUEST_END)
+// OBLIVIOUS_HTTP_REQUEST measures the time between when Oblivoius HTTP
+// has begun and when Oblivious HTTP has ended (either success or failure).
+// The following parameters are attached:
+// {
+// "net_error": <The net error code integer, can be a failure or a success>,
+// "outer_response_error_code": <The HTTP error code of the outer relay HTTP
+// response, set iff the result fails because the outer HTTP response status
+// code is not HTTP_OK>,
+// "inner_response_code": <The HTTP code of the inner gateway HTTP response,
+// parsed out from the binary HTTP structure>
+// }
+EVENT_TYPE(OBLIVIOUS_HTTP_REQUEST)
-// OBLIVIOUS_HTTP_REQUEST_DATA logs either just the headers of the request or
+// OBLIVIOUS_HTTP_REQUEST_DATA logs either just the byte count of the request or
// the entire request (depending on capture settings), before encryption.
EVENT_TYPE(OBLIVIOUS_HTTP_REQUEST_DATA)
-// OBLIVIOUS_HTTP_RESPONSE_DATA logs either just the headers of the response or
-// the entire response (depending on capture settings), after decryption.
+// OBLIVIOUS_HTTP_RESPONSE_DATA logs either just the byte count of the response
+// or the entire response (depending on capture settings), after decryption.
EVENT_TYPE(OBLIVIOUS_HTTP_RESPONSE_DATA)
+
+// OBLIVIOUS_HTTP_RESPONSE_HEADERS logs headers of the response, after
+// decryption.
+EVENT_TYPE(OBLIVIOUS_HTTP_RESPONSE_HEADERS)
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 27b10c6cb..8d9ade2af 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -213,16 +213,9 @@ void NetworkQualityEstimator::NotifyStartTransaction(
if (!RequestSchemeIsHTTPOrHTTPS(request))
return;
- // Update |estimated_quality_at_last_main_frame_| if this is a main frame
- // request.
// TODO(tbansal): Refactor this to a separate method.
if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
- base::TimeTicks now = tick_clock_->NowTicks();
- last_main_frame_request_ = now;
-
ComputeEffectiveConnectionType();
- effective_connection_type_at_last_main_frame_ = effective_connection_type_;
- estimated_quality_at_last_main_frame_ = network_quality_;
} else {
MaybeComputeEffectiveConnectionType();
}
@@ -293,7 +286,6 @@ void NetworkQualityEstimator::NotifyHeadersReceived(
if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
ComputeEffectiveConnectionType();
- RecordMetricsOnMainFrameRequest();
}
LoadTimingInfo load_timing_info;
@@ -477,8 +469,6 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
network_quality_ = nqe::internal::NetworkQuality();
end_to_end_rtt_ = absl::nullopt;
effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
- effective_connection_type_at_last_main_frame_ =
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
rtt_observations_size_at_last_ect_computation_ = 0;
throughput_observations_size_at_last_ect_computation_ = 0;
new_rtt_observations_since_last_ect_computation_ = 0;
@@ -486,7 +476,6 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
transport_rtt_observation_count_last_ect_computation_ = 0;
end_to_end_rtt_observation_count_at_last_ect_computation_ = 0;
last_socket_watcher_rtt_notification_ = base::TimeTicks();
- estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality();
cached_estimate_applied_ = false;
GatherEstimatesForNextConnectionType();
@@ -527,7 +516,6 @@ void NetworkQualityEstimator::ContinueGatherEstimatesForNextConnectionType(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Update the local state as part of preparation for the new connection.
current_network_id_ = network_id;
- RecordNetworkIDAvailability();
// Read any cached estimates for the new network. If cached estimates are
// unavailable, add the default estimates.
@@ -537,47 +525,6 @@ void NetworkQualityEstimator::ContinueGatherEstimatesForNextConnectionType(
ComputeEffectiveConnectionType();
}
-void NetworkQualityEstimator::RecordNetworkIDAvailability() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (current_network_id_.type ==
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI ||
- NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
- UMA_HISTOGRAM_BOOLEAN("NQE.NetworkIdAvailable",
- !current_network_id_.id.empty());
- }
-}
-
-void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (estimated_quality_at_last_main_frame_.http_rtt() !=
- nqe::internal::InvalidRTT()) {
- // Add the 50th percentile value.
- LOCAL_HISTOGRAM_TIMES("NQE.MainFrame.RTT.Percentile50",
- estimated_quality_at_last_main_frame_.http_rtt());
- }
-
- if (estimated_quality_at_last_main_frame_.transport_rtt() !=
- nqe::internal::InvalidRTT()) {
- // Add the 50th percentile value.
- LOCAL_HISTOGRAM_TIMES(
- "NQE.MainFrame.TransportRTT.Percentile50",
- estimated_quality_at_last_main_frame_.transport_rtt());
- }
-
- if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
- nqe::internal::INVALID_RTT_THROUGHPUT) {
- // Add the 50th percentile value.
- LOCAL_HISTOGRAM_COUNTS_1000000(
- "NQE.MainFrame.Kbps.Percentile50",
- estimated_quality_at_last_main_frame_.downstream_throughput_kbps());
- }
-
- LOCAL_HISTOGRAM_ENUMERATION("NQE.MainFrame.EffectiveConnectionType",
- effective_connection_type_at_last_main_frame_,
- EFFECTIVE_CONNECTION_TYPE_LAST);
-}
-
void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -599,31 +546,14 @@ void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
network_quality_ = nqe::internal::NetworkQuality(http_rtt, transport_rtt,
downstream_throughput_kbps);
ClampKbpsBasedOnEct();
-
- UMA_HISTOGRAM_ENUMERATION("NQE.EffectiveConnectionType.OnECTComputation",
- effective_connection_type_,
- EFFECTIVE_CONNECTION_TYPE_LAST);
if (network_quality_.http_rtt() != nqe::internal::InvalidRTT()) {
UMA_HISTOGRAM_TIMES("NQE.RTT.OnECTComputation",
network_quality_.http_rtt());
}
- if (network_quality_.transport_rtt() != nqe::internal::InvalidRTT()) {
- UMA_HISTOGRAM_TIMES("NQE.TransportRTT.OnECTComputation",
- network_quality_.transport_rtt());
- }
-
- if (end_to_end_rtt != nqe::internal::InvalidRTT()) {
- UMA_HISTOGRAM_TIMES("NQE.EndToEndRTT.OnECTComputation", end_to_end_rtt);
- }
end_to_end_rtt_ = absl::nullopt;
- if (end_to_end_rtt != nqe::internal::InvalidRTT())
+ if (end_to_end_rtt != nqe::internal::InvalidRTT()) {
end_to_end_rtt_ = end_to_end_rtt;
-
- if (network_quality_.downstream_throughput_kbps() !=
- nqe::internal::INVALID_RTT_THROUGHPUT) {
- UMA_HISTOGRAM_COUNTS_1M("NQE.Kbps.OnECTComputation",
- network_quality_.downstream_throughput_kbps());
}
NotifyObserversOfRTTOrThroughputComputed();
@@ -690,8 +620,6 @@ void NetworkQualityEstimator::AdjustHttpRttBasedOnRTTCounts(
params_->http_rtt_transport_rtt_min_count() ||
end_to_end_rtt_observation_count_at_last_ect_computation_ >=
params_->http_rtt_transport_rtt_min_count()) {
- UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts",
- base::TimeDelta());
return;
}
@@ -701,8 +629,6 @@ void NetworkQualityEstimator::AdjustHttpRttBasedOnRTTCounts(
tick_clock_->NowTicks() - last_connection_change_;
if (cached_estimate_applied_ &&
time_since_connection_change <= base::Minutes(1)) {
- UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts",
- base::TimeDelta());
return;
}
@@ -711,8 +637,6 @@ void NetworkQualityEstimator::AdjustHttpRttBasedOnRTTCounts(
// HTTP RTT can't be trusted due to hanging GETs. In that case, return the
// typical HTTP RTT for a fast connection.
if (current_network_id_.type == net::NetworkChangeNotifier::CONNECTION_NONE) {
- UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts",
- base::TimeDelta());
return;
}
@@ -720,15 +644,10 @@ void NetworkQualityEstimator::AdjustHttpRttBasedOnRTTCounts(
params_->TypicalNetworkQuality(net::EFFECTIVE_CONNECTION_TYPE_4G)
.http_rtt();
if (upper_bound_http_rtt > *http_rtt) {
- UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts",
- base::TimeDelta());
return;
}
DCHECK_LE(upper_bound_http_rtt, *http_rtt);
-
- UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts",
- *http_rtt - upper_bound_http_rtt);
*http_rtt = upper_bound_http_rtt;
}
@@ -1036,11 +955,10 @@ bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
const bool cached_estimate_available = network_quality_store_->GetById(
current_network_id_, &cached_network_quality);
- UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable",
- cached_estimate_available);
- if (!cached_estimate_available)
+ if (!cached_estimate_available) {
return false;
+ }
EffectiveConnectionType effective_connection_type =
cached_network_quality.effective_connection_type();
@@ -1195,10 +1113,6 @@ void NetworkQualityEstimator::AddAndNotifyObserversOfThroughput(
++new_throughput_observations_since_last_ect_computation_;
http_downstream_throughput_kbps_observations_.AddObservation(observation);
- LOCAL_HISTOGRAM_ENUMERATION("NQE.Kbps.ObservationSource",
- observation.source(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_MAX);
-
// Maybe recompute the effective connection type since a new throughput
// observation is available.
if (observation.source() !=
@@ -1507,20 +1421,6 @@ void NetworkQualityEstimator::OnPeerToPeerConnectionsCountChange(
if (p2p_connections_count_ == count)
return;
- if (p2p_connections_count_ == 0 && count > 0) {
- DCHECK(!p2p_connections_count_active_timestamp_);
- p2p_connections_count_active_timestamp_ = tick_clock_->NowTicks();
- }
-
- if (p2p_connections_count_ > 0 && count == 0) {
- DCHECK(p2p_connections_count_active_timestamp_);
- base::TimeDelta duration = tick_clock_->NowTicks() -
- p2p_connections_count_active_timestamp_.value();
- LOCAL_HISTOGRAM_CUSTOM_TIMES("NQE.PeerToPeerConnectionsDuration", duration,
- base::Milliseconds(1), base::Hours(1), 50);
- p2p_connections_count_active_timestamp_ = absl::nullopt;
- }
-
p2p_connections_count_ = count;
for (auto& observer : peer_to_peer_type_observer_list_) {
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index 6927a0535..6268c2e33 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -442,13 +442,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// should discard RTT if it is set to the value returned by |InvalidRTT()|.
static const base::TimeDelta InvalidRTT();
- // Records UMA on whether the NetworkID was available or not. Called right
- // after a network change event.
- void RecordNetworkIDAvailability() const;
-
- // Records UMA on main frame requests.
- void RecordMetricsOnMainFrameRequest() const;
-
// Records a downstream throughput observation to the observation buffer if
// a valid observation is available. |downstream_kbps| is the downstream
// throughput in kilobits per second.
@@ -532,11 +525,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// type.
void ClampKbpsBasedOnEct();
- // Earliest timestamp since when there is at least one active peer to peer
- // connection count. Set to current timestamp when |p2p_connections_count_|
- // changes from 0 to 1. Reset to null when |p2p_connections_count_| becomes 0.
- absl::optional<base::TimeTicks> p2p_connections_count_active_timestamp_;
-
// Determines if the requests to local host can be used in estimating the
// network quality. Set to true only for tests.
bool use_localhost_requests_ = false;
@@ -567,15 +555,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
ObservationBuffer
rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_COUNT];
- // Time when the transaction for the last main frame request was started.
- base::TimeTicks last_main_frame_request_;
-
- // Estimated network quality when the transaction for the last main frame
- // request was started.
- nqe::internal::NetworkQuality estimated_quality_at_last_main_frame_;
- EffectiveConnectionType effective_connection_type_at_last_main_frame_ =
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-
// Observer lists for round trip times and throughput measurements.
base::ObserverList<RTTObserver>::Unchecked rtt_observer_list_;
base::ObserverList<ThroughputObserver>::Unchecked throughput_observer_list_;
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 013bdb6bf..2b7948170 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -216,8 +216,6 @@ TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
- histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
- false, 2);
base::TimeDelta rtt;
int32_t kbps;
@@ -270,18 +268,11 @@ TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
"downstream_throughput_kbps"));
// Check UMA histograms.
- histogram_tester.ExpectUniqueSample(
- "NQE.MainFrame.EffectiveConnectionType",
- EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
EXPECT_LE(1u,
histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size());
- EXPECT_LE(1u,
- histogram_tester.GetAllSamples("NQE.Kbps.OnECTComputation").size());
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1);
- histogram_tester.ExpectBucketCount(
- "NQE.Kbps.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1);
std::unique_ptr<URLRequest> request2(
context->CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY,
@@ -289,12 +280,9 @@ TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request2->Start();
test_delegate.RunUntilComplete();
- histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", 2);
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
- false, 3);
histogram_tester.ExpectTotalCount("NQE.RatioMedianRTT.WiFi", 0);
EXPECT_FALSE(estimator.GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP,
@@ -302,16 +290,8 @@ TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
EXPECT_FALSE(
estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
- // Verify that metrics are logged correctly on main-frame requests.
- histogram_tester.ExpectTotalCount("NQE.MainFrame.RTT.Percentile50", 1);
- histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50",
- 0);
- histogram_tester.ExpectTotalCount("NQE.MainFrame.Kbps.Percentile50", 1);
-
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string());
- histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
- false, 4);
EXPECT_FALSE(estimator.GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP,
base::TimeTicks(), &rtt, nullptr));
@@ -324,15 +304,9 @@ TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
request3->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request3->Start();
test_delegate.RunUntilComplete();
- histogram_tester.ExpectBucketCount(
- "NQE.MainFrame.EffectiveConnectionType",
- EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 2);
- histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", 3);
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
- histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false,
- 4);
}
// Tests that the network quality estimator writes and reads network quality
@@ -354,8 +328,6 @@ TEST_F(NetworkQualityEstimatorTest, Caching) {
: "";
estimator.SimulateNetworkChange(connection_type, connection_id);
- histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
- false, 2);
base::TimeDelta rtt;
int32_t kbps;
@@ -402,9 +374,6 @@ TEST_F(NetworkQualityEstimatorTest, Caching) {
base::TimeTicks(), &rtt, nullptr));
EXPECT_FALSE(estimator.GetTransportRTT());
- histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable",
- false, 2);
-
// Add the observers before changing the network type.
TestEffectiveConnectionTypeObserver observer;
estimator.AddEffectiveConnectionTypeObserver(&observer);
@@ -430,10 +399,6 @@ TEST_F(NetworkQualityEstimatorTest, Caching) {
NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 1);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 4);
- histogram_tester.ExpectBucketCount(
- "NQE.Kbps.ObservationSource",
- NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, 1);
-
// Verify the contents of the net log.
EXPECT_LE(
1, estimator.GetEntriesCount(NetLogEventType::NETWORK_QUALITY_CHANGED) -
@@ -452,9 +417,6 @@ TEST_F(NetworkQualityEstimatorTest, Caching) {
NetLogEventType::NETWORK_QUALITY_CHANGED,
"effective_connection_type"));
- histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable",
- true, 1);
- histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 3);
base::RunLoop().RunUntilIdle();
// Verify that the cached network quality was read, and observers were
@@ -481,7 +443,6 @@ TEST_F(NetworkQualityEstimatorTest, CachingDisabled) {
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test");
- histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0);
base::TimeDelta rtt;
int32_t kbps;
@@ -524,8 +485,6 @@ TEST_F(NetworkQualityEstimatorTest, CachingDisabled) {
base::TimeTicks(), &rtt, nullptr));
EXPECT_FALSE(estimator.GetTransportRTT());
- histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0);
-
// Add the observers before changing the network type.
TestRTTObserver rtt_observer;
estimator.AddRTTObserver(&rtt_observer);
@@ -535,7 +494,6 @@ TEST_F(NetworkQualityEstimatorTest, CachingDisabled) {
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
- histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0);
base::RunLoop().RunUntilIdle();
// Verify that the cached network quality was read, and observers were
@@ -560,7 +518,6 @@ TEST_F(NetworkQualityEstimatorTest, QuicObservations) {
NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1);
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, 1);
- histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 2);
// Verify that the QUIC RTT samples are used when computing transport RTT
@@ -582,7 +539,6 @@ TEST_F(NetworkQualityEstimatorTest,
absl::nullopt);
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, 1);
- histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 1);
EXPECT_EQ(base::Milliseconds(10), estimator.GetTransportRTT());
@@ -603,7 +559,6 @@ TEST_F(NetworkQualityEstimatorTest,
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_H2_PINGS,
1);
- histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 1);
EXPECT_EQ(base::Milliseconds(10), estimator.GetTransportRTT());
@@ -731,11 +686,7 @@ TEST_F(NetworkQualityEstimatorTest, DefaultObservations) {
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource",
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM, 1);
- histogram_tester.ExpectBucketCount(
- "NQE.Kbps.ObservationSource",
- NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM, 1);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 2);
- histogram_tester.ExpectTotalCount("NQE.Kbps.ObservationSource", 1);
// Default observations should be added on connection change.
estimator.SimulateNetworkChange(
@@ -746,11 +697,7 @@ TEST_F(NetworkQualityEstimatorTest, DefaultObservations) {
histogram_tester.ExpectBucketCount(
"NQE.RTT.ObservationSource",
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM, 2);
- histogram_tester.ExpectBucketCount(
- "NQE.Kbps.ObservationSource",
- NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM, 2);
histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 4);
- histogram_tester.ExpectTotalCount("NQE.Kbps.ObservationSource", 2);
base::TimeDelta rtt;
int32_t kbps;
@@ -1394,9 +1341,6 @@ TEST_F(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) {
NetLogEventType::NETWORK_QUALITY_CHANGED,
"downstream_throughput_kbps"));
- histogram_tester.ExpectUniqueSample("NQE.MainFrame.EffectiveConnectionType",
- EFFECTIVE_CONNECTION_TYPE_2G, 1);
-
// Next request should not trigger recomputation of effective connection type
// since there has been no change in the clock.
std::unique_ptr<URLRequest> request2(
@@ -1765,12 +1709,6 @@ TEST_F(NetworkQualityEstimatorTest,
request->Start();
test_delegate.RunUntilComplete();
EXPECT_EQ(1U, observer.effective_connection_types().size());
- histogram_tester.ExpectUniqueSample("NQE.MainFrame.EffectiveConnectionType",
- EFFECTIVE_CONNECTION_TYPE_2G, 1);
- EXPECT_LE(1u,
- histogram_tester
- .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation")
- .size());
size_t expected_effective_connection_type_notifications = 1;
EXPECT_EQ(expected_effective_connection_type_notifications,
@@ -1932,11 +1870,6 @@ TEST_F(NetworkQualityEstimatorTest, TestRttThroughputObservers) {
EXPECT_EQ(quic_rtt, estimator.end_to_end_rtt_.value());
EXPECT_LT(
0u, estimator.end_to_end_rtt_observation_count_at_last_ect_computation_);
- const std::vector<base::Bucket> end_to_end_rtt_samples =
- histogram_tester.GetAllSamples("NQE.EndToEndRTT.OnECTComputation");
- EXPECT_FALSE(end_to_end_rtt_samples.empty());
- for (const auto& bucket : end_to_end_rtt_samples)
- EXPECT_EQ(quic_rtt.InMilliseconds(), bucket.min);
}
TEST_F(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) {
@@ -2087,32 +2020,11 @@ TEST_F(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- // Verify that metrics are logged correctly on main-frame requests.
- histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50",
- num_requests);
-
- histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType",
- num_requests);
- histogram_tester.ExpectBucketCount("NQE.MainFrame.EffectiveConnectionType",
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 0);
ExpectBucketCountAtLeast(&histogram_tester, "NQE.RTT.ObservationSource",
NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1);
- ExpectBucketCountAtLeast(&histogram_tester, "NQE.Kbps.ObservationSource",
- NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1);
- EXPECT_LE(1u,
- histogram_tester
- .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation")
- .size());
- EXPECT_LE(1u,
- histogram_tester.GetAllSamples("NQE.TransportRTT.OnECTComputation")
- .size());
EXPECT_LE(1u,
histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size());
- histogram_tester.ExpectBucketCount(
- "NQE.Kbps.ObservationSource",
- NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 0);
-
estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
histogram_tester.ExpectBucketCount(
@@ -2126,44 +2038,6 @@ TEST_F(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 2);
}
-TEST_F(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) {
- TestNetworkQualityEstimator estimator;
-
- // Create the histogram tester after |estimator| is constructed. This ensures
- // that any network checks done at the time of |estimator| construction do not
- // affect |histogram_tester|.
- base::HistogramTester histogram_tester;
-
- // The NetworkID is recorded as available on Wi-Fi connection.
- estimator.SimulateNetworkChange(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- histogram_tester.ExpectUniqueSample("NQE.NetworkIdAvailable", 1, 1);
-
- // The histogram is not recorded on an unknown connection.
- estimator.SimulateNetworkChange(
- NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "");
- histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 1);
-
- // The NetworkID is recorded as not being available on a Wi-Fi connection
- // with an empty SSID.
- estimator.SimulateNetworkChange(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "");
- histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 0, 1);
- histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 2);
-
- // The NetworkID is recorded as being available on a Wi-Fi connection.
- estimator.SimulateNetworkChange(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 2);
- histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 3);
-
- // The NetworkID is recorded as being available on a cellular connection.
- estimator.SimulateNetworkChange(
- NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1");
- histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 3);
- histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 4);
-}
-
class TestNetworkQualitiesCacheObserver
: public nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver {
public:
@@ -2893,29 +2767,6 @@ TEST_F(NetworkQualityEstimatorTest, HangingRequestUsingTransportAndHttpOnly) {
}
}
-TEST_F(NetworkQualityEstimatorTest, PeerToPeerConnectionCounts) {
- base::SimpleTestTickClock tick_clock;
- TestNetworkQualityEstimator estimator;
- estimator.SetTickClockForTesting(&tick_clock);
- estimator.OnPeerToPeerConnectionsCountChange(3u);
-
- base::TimeDelta advance_1 = base::Minutes(4);
- tick_clock.Advance(advance_1);
-
- base::HistogramTester histogram_tester;
- histogram_tester.ExpectTotalCount("NQE.PeerToPeerConnectionsDuration", 0);
-
- estimator.OnPeerToPeerConnectionsCountChange(1u);
- base::TimeDelta advance_2 = base::Minutes(6);
- tick_clock.Advance(advance_2);
- histogram_tester.ExpectTotalCount("NQE.PeerToPeerConnectionsDuration", 0);
-
- estimator.OnPeerToPeerConnectionsCountChange(0u);
- histogram_tester.ExpectUniqueSample("NQE.PeerToPeerConnectionsDuration",
- (advance_1 + advance_2).InMilliseconds(),
- 1);
-}
-
TEST_F(NetworkQualityEstimatorTest, TestPeerToPeerConnectionsCountObserver) {
TestPeerToPeerConnectionsCountObserver observer;
TestNetworkQualityEstimator estimator;
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index c646c5d2f..c6973e29c 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -433,6 +433,21 @@ base::StringPiece QuicHttpStream::GetAcceptChViaAlps() const {
return session()->GetAcceptChViaAlps(url::SchemeHostPort(request_info_->url));
}
+absl::optional<quic::QuicErrorCode> QuicHttpStream::GetQuicErrorCode() const {
+ if (stream_) {
+ return stream_->connection_error();
+ }
+ return connection_error_;
+}
+
+absl::optional<quic::QuicRstStreamErrorCode>
+QuicHttpStream::GetQuicRstStreamErrorCode() const {
+ if (stream_) {
+ return stream_->stream_error();
+ }
+ return stream_error_;
+}
+
void QuicHttpStream::ReadTrailingHeaders() {
int rv = stream_->ReadTrailingHeaders(
&trailing_header_block_,
@@ -762,6 +777,8 @@ void QuicHttpStream::ResetStream() {
closed_stream_received_bytes_ = stream_->NumBytesConsumed();
closed_stream_sent_bytes_ = stream_->stream_bytes_written();
closed_is_first_stream_ = stream_->IsFirstStream();
+ connection_error_ = stream_->connection_error();
+ stream_error_ = stream_->stream_error();
}
int QuicHttpStream::MapStreamError(int rv) {
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index 812bc4e24..5b6872efd 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -76,6 +76,9 @@ class NET_EXPORT_PRIVATE QuicHttpStream : public MultiplexedHttpStream {
void SetRequestIdempotency(Idempotency idempotency) override;
const std::set<std::string>& GetDnsAliases() const override;
base::StringPiece GetAcceptChViaAlps() const override;
+ absl::optional<quic::QuicErrorCode> GetQuicErrorCode() const override;
+ absl::optional<quic::QuicRstStreamErrorCode> GetQuicRstStreamErrorCode()
+ const override;
static HttpResponseInfo::ConnectionInfo ConnectionInfoFromQuicVersion(
quic::ParsedQuicVersion quic_version);
@@ -205,6 +208,9 @@ class NET_EXPORT_PRIVATE QuicHttpStream : public MultiplexedHttpStream {
// the default value of false.
bool closed_is_first_stream_ = false;
+ absl::optional<quic::QuicErrorCode> connection_error_;
+ absl::optional<quic::QuicRstStreamErrorCode> stream_error_;
+
// The caller's callback to be used for asynchronous operations.
CompletionOnceCallback callback_;
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 4989bf000..0f1192063 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -238,18 +238,6 @@ RSAKeyUsage CheckRSAKeyUsage(const X509Certificate* cert,
: RSAKeyUsage::kMissingDigitalSignature;
}
-// IsCECPQ2Host returns true if the given host is eligible for CECPQ2. This is
-// used to implement a gradual rollout as the larger TLS messages may cause
-// middlebox issues.
-bool IsCECPQ2Host(const std::string& host) {
- // Currently only eTLD+1s that start with "aa" are included, for example
- // aardvark.com or aaron.com.
- return registry_controlled_domains::GetDomainAndRegistry(
- host, registry_controlled_domains::PrivateRegistryFilter::
- EXCLUDE_PRIVATE_REGISTRIES)
- .find(features::kPostQuantumCECPQ2Prefix.Get()) == 0;
-}
-
bool HostIsIPAddressNoBrackets(base::StringPiece host) {
// Note this cannot directly call url::HostIsIPAddress, because that function
// expects bracketed IPv6 literals. By the time hosts reach SSLClientSocket,
@@ -758,20 +746,10 @@ int SSLClientSocketImpl::Init() {
return ERR_UNEXPECTED;
}
- if (base::FeatureList::IsEnabled(features::kPostQuantumKyber)) {
+ if (context_->config().post_quantum_enabled &&
+ base::FeatureList::IsEnabled(features::kPostQuantumKyber)) {
static const int kCurves[] = {NID_X25519Kyber768, NID_X25519,
- NID_P256Kyber768, NID_X9_62_prime256v1,
- NID_secp384r1};
- if (!SSL_set1_curves(ssl_.get(), kCurves, std::size(kCurves))) {
- return ERR_UNEXPECTED;
- }
- } else if (context_->config().cecpq2_enabled &&
- (base::FeatureList::IsEnabled(features::kPostQuantumCECPQ2) ||
- (!host_is_ip_address &&
- base::FeatureList::IsEnabled(features::kPostQuantumCECPQ2SomeDomains) &&
- IsCECPQ2Host(host_and_port_.host())))) {
- static const int kCurves[] = {NID_CECPQ2, NID_X25519, NID_X9_62_prime256v1,
- NID_secp384r1};
+ NID_X9_62_prime256v1, NID_secp384r1};
if (!SSL_set1_curves(ssl_.get(), kCurves, std::size(kCurves))) {
return ERR_UNEXPECTED;
}
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc
index ebdb5129f..d7fe60ca6 100644
--- a/net/socket/udp_socket_posix.cc
+++ b/net/socket/udp_socket_posix.cc
@@ -1063,6 +1063,14 @@ int UDPSocketPosix::SetDiffServCodePoint(DiffServCodePoint dscp) {
return OK;
}
+int UDPSocketPosix::SetIPv6Only(bool ipv6_only) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (is_connected()) {
+ return ERR_SOCKET_IS_CONNECTED;
+ }
+ return net::SetIPv6Only(socket_, ipv6_only);
+}
+
void UDPSocketPosix::DetachFromThread() {
DETACH_FROM_THREAD(thread_checker_);
}
diff --git a/net/socket/udp_socket_posix.h b/net/socket/udp_socket_posix.h
index 59eb51499..ed9c7549c 100644
--- a/net/socket/udp_socket_posix.h
+++ b/net/socket/udp_socket_posix.h
@@ -251,6 +251,10 @@ class NET_EXPORT UDPSocketPosix {
// Returns a net error code.
int SetDiffServCodePoint(DiffServCodePoint dscp);
+ // Sets IPV6_V6ONLY on the socket. If this flag is true, the socket will be
+ // restricted to only IPv6; false allows both IPv4 and IPv6 traffic.
+ int SetIPv6Only(bool ipv6_only);
+
// Exposes the underlying socket descriptor for testing its state. Does not
// release ownership of the descriptor.
SocketDescriptor SocketDescriptorForTesting() const { return socket_; }
diff --git a/net/socket/udp_socket_win.cc b/net/socket/udp_socket_win.cc
index 3e52f8c30..dfc234f5d 100644
--- a/net/socket/udp_socket_win.cc
+++ b/net/socket/udp_socket_win.cc
@@ -1185,6 +1185,14 @@ int UDPSocketWin::SetDiffServCodePoint(DiffServCodePoint dscp) {
return OK;
}
+int UDPSocketWin::SetIPv6Only(bool ipv6_only) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (is_connected()) {
+ return ERR_SOCKET_IS_CONNECTED;
+ }
+ return net::SetIPv6Only(socket_, ipv6_only);
+}
+
void UDPSocketWin::DetachFromThread() {
DETACH_FROM_THREAD(thread_checker_);
}
diff --git a/net/socket/udp_socket_win.h b/net/socket/udp_socket_win.h
index 421de9df4..857613564 100644
--- a/net/socket/udp_socket_win.h
+++ b/net/socket/udp_socket_win.h
@@ -334,11 +334,15 @@ class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate {
int SetMulticastLoopbackMode(bool loopback);
// Sets the differentiated services flags on outgoing packets. May not do
- // anything on some platforms. A return value of ERR_INVALID_HANDLE indicates
+ // anything on some platforms. A return value of ERR_INVALID_HANDLE indicates
// the value was not set but could succeed on a future call, because
// initialization is in progress.
int SetDiffServCodePoint(DiffServCodePoint dscp);
+ // Sets IPV6_V6ONLY on the socket. If this flag is true, the socket will be
+ // restricted to only IPv6; false allows both IPv4 and IPv6 traffic.
+ int SetIPv6Only(bool ipv6_only);
+
// Resets the thread to be used for thread-safety checks.
void DetachFromThread();
diff --git a/net/ssl/ssl_config_service.cc b/net/ssl/ssl_config_service.cc
index 1570edecf..0bb171c02 100644
--- a/net/ssl/ssl_config_service.cc
+++ b/net/ssl/ssl_config_service.cc
@@ -19,11 +19,11 @@ namespace {
bool SSLContextConfigsAreEqual(const net::SSLContextConfig& config1,
const net::SSLContextConfig& config2) {
return std::tie(config1.version_min, config1.version_max,
- config1.disabled_cipher_suites, config1.cecpq2_enabled,
- config1.ech_enabled, config1.insecure_hash_enabled) ==
+ config1.disabled_cipher_suites, config1.post_quantum_enabled,
+ config1.ech_enabled, config1.insecure_hash_override) ==
std::tie(config2.version_min, config2.version_max,
- config2.disabled_cipher_suites, config2.cecpq2_enabled,
- config2.ech_enabled, config2.insecure_hash_enabled);
+ config2.disabled_cipher_suites, config2.post_quantum_enabled,
+ config2.ech_enabled, config2.insecure_hash_override);
}
} // namespace
@@ -42,15 +42,8 @@ bool SSLContextConfig::EncryptedClientHelloEnabled() const {
}
bool SSLContextConfig::InsecureHashesInTLSHandshakesEnabled() const {
- switch (insecure_hash_enabled) {
- case insecure_hash_enabled_value::kUnset:
- return base::FeatureList::IsEnabled(features::kSHA1ServerSignature);
- case insecure_hash_enabled_value::kEnabled:
- return true;
- case insecure_hash_enabled_value::kDisabled:
- return false;
- }
- NOTREACHED();
+ return insecure_hash_override.value_or(
+ base::FeatureList::IsEnabled(features::kSHA1ServerSignature));
}
SSLConfigService::SSLConfigService()
diff --git a/net/ssl/ssl_config_service.h b/net/ssl/ssl_config_service.h
index 489cb7a34..e7c229d87 100644
--- a/net/ssl/ssl_config_service.h
+++ b/net/ssl/ssl_config_service.h
@@ -10,6 +10,7 @@
#include "base/observer_list.h"
#include "net/base/net_export.h"
#include "net/ssl/ssl_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
@@ -45,23 +46,16 @@ struct NET_EXPORT SSLContextConfig {
std::vector<uint16_t> disabled_cipher_suites;
// If false, disables post-quantum key agreement in TLS connections.
- bool cecpq2_enabled = true;
+ bool post_quantum_enabled = true;
// If false, disables TLS Encrypted ClientHello (ECH). If true, the feature
// may be enabled or disabled, depending on feature flags. If querying whether
// ECH is enabled, use `EncryptedClientHelloEnabled` instead.
bool ech_enabled = true;
- // If kEnabled, allows insecure hashes in TLS handshakes. If kDisabled,
- // disallows insecure hashes in TLS handshakes. If kUnset use hashes
- // determined by feature flags.
- enum class insecure_hash_enabled_value {
- kUnset,
- kEnabled,
- kDisabled,
- };
- insecure_hash_enabled_value insecure_hash_enabled =
- insecure_hash_enabled_value::kUnset;
+ // If specified, controls whether insecure hashes are allowed in TLS
+ // handshakes. If `absl::nullopt`, this is determined by feature flags.
+ absl::optional<bool> insecure_hash_override;
// ADDING MORE HERE? Don't forget to update `SSLContextConfigsAreEqual`.
};
diff --git a/net/test/embedded_test_server/http_request.cc b/net/test/embedded_test_server/http_request.cc
index 4704ab10a..66d7569d1 100644
--- a/net/test/embedded_test_server/http_request.cc
+++ b/net/test/embedded_test_server/http_request.cc
@@ -171,7 +171,8 @@ HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() {
LOG(WARNING) << "Malformed Content-Length header's value.";
}
} else if (http_request_->headers.count("Transfer-Encoding") > 0) {
- if (http_request_->headers["Transfer-Encoding"] == "chunked") {
+ if (base::CompareCaseInsensitiveASCII(
+ http_request_->headers["Transfer-Encoding"], "chunked") == 0) {
http_request_->has_content = true;
chunked_decoder_ = std::make_unique<HttpChunkedDecoder>();
state_ = STATE_CONTENT;
diff --git a/net/third_party/quiche/src/WORKSPACE.bazel b/net/third_party/quiche/src/WORKSPACE.bazel
index 8b8cc6ea9..62e2c6f75 100644
--- a/net/third_party/quiche/src/WORKSPACE.bazel
+++ b/net/third_party/quiche/src/WORKSPACE.bazel
@@ -18,9 +18,9 @@ http_archive(
http_archive(
name = "com_google_absl",
- sha256 = "44634eae586a7158dceedda7d8fd5cec6d1ebae08c83399f75dd9ce76324de40", # Last updated 2022-05-18
- strip_prefix = "abseil-cpp-3e04aade4e7a53aebbbed1a1268117f1f522bfb0",
- urls = ["https://github.com/abseil/abseil-cpp/archive/3e04aade4e7a53aebbbed1a1268117f1f522bfb0.zip"],
+ sha256 = "d33809a982df8705f5220d1acb7cc63650e692a12dc2a8ef3e68b8959a1cee02", # Last updated 2023-04-12
+ strip_prefix = "abseil-cpp-32d314d0f5bb0ca3ff71ece49c71a728c128d43e",
+ urls = ["https://github.com/abseil/abseil-cpp/archive/32d314d0f5bb0ca3ff71ece49c71a728c128d43e.zip"],
)
http_archive(
@@ -62,9 +62,9 @@ http_archive(
http_archive(
name = "com_google_googletest",
- sha256 = "7ee83802222f9392452c57b4757185697a51639b69b64590f2c2188f58618581", # Last updated 2022-05-18
- strip_prefix = "googletest-8d51dc50eb7e7698427fed81b85edad0e032112e",
- urls = ["https://github.com/google/googletest/archive/8d51dc50eb7e7698427fed81b85edad0e032112e.zip"],
+ sha256 = "82808543c49488e712d9bd84c50edf40d692ffdaca552b4b019b8b533d3cf8ef", # Last updated 2023-04-12
+ strip_prefix = "googletest-12a5852e451baabc79c63a86c634912c563d57bc",
+ urls = ["https://github.com/google/googletest/archive/12a5852e451baabc79c63a86c634912c563d57bc.zip"],
)
# Note this must use a commit from the `abseil` branch of the RE2 project.
diff --git a/net/third_party/quiche/src/build/source_list.bzl b/net/third_party/quiche/src/build/source_list.bzl
index 3ef9b8b6b..6501eb8e2 100644
--- a/net/third_party/quiche/src/build/source_list.bzl
+++ b/net/third_party/quiche/src/build/source_list.bzl
@@ -20,6 +20,7 @@ quiche_core_hdrs = [
"balsa/noop_balsa_visitor.h",
"balsa/simple_buffer.h",
"balsa/standard_header_map.h",
+ "common/btree_scheduler.h",
"common/capsule.h",
"common/masque/connect_udp_datagram_payload.h",
"common/platform/api/quiche_bug_tracker.h",
@@ -1024,6 +1025,7 @@ quiche_tests_srcs = [
"balsa/header_properties_test.cc",
"balsa/simple_buffer_test.cc",
"binary_http/binary_http_message_test.cc",
+ "common/btree_scheduler_test.cc",
"common/capsule_test.cc",
"common/masque/connect_udp_datagram_payload_test.cc",
"common/platform/api/quiche_file_utils_test.cc",
@@ -1306,6 +1308,7 @@ fuzzers_hdrs = [
]
fuzzers_srcs = [
+ "common/btree_scheduler_fuzzer.cc",
"common/structured_headers_fuzzer.cc",
"quic/core/crypto/certificate_view_der_fuzzer.cc",
"quic/core/crypto/certificate_view_pem_fuzzer.cc",
diff --git a/net/third_party/quiche/src/build/source_list.gni b/net/third_party/quiche/src/build/source_list.gni
index cd0d0c19f..7d493d23c 100644
--- a/net/third_party/quiche/src/build/source_list.gni
+++ b/net/third_party/quiche/src/build/source_list.gni
@@ -20,6 +20,7 @@ quiche_core_hdrs = [
"src/quiche/balsa/noop_balsa_visitor.h",
"src/quiche/balsa/simple_buffer.h",
"src/quiche/balsa/standard_header_map.h",
+ "src/quiche/common/btree_scheduler.h",
"src/quiche/common/capsule.h",
"src/quiche/common/masque/connect_udp_datagram_payload.h",
"src/quiche/common/platform/api/quiche_bug_tracker.h",
@@ -1024,6 +1025,7 @@ quiche_tests_srcs = [
"src/quiche/balsa/header_properties_test.cc",
"src/quiche/balsa/simple_buffer_test.cc",
"src/quiche/binary_http/binary_http_message_test.cc",
+ "src/quiche/common/btree_scheduler_test.cc",
"src/quiche/common/capsule_test.cc",
"src/quiche/common/masque/connect_udp_datagram_payload_test.cc",
"src/quiche/common/platform/api/quiche_file_utils_test.cc",
@@ -1306,6 +1308,7 @@ fuzzers_hdrs = [
]
fuzzers_srcs = [
+ "src/quiche/common/btree_scheduler_fuzzer.cc",
"src/quiche/common/structured_headers_fuzzer.cc",
"src/quiche/quic/core/crypto/certificate_view_der_fuzzer.cc",
"src/quiche/quic/core/crypto/certificate_view_pem_fuzzer.cc",
diff --git a/net/third_party/quiche/src/build/source_list.json b/net/third_party/quiche/src/build/source_list.json
index 561a1d455..1bd873646 100644
--- a/net/third_party/quiche/src/build/source_list.json
+++ b/net/third_party/quiche/src/build/source_list.json
@@ -19,6 +19,7 @@
"quiche/balsa/noop_balsa_visitor.h",
"quiche/balsa/simple_buffer.h",
"quiche/balsa/standard_header_map.h",
+ "quiche/common/btree_scheduler.h",
"quiche/common/capsule.h",
"quiche/common/masque/connect_udp_datagram_payload.h",
"quiche/common/platform/api/quiche_bug_tracker.h",
@@ -1023,6 +1024,7 @@
"quiche/balsa/header_properties_test.cc",
"quiche/balsa/simple_buffer_test.cc",
"quiche/binary_http/binary_http_message_test.cc",
+ "quiche/common/btree_scheduler_test.cc",
"quiche/common/capsule_test.cc",
"quiche/common/masque/connect_udp_datagram_payload_test.cc",
"quiche/common/platform/api/quiche_file_utils_test.cc",
@@ -1305,6 +1307,7 @@
],
"fuzzers_srcs": [
+ "quiche/common/btree_scheduler_fuzzer.cc",
"quiche/common/structured_headers_fuzzer.cc",
"quiche/quic/core/crypto/certificate_view_der_fuzzer.cc",
"quiche/quic/core/crypto/certificate_view_pem_fuzzer.cc",
diff --git a/net/third_party/quiche/src/quiche/BUILD.bazel b/net/third_party/quiche/src/quiche/BUILD.bazel
index 99e8fc5d7..f63fb060e 100644
--- a/net/third_party/quiche/src/quiche/BUILD.bazel
+++ b/net/third_party/quiche/src/quiche/BUILD.bazel
@@ -345,6 +345,7 @@ test_suite_from_source_list(
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/types:optional",
+ "@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
"@com_google_googleurl//url",
],
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc
index ebe07225f..16dad4f9c 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc
@@ -40,31 +40,21 @@ namespace anonymous_tokens {
namespace internal {
-BN_ULONG TOBN(BN_ULONG hi, BN_ULONG lo) {
- return ((BN_ULONG)(hi) << 32 | (lo));
-}
-
// Approximation of sqrt(2) taken from
// //depot/google3/third_party/openssl/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c;l=997
-const BN_ULONG kBoringSSLRSASqrtTwo[] = {
- TOBN(0x4d7c60a5, 0xe633e3e1), TOBN(0x5fcf8f7b, 0xca3ea33b),
- TOBN(0xc246785e, 0x92957023), TOBN(0xf9acce41, 0x797f2805),
- TOBN(0xfdfe170f, 0xd3b1f780), TOBN(0xd24f4a76, 0x3facb882),
- TOBN(0x18838a2e, 0xaff5f3b2), TOBN(0xc1fcbdde, 0xa2f7dc33),
- TOBN(0xdea06241, 0xf7aa81c2), TOBN(0xf6a1be3f, 0xca221307),
- TOBN(0x332a5e9f, 0x7bda1ebf), TOBN(0x0104dc01, 0xfe32352f),
- TOBN(0xb8cf341b, 0x6f8236c7), TOBN(0x4264dabc, 0xd528b651),
- TOBN(0xf4d3a02c, 0xebc93e0c), TOBN(0x81394ab6, 0xd8fd0efd),
- TOBN(0xeaa4a089, 0x9040ca4a), TOBN(0xf52f120f, 0x836e582e),
- TOBN(0xcb2a6343, 0x31f3c84d), TOBN(0xc6d5a8a3, 0x8bb7e9dc),
- TOBN(0x460abc72, 0x2f7c4e33), TOBN(0xcab1bc91, 0x1688458a),
- TOBN(0x53059c60, 0x11bc337b), TOBN(0xd2202e87, 0x42af1f4e),
- TOBN(0x78048736, 0x3dfa2768), TOBN(0x0f74a85e, 0x439c7b4a),
- TOBN(0xa8b1fe6f, 0xdc83db39), TOBN(0x4afc8304, 0x3ab8a2c3),
- TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484),
+const std::vector<uint32_t> kBoringSSLRSASqrtTwo = {
+ 0x4d7c60a5, 0xe633e3e1, 0x5fcf8f7b, 0xca3ea33b, 0xc246785e, 0x92957023,
+ 0xf9acce41, 0x797f2805, 0xfdfe170f, 0xd3b1f780, 0xd24f4a76, 0x3facb882,
+ 0x18838a2e, 0xaff5f3b2, 0xc1fcbdde, 0xa2f7dc33, 0xdea06241, 0xf7aa81c2,
+ 0xf6a1be3f, 0xca221307, 0x332a5e9f, 0x7bda1ebf, 0x0104dc01, 0xfe32352f,
+ 0xb8cf341b, 0x6f8236c7, 0x4264dabc, 0xd528b651, 0xf4d3a02c, 0xebc93e0c,
+ 0x81394ab6, 0xd8fd0efd, 0xeaa4a089, 0x9040ca4a, 0xf52f120f, 0x836e582e,
+ 0xcb2a6343, 0x31f3c84d, 0xc6d5a8a3, 0x8bb7e9dc, 0x460abc72, 0x2f7c4e33,
+ 0xcab1bc91, 0x1688458a, 0x53059c60, 0x11bc337b, 0xd2202e87, 0x42af1f4e,
+ 0x78048736, 0x3dfa2768, 0x0f74a85e, 0x439c7b4a, 0xa8b1fe6f, 0xdc83db39,
+ 0x4afc8304, 0x3ab8a2c3, 0xed17ac85, 0x83339915, 0x1d6f60ba, 0x893ba84c,
+ 0x597d89b3, 0x754abe9f, 0xb504f333, 0xf9de6484,
};
-const int kBoringSSLRSASqrtTwoLen = 32;
absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataHashWithHKDF(
absl::string_view public_metadata, absl::string_view rsa_modulus_str,
@@ -224,13 +214,24 @@ absl::StatusOr<const EVP_MD*> ProtoMaskGenFunctionToEVPDigest(
absl::StatusOr<bssl::UniquePtr<BIGNUM>> GetRsaSqrtTwo(int x) {
// Compute hard-coded sqrt(2).
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> sqrt2, NewBigNum());
- for (int i = internal::kBoringSSLRSASqrtTwoLen - 1; i >= 0; --i) {
+ // TODO(b/277606961): simplify RsaSqrtTwo initialization logic
+ for (int i = internal::kBoringSSLRSASqrtTwo.size() - 2; i >= 0; i = i - 2) {
+ // Add the uint32_t values as words directly and shift.
+ // 'i' is the "hi" value of a uint64_t, and 'i+1' is the "lo" value.
if (BN_add_word(sqrt2.get(), internal::kBoringSSLRSASqrtTwo[i]) != 1) {
return absl::InternalError(absl::StrCat(
"Cannot add word to compute RSA sqrt(2): ", GetSslErrors()));
}
+ if (BN_lshift(sqrt2.get(), sqrt2.get(), 32) != 1) {
+ return absl::InternalError(absl::StrCat(
+ "Cannot shift to compute RSA sqrt(2): ", GetSslErrors()));
+ }
+ if (BN_add_word(sqrt2.get(), internal::kBoringSSLRSASqrtTwo[i+1]) != 1) {
+ return absl::InternalError(absl::StrCat(
+ "Cannot add word to compute RSA sqrt(2): ", GetSslErrors()));
+ }
if (i > 0) {
- if (BN_lshift(sqrt2.get(), sqrt2.get(), 64) != 1) {
+ if (BN_lshift(sqrt2.get(), sqrt2.get(), 32) != 1) {
return absl::InternalError(absl::StrCat(
"Cannot shift to compute RSA sqrt(2): ", GetSslErrors()));
}
@@ -238,7 +239,7 @@ absl::StatusOr<bssl::UniquePtr<BIGNUM>> GetRsaSqrtTwo(int x) {
}
// Check that hard-coded result is correct length.
- int sqrt2_bits = 64 * internal::kBoringSSLRSASqrtTwoLen;
+ int sqrt2_bits = 32 * internal::kBoringSSLRSASqrtTwo.size();
if (BN_num_bits(sqrt2.get()) != sqrt2_bits) {
return absl::InternalError("RSA sqrt(2) is not correct length.");
}
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h
index 60fa56575..c1abec14a 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h
@@ -60,7 +60,7 @@ class QUICHE_EXPORT RsaBlindSigner : public BlindSigner {
absl::StatusOr<std::string> SignInternal(absl::string_view input) const;
- const std::optional<absl::string_view> public_metadata_;
+ const std::optional<std::string> public_metadata_;
// We only keep these for the case when we use RSA blind signatures with
// public metadata. Specifically augmented_rsa_e_ and augmented_rsa_d_ is
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h
index 5663c7937..519fbc2eb 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h
@@ -68,7 +68,7 @@ class QUICHE_EXPORT RsaBlinder : public Blinder {
bssl::UniquePtr<BN_MONT_CTX> mont_n);
const int salt_length_;
- std::optional<absl::string_view> public_metadata_;
+ std::optional<std::string> public_metadata_;
const EVP_MD* sig_hash_; // Owned by BoringSSL.
const EVP_MD* mgf1_hash_; // Owned by BoringSSL.
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_ssa_pss_verifier.h b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_ssa_pss_verifier.h
index e97fed859..569abe895 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_ssa_pss_verifier.h
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_ssa_pss_verifier.h
@@ -59,7 +59,7 @@ class QUICHE_EXPORT RsaSsaPssVerifier : public Verifier {
bssl::UniquePtr<BIGNUM> augmented_rsa_e);
const int salt_length_;
- std::optional<absl::string_view> public_metadata_;
+ std::optional<std::string> public_metadata_;
const EVP_MD* sig_hash_; // Owned by BoringSSL.
const EVP_MD* mgf1_hash_; // Owned by BoringSSL.
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/testing/utils.cc b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/testing/utils.cc
index 8f8afaf2a..75a12eda6 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/testing/utils.cc
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/anonymous_tokens/cpp/testing/utils.cc
@@ -17,6 +17,7 @@
#include <stdint.h>
#include <fstream>
+#include <ios>
#include <memory>
#include <random>
#include <sstream>
@@ -43,21 +44,22 @@ namespace anonymous_tokens {
namespace {
absl::StatusOr<std::string> ReadFileToString(absl::string_view path) {
- std::ifstream file((std::string(path)));
+ std::ifstream file(std::string(path), std::ios::binary);
if (!file.is_open()) {
return absl::InternalError("Reading file failed.");
}
- std::ostringstream ss;
+ std::ostringstream ss(std::ios::binary);
ss << file.rdbuf();
return ss.str();
}
absl::StatusOr<std::pair<RSAPublicKey, RSAPrivateKey>> ParseRsaKeysFromFile(
absl::string_view path) {
- ANON_TOKENS_ASSIGN_OR_RETURN(std::string text_proto, ReadFileToString(path));
+ ANON_TOKENS_ASSIGN_OR_RETURN(std::string binary_proto,
+ ReadFileToString(path));
RSAPrivateKey private_key;
- if (!private_key.ParseFromString(text_proto)) {
- return absl::InternalError("Parsing text proto failed.");
+ if (!private_key.ParseFromString(binary_proto)) {
+ return absl::InternalError("Parsing binary proto failed.");
}
RSAPublicKey public_key;
public_key.set_n(private_key.n());
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth.cc b/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth.cc
index aa6e5b259..ed7cbd099 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth.cc
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth.cc
@@ -45,7 +45,7 @@ void BlindSignAuth::GetTokens(
request.set_use_attestation(false);
request.set_service_type("chromeipblinding");
request.set_location_granularity(
- privacy::ppn::GetInitialDataRequest_LocationGranularity_UNKNOWN);
+ privacy::ppn::GetInitialDataRequest_LocationGranularity_CITY_GEOS);
// Call GetInitialData on the HttpFetcher.
std::string path_and_query = "/v1/getInitialData";
@@ -276,13 +276,16 @@ absl::Status BlindSignAuth::FingerprintPublicMetadata(
uint32_t digest_length = 0;
// Concatenate fields in tag number order, omitting fields whose values match
// the default. This enables new fields to be added without changing the
- // resulting encoding.
- const std::string input = absl::StrCat( //
- metadata.exit_location().country(), //
- metadata.exit_location().city_geo_id(), //
- metadata.service_type(), //
- OmitDefault(metadata.expiration().seconds()), //
- OmitDefault(metadata.expiration().nanos()));
+ // resulting encoding. The signer needs to ensure that | is not allowed in any
+ // metadata value so intentional collisions cannot be created.
+ const std::vector<std::string> parts = {
+ metadata.exit_location().country(),
+ metadata.exit_location().city_geo_id(),
+ metadata.service_type(),
+ OmitDefault(metadata.expiration().seconds()),
+ OmitDefault(metadata.expiration().nanos()),
+ };
+ const std::string input = absl::StrJoin(parts, "|");
if (EVP_Digest(input.data(), input.length(),
reinterpret_cast<uint8_t*>(&digest[0]), &digest_length, hasher,
nullptr) != 1) {
diff --git a/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth_test.cc b/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth_test.cc
index 1e2270eb4..5f0dc1ec7 100644
--- a/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth_test.cc
+++ b/net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_auth_test.cc
@@ -56,7 +56,7 @@ class BlindSignAuthTest : public QuicheTest {
expected_get_initial_data_request_.set_use_attestation(false);
expected_get_initial_data_request_.set_service_type("chromeipblinding");
expected_get_initial_data_request_.set_location_granularity(
- privacy::ppn::GetInitialDataRequest_LocationGranularity_UNKNOWN);
+ privacy::ppn::GetInitialDataRequest_LocationGranularity_CITY_GEOS);
// Create fake public key response.
privacy::ppn::GetInitialDataResponse fake_get_initial_data_response;
diff --git a/net/third_party/quiche/src/quiche/common/btree_scheduler.h b/net/third_party/quiche/src/quiche/common/btree_scheduler.h
new file mode 100644
index 000000000..fd07d36a3
--- /dev/null
+++ b/net/third_party/quiche/src/quiche/common/btree_scheduler.h
@@ -0,0 +1,297 @@
+// Copyright 2023 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.
+
+#ifndef QUICHE_COMMON_BTREE_SCHEDULER_H_
+#define QUICHE_COMMON_BTREE_SCHEDULER_H_
+
+#include <limits>
+
+#include "absl/container/btree_map.h"
+#include "absl/container/node_hash_map.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/types/optional.h"
+#include "quiche/common/platform/api/quiche_bug_tracker.h"
+#include "quiche/common/platform/api/quiche_export.h"
+
+namespace quiche {
+
+// BTreeScheduler is a data structure that allows streams (and potentially other
+// entities) to be scheduled according to the arbitrary priorities. The API for
+// using the scheduler can be used as follows:
+// - A stream has to be registered with a priority before being scheduled.
+// - A stream can be unregistered, or can be re-prioritized.
+// - A stream can be scheduled; that adds it into the queue.
+// - PopFront() will return the stream with highest priority.
+// - ShouldYield() will return if there is a stream with higher priority than
+// the specified one.
+//
+// The prioritization works as following:
+// - If two streams have different priorities, the higher priority stream goes
+// first.
+// - If two streams have the same priority, the one that got scheduled earlier
+// goes first. Internally, this is implemented by assigning a monotonically
+// decreasing sequence number to every newly scheduled stream.
+//
+// The Id type has to define operator==, be hashable via absl::Hash, and
+// printable via operator<<; the Priority type has to define operator<.
+template <typename Id, typename Priority>
+class QUICHE_EXPORT BTreeScheduler {
+ public:
+ // Returns true if there are any streams scheduled.
+ bool HasScheduled() const { return !schedule_.empty(); }
+ // Returns the number of currently scheduled streams.
+ size_t NumScheduled() const { return schedule_.size(); }
+
+ // Counts the number of scheduled entries in the range [min, max]. If either
+ // min or max is omitted, negative or positive infinity is assumed.
+ size_t NumScheduledInPriorityRange(absl::optional<Priority> min,
+ absl::optional<Priority> max) const;
+
+ // Returns true if there is a stream that would go before `id` in the
+ // schedule.
+ absl::StatusOr<bool> ShouldYield(Id id) const;
+
+ // Returns the priority for `id`, or nullopt if stream is not registered.
+ absl::optional<Priority> GetPriorityFor(Id id) const {
+ auto it = streams_.find(id);
+ if (it == streams_.end()) {
+ return absl::nullopt;
+ }
+ return it->second.priority;
+ }
+
+ // Pops the highest priority stream. Will fail if the schedule is empty.
+ absl::StatusOr<Id> PopFront();
+
+ // Registers the specified stream with the supplied priority. The stream must
+ // not be already registered.
+ absl::Status Register(Id stream_id, const Priority& priority);
+ // Unregisters a previously registered stream.
+ absl::Status Unregister(Id stream_id);
+ // Alters the priority of an already registered stream.
+ absl::Status UpdatePriority(Id stream_id, const Priority& new_priority);
+
+ // Adds the `stream` into the schedule if it's not already there.
+ absl::Status Schedule(Id stream_id);
+ // Returns true if `stream` is in the schedule.
+ bool IsScheduled(Id stream_id) const;
+
+ private:
+ // A record for a registered stream.
+ struct StreamEntry {
+ // The current priority of the stream.
+ Priority priority;
+ // If present, the sequence number with which the stream is currently
+ // scheduled. If absent, indicates that the stream is not scheduled.
+ absl::optional<int> current_sequence_number;
+
+ bool scheduled() const { return current_sequence_number.has_value(); }
+ };
+ // The full entry for the stream (includes the ID that's used as a hashmap
+ // key).
+ using FullStreamEntry = std::pair<const Id, StreamEntry>;
+
+ // A key that is used to order entities within the schedule.
+ struct ScheduleKey {
+ // The main order key: the priority of the stream.
+ Priority priority;
+ // The secondary order key: the sequence number.
+ int sequence_number;
+
+ // Orders schedule keys in order of decreasing priority.
+ bool operator<(const ScheduleKey& other) const {
+ return std::make_tuple(priority, sequence_number) >
+ std::make_tuple(other.priority, other.sequence_number);
+ }
+
+ // In order to find all entities with priority `p`, one can iterate between
+ // `lower_bound(MinForPriority(p))` and `upper_bound(MaxForPriority(p))`.
+ static ScheduleKey MinForPriority(Priority priority) {
+ return ScheduleKey{priority, std::numeric_limits<int>::max()};
+ }
+ static ScheduleKey MaxForPriority(Priority priority) {
+ return ScheduleKey{priority, std::numeric_limits<int>::min()};
+ }
+ };
+ using FullScheduleEntry = std::pair<const ScheduleKey, FullStreamEntry*>;
+ using ScheduleIterator =
+ typename absl::btree_map<ScheduleKey, FullStreamEntry*>::const_iterator;
+
+ // Convenience method to get the stream ID for a schedule entry.
+ static Id StreamId(const FullScheduleEntry& entry) {
+ return entry.second->first;
+ }
+
+ // Removes a stream from the schedule, and returns the old entry if it were
+ // present.
+ absl::StatusOr<FullScheduleEntry> DescheduleStream(const StreamEntry& entry);
+
+ // The map of currently registered streams.
+ absl::node_hash_map<Id, StreamEntry> streams_;
+ // The stream schedule, ordered starting from the highest priority stream.
+ absl::btree_map<ScheduleKey, FullStreamEntry*> schedule_;
+
+ // The counter that is used to ensure that streams with the same priority are
+ // handled in the FIFO order. Decreases with every write.
+ int current_write_sequence_number_ = 0;
+};
+
+template <typename Id, typename Priority>
+size_t BTreeScheduler<Id, Priority>::NumScheduledInPriorityRange(
+ absl::optional<Priority> min, absl::optional<Priority> max) const {
+ if (min.has_value() && max.has_value()) {
+ QUICHE_DCHECK(*min <= *max);
+ }
+ // This is reversed, since the schedule is ordered in the descending priority
+ // order.
+ ScheduleIterator begin =
+ max.has_value() ? schedule_.lower_bound(ScheduleKey::MinForPriority(*max))
+ : schedule_.begin();
+ ScheduleIterator end =
+ min.has_value() ? schedule_.upper_bound(ScheduleKey::MaxForPriority(*min))
+ : schedule_.end();
+ return end - begin;
+}
+
+template <typename Id, typename Priority>
+absl::Status BTreeScheduler<Id, Priority>::Register(Id stream_id,
+ const Priority& priority) {
+ auto [it, success] = streams_.insert({stream_id, StreamEntry{priority}});
+ if (!success) {
+ return absl::AlreadyExistsError("ID already registered");
+ }
+ return absl::OkStatus();
+}
+
+template <typename Id, typename Priority>
+auto BTreeScheduler<Id, Priority>::DescheduleStream(const StreamEntry& entry)
+ -> absl::StatusOr<FullScheduleEntry> {
+ QUICHE_DCHECK(entry.scheduled());
+ auto it = schedule_.find(
+ ScheduleKey{entry.priority, *entry.current_sequence_number});
+ if (it == schedule_.end()) {
+ return absl::InternalError(
+ "Calling DescheduleStream() on an entry that is not in the schedule at "
+ "the expected key.");
+ }
+ FullScheduleEntry result = *it;
+ schedule_.erase(it);
+ return result;
+}
+
+template <typename Id, typename Priority>
+absl::Status BTreeScheduler<Id, Priority>::Unregister(Id stream_id) {
+ auto it = streams_.find(stream_id);
+ if (it == streams_.end()) {
+ return absl::NotFoundError("Stream not registered");
+ }
+ const StreamEntry& stream = it->second;
+
+ if (stream.scheduled()) {
+ if (!DescheduleStream(stream).ok()) {
+ QUICHE_BUG(BTreeSchedule_Unregister_NotInSchedule)
+ << "UnregisterStream() called on a stream ID " << stream_id
+ << ", which is marked ready, but is not in the schedule";
+ }
+ }
+
+ streams_.erase(it);
+ return absl::OkStatus();
+}
+
+template <typename Id, typename Priority>
+absl::Status BTreeScheduler<Id, Priority>::UpdatePriority(
+ Id stream_id, const Priority& new_priority) {
+ auto it = streams_.find(stream_id);
+ if (it == streams_.end()) {
+ return absl::NotFoundError("ID not registered");
+ }
+
+ StreamEntry& stream = it->second;
+ absl::optional<int> sequence_number;
+ if (stream.scheduled()) {
+ absl::StatusOr<FullScheduleEntry> old_entry = DescheduleStream(stream);
+ if (old_entry.ok()) {
+ sequence_number = old_entry->first.sequence_number;
+ QUICHE_DCHECK_EQ(old_entry->second, &*it);
+ } else {
+ QUICHE_BUG(BTreeScheduler_Update_Not_In_Schedule)
+ << "UpdatePriority() called on a stream ID " << stream_id
+ << ", which is marked ready, but is not in the schedule";
+ }
+ }
+
+ stream.priority = new_priority;
+ if (sequence_number.has_value()) {
+ schedule_.insert({ScheduleKey{stream.priority, *sequence_number}, &*it});
+ }
+ return absl::OkStatus();
+}
+
+template <typename Id, typename Priority>
+absl::StatusOr<bool> BTreeScheduler<Id, Priority>::ShouldYield(
+ Id stream_id) const {
+ const auto stream_it = streams_.find(stream_id);
+ if (stream_it == streams_.end()) {
+ return absl::NotFoundError("ID not registered");
+ }
+ const StreamEntry& stream = stream_it->second;
+
+ if (schedule_.empty()) {
+ return false;
+ }
+ const FullScheduleEntry& next = *schedule_.begin();
+ if (StreamId(next) == stream_id) {
+ return false;
+ }
+ return next.first.priority >= stream.priority;
+}
+
+template <typename Id, typename Priority>
+absl::StatusOr<Id> BTreeScheduler<Id, Priority>::PopFront() {
+ if (schedule_.empty()) {
+ return absl::NotFoundError("No streams scheduled");
+ }
+ auto schedule_it = schedule_.begin();
+ QUICHE_DCHECK(schedule_it->second->second.scheduled());
+ schedule_it->second->second.current_sequence_number = absl::nullopt;
+
+ Id result = StreamId(*schedule_it);
+ schedule_.erase(schedule_it);
+ return result;
+}
+
+template <typename Id, typename Priority>
+absl::Status BTreeScheduler<Id, Priority>::Schedule(Id stream_id) {
+ const auto stream_it = streams_.find(stream_id);
+ if (stream_it == streams_.end()) {
+ return absl::NotFoundError("ID not registered");
+ }
+ if (stream_it->second.scheduled()) {
+ return absl::OkStatus();
+ }
+ auto [schedule_it, success] =
+ schedule_.insert({ScheduleKey{stream_it->second.priority,
+ --current_write_sequence_number_},
+ &*stream_it});
+ QUICHE_BUG_IF(WebTransportWriteBlockedList_AddStream_conflict, !success)
+ << "Conflicting key in scheduler for stream " << stream_id;
+ stream_it->second.current_sequence_number =
+ schedule_it->first.sequence_number;
+ return absl::OkStatus();
+}
+
+template <typename Id, typename Priority>
+bool BTreeScheduler<Id, Priority>::IsScheduled(Id stream_id) const {
+ const auto stream_it = streams_.find(stream_id);
+ if (stream_it == streams_.end()) {
+ return false;
+ }
+ return stream_it->second.scheduled();
+}
+
+} // namespace quiche
+
+#endif // QUICHE_COMMON_BTREE_SCHEDULER_H_
diff --git a/net/third_party/quiche/src/quiche/common/btree_scheduler_fuzzer.cc b/net/third_party/quiche/src/quiche/common/btree_scheduler_fuzzer.cc
new file mode 100644
index 000000000..eb7164554
--- /dev/null
+++ b/net/third_party/quiche/src/quiche/common/btree_scheduler_fuzzer.cc
@@ -0,0 +1,46 @@
+// Copyright 2023 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 "quiche/common/btree_scheduler.h"
+#include "quiche/common/quiche_data_reader.h"
+
+namespace {
+uint8_t ReadUint8(quiche::QuicheDataReader& reader) {
+ uint8_t result;
+ if (!reader.ReadUInt8(&result)) {
+ exit(0);
+ }
+ return result;
+}
+} // namespace
+
+// Simple fuzzer that attempts to drive the scheduler into an invalid state that
+// would cause a QUICHE_BUG or a crash.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data_ptr, size_t size) {
+ quiche::BTreeScheduler<uint8_t, uint8_t> scheduler;
+ quiche::QuicheDataReader reader(reinterpret_cast<const char*>(data_ptr),
+ size);
+ while (!reader.IsDoneReading()) {
+ switch (ReadUint8(reader)) {
+ case 0:
+ (void)scheduler.Register(ReadUint8(reader), ReadUint8(reader));
+ break;
+ case 1:
+ (void)scheduler.Unregister(ReadUint8(reader));
+ break;
+ case 2:
+ (void)scheduler.UpdatePriority(ReadUint8(reader), ReadUint8(reader));
+ break;
+ case 3:
+ (void)scheduler.Schedule(ReadUint8(reader));
+ break;
+ case 4:
+ (void)scheduler.PopFront();
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
diff --git a/net/third_party/quiche/src/quiche/common/btree_scheduler_test.cc b/net/third_party/quiche/src/quiche/common/btree_scheduler_test.cc
new file mode 100644
index 000000000..d3a806c55
--- /dev/null
+++ b/net/third_party/quiche/src/quiche/common/btree_scheduler_test.cc
@@ -0,0 +1,281 @@
+// Copyright 2023 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 "quiche/common/btree_scheduler.h"
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
+#include "quiche/common/platform/api/quiche_test.h"
+#include "quiche/common/test_tools/quiche_test_utils.h"
+
+namespace quiche::test {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Optional;
+
+template <typename Id, typename Priority>
+void ScheduleIds(BTreeScheduler<Id, Priority>& scheduler,
+ absl::Span<const Id> ids) {
+ for (Id id : ids) {
+ QUICHE_EXPECT_OK(scheduler.Schedule(id));
+ }
+}
+
+template <typename Id, typename Priority>
+std::vector<Id> PopAll(BTreeScheduler<Id, Priority>& scheduler) {
+ std::vector<Id> result;
+ result.reserve(scheduler.NumScheduled());
+ for (;;) {
+ absl::StatusOr<Id> id = scheduler.PopFront();
+ if (id.ok()) {
+ result.push_back(*id);
+ } else {
+ EXPECT_THAT(id, StatusIs(absl::StatusCode::kNotFound));
+ break;
+ }
+ }
+ return result;
+}
+
+TEST(BTreeSchedulerTest, SimplePop) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 100));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 101));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 102));
+
+ EXPECT_THAT(scheduler.GetPriorityFor(1), Optional(100));
+ EXPECT_THAT(scheduler.GetPriorityFor(3), Optional(102));
+ EXPECT_EQ(scheduler.GetPriorityFor(5), absl::nullopt);
+
+ EXPECT_EQ(scheduler.NumScheduled(), 0u);
+ EXPECT_FALSE(scheduler.HasScheduled());
+ QUICHE_EXPECT_OK(scheduler.Schedule(1));
+ QUICHE_EXPECT_OK(scheduler.Schedule(2));
+ QUICHE_EXPECT_OK(scheduler.Schedule(3));
+ EXPECT_EQ(scheduler.NumScheduled(), 3u);
+ EXPECT_TRUE(scheduler.HasScheduled());
+
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(3));
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(2));
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(1));
+
+ QUICHE_EXPECT_OK(scheduler.Schedule(2));
+ QUICHE_EXPECT_OK(scheduler.Schedule(1));
+ QUICHE_EXPECT_OK(scheduler.Schedule(3));
+
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(3));
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(2));
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(1));
+
+ QUICHE_EXPECT_OK(scheduler.Schedule(3));
+ QUICHE_EXPECT_OK(scheduler.Schedule(1));
+
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(3));
+ EXPECT_THAT(scheduler.PopFront(), IsOkAndHolds(1));
+}
+
+TEST(BTreeSchedulerTest, FIFO) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 100));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 100));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 100));
+
+ ScheduleIds(scheduler, {2, 1, 3});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(2, 1, 3));
+
+ QUICHE_EXPECT_OK(scheduler.Register(4, 101));
+ QUICHE_EXPECT_OK(scheduler.Register(5, 99));
+
+ ScheduleIds(scheduler, {5, 1, 2, 3, 4});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(4, 1, 2, 3, 5));
+ ScheduleIds(scheduler, {1, 5, 2, 4, 3});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(4, 1, 2, 3, 5));
+ ScheduleIds(scheduler, {3, 5, 2, 4, 1});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(4, 3, 2, 1, 5));
+ ScheduleIds(scheduler, {3, 2, 1, 2, 3});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(3, 2, 1));
+}
+
+TEST(BTreeSchedulerTest, NumEntriesInRange) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(4, -2));
+ QUICHE_EXPECT_OK(scheduler.Register(5, -5));
+ QUICHE_EXPECT_OK(scheduler.Register(6, 10));
+ QUICHE_EXPECT_OK(scheduler.Register(7, 16));
+ QUICHE_EXPECT_OK(scheduler.Register(8, 32));
+ QUICHE_EXPECT_OK(scheduler.Register(9, 64));
+
+ EXPECT_EQ(scheduler.NumScheduled(), 0u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(absl::nullopt, absl::nullopt),
+ 0u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(-1, 1), 0u);
+
+ for (int stream = 1; stream <= 9; ++stream) {
+ QUICHE_ASSERT_OK(scheduler.Schedule(stream));
+ }
+
+ EXPECT_EQ(scheduler.NumScheduled(), 9u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(absl::nullopt, absl::nullopt),
+ 9u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(0, 0), 3u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(absl::nullopt, -1), 2u);
+ EXPECT_EQ(scheduler.NumScheduledInPriorityRange(1, absl::nullopt), 4u);
+}
+
+TEST(BTreeSchedulerTest, Registration) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+
+ QUICHE_EXPECT_OK(scheduler.Schedule(1));
+ QUICHE_EXPECT_OK(scheduler.Schedule(2));
+ EXPECT_EQ(scheduler.NumScheduled(), 2u);
+ EXPECT_TRUE(scheduler.IsScheduled(2));
+
+ EXPECT_THAT(scheduler.Register(2, 0),
+ StatusIs(absl::StatusCode::kAlreadyExists));
+ QUICHE_EXPECT_OK(scheduler.Unregister(2));
+ EXPECT_EQ(scheduler.NumScheduled(), 1u);
+ EXPECT_FALSE(scheduler.IsScheduled(2));
+
+ EXPECT_THAT(scheduler.UpdatePriority(2, 1234),
+ StatusIs(absl::StatusCode::kNotFound));
+ EXPECT_THAT(scheduler.Unregister(2), StatusIs(absl::StatusCode::kNotFound));
+ EXPECT_THAT(scheduler.Schedule(2), StatusIs(absl::StatusCode::kNotFound));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+ EXPECT_EQ(scheduler.NumScheduled(), 1u);
+ EXPECT_TRUE(scheduler.IsScheduled(1));
+ EXPECT_FALSE(scheduler.IsScheduled(2));
+}
+
+TEST(BTreeSchedulerTest, UpdatePriorityUp) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 0));
+
+ ScheduleIds(scheduler, {1, 2, 3});
+ QUICHE_EXPECT_OK(scheduler.UpdatePriority(2, 1000));
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(2, 1, 3));
+}
+
+TEST(BTreeSchedulerTest, UpdatePriorityDown) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 0));
+
+ ScheduleIds(scheduler, {1, 2, 3});
+ QUICHE_EXPECT_OK(scheduler.UpdatePriority(2, -1000));
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(1, 3, 2));
+}
+
+TEST(BTreeSchedulerTest, UpdatePriorityEqual) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 0));
+
+ ScheduleIds(scheduler, {1, 2, 3});
+ QUICHE_EXPECT_OK(scheduler.UpdatePriority(2, 0));
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(1, 2, 3));
+}
+
+TEST(BTreeSchedulerTest, UpdatePriorityIntoSameBucket) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(1, 0));
+ QUICHE_EXPECT_OK(scheduler.Register(2, -100));
+ QUICHE_EXPECT_OK(scheduler.Register(3, 0));
+
+ ScheduleIds(scheduler, {1, 2, 3});
+ QUICHE_EXPECT_OK(scheduler.UpdatePriority(2, 0));
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(1, 2, 3));
+}
+
+TEST(BTreeSchedulerTest, ShouldYield) {
+ BTreeScheduler<int, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(10, 100));
+ QUICHE_EXPECT_OK(scheduler.Register(20, 101));
+ QUICHE_EXPECT_OK(scheduler.Register(21, 101));
+ QUICHE_EXPECT_OK(scheduler.Register(30, 102));
+
+ EXPECT_THAT(scheduler.ShouldYield(10), IsOkAndHolds(false));
+ EXPECT_THAT(scheduler.ShouldYield(20), IsOkAndHolds(false));
+ EXPECT_THAT(scheduler.ShouldYield(21), IsOkAndHolds(false));
+ EXPECT_THAT(scheduler.ShouldYield(30), IsOkAndHolds(false));
+ EXPECT_THAT(scheduler.ShouldYield(40), StatusIs(absl::StatusCode::kNotFound));
+
+ QUICHE_EXPECT_OK(scheduler.Schedule(20));
+
+ EXPECT_THAT(scheduler.ShouldYield(10), IsOkAndHolds(true));
+ EXPECT_THAT(scheduler.ShouldYield(20), IsOkAndHolds(false));
+ EXPECT_THAT(scheduler.ShouldYield(21), IsOkAndHolds(true));
+ EXPECT_THAT(scheduler.ShouldYield(30), IsOkAndHolds(false));
+}
+
+struct CustomPriority {
+ int a;
+ int b;
+
+ bool operator<(const CustomPriority& other) const {
+ return std::make_tuple(a, b) < std::make_tuple(other.a, other.b);
+ }
+};
+
+TEST(BTreeSchedulerTest, CustomPriority) {
+ BTreeScheduler<int, CustomPriority> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(10, CustomPriority{0, 1}));
+ QUICHE_EXPECT_OK(scheduler.Register(11, CustomPriority{0, 0}));
+ QUICHE_EXPECT_OK(scheduler.Register(12, CustomPriority{0, 0}));
+ QUICHE_EXPECT_OK(scheduler.Register(13, CustomPriority{10, 0}));
+ QUICHE_EXPECT_OK(scheduler.Register(14, CustomPriority{-10, 0}));
+
+ ScheduleIds(scheduler, {10, 11, 12, 13, 14});
+ EXPECT_THAT(PopAll(scheduler), ElementsAre(13, 10, 11, 12, 14));
+}
+
+struct CustomId {
+ int a;
+ std::string b;
+
+ bool operator==(const CustomId& other) const {
+ return a == other.a && b == other.b;
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const CustomId& c) {
+ return H::combine(std::move(h), c.a, c.b);
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const CustomId& id) {
+ os << id.a << ":" << id.b;
+ return os;
+}
+
+TEST(BTreeSchedulerTest, CustomIds) {
+ BTreeScheduler<CustomId, int> scheduler;
+ QUICHE_EXPECT_OK(scheduler.Register(CustomId{1, "foo"}, 10));
+ QUICHE_EXPECT_OK(scheduler.Register(CustomId{1, "bar"}, 12));
+ QUICHE_EXPECT_OK(scheduler.Register(CustomId{2, "foo"}, 11));
+ EXPECT_THAT(scheduler.Register(CustomId{1, "foo"}, 10),
+ StatusIs(absl::StatusCode::kAlreadyExists));
+
+ ScheduleIds(scheduler,
+ {CustomId{1, "foo"}, CustomId{1, "bar"}, CustomId{2, "foo"}});
+ EXPECT_THAT(scheduler.ShouldYield(CustomId{1, "foo"}), IsOkAndHolds(true));
+ EXPECT_THAT(scheduler.ShouldYield(CustomId{1, "bar"}), IsOkAndHolds(false));
+ EXPECT_THAT(
+ PopAll(scheduler),
+ ElementsAre(CustomId{1, "bar"}, CustomId{2, "foo"}, CustomId{1, "foo"}));
+}
+
+} // namespace
+} // namespace quiche::test
diff --git a/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.cc b/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.cc
index ecea02403..e55df8a97 100644
--- a/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.cc
@@ -9,8 +9,6 @@
#include "quiche/quic/core/crypto/crypto_framer.h"
#include "quiche/quic/core/crypto/crypto_handshake.h"
#include "quiche/quic/core/crypto/crypto_handshake_message.h"
-#include "quiche/quic/core/crypto/crypto_protocol.h"
-#include "quiche/quic/core/crypto/crypto_utils.h"
#include "quiche/quic/core/crypto/quic_decrypter.h"
#include "quiche/quic/core/crypto/quic_encrypter.h"
#include "quiche/quic/core/frames/quic_ack_frequency_frame.h"
diff --git a/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.h b/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.h
index 48a45f07c..fd83233c9 100644
--- a/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.h
+++ b/net/third_party/quiche/src/quiche/quic/core/chlo_extractor.h
@@ -11,7 +11,7 @@
namespace quic {
// A utility for extracting QUIC Client Hello messages from packets,
-// without needs to spin up a full QuicSession.
+// without needing to spin up a full QuicSession.
class QUIC_NO_EXPORT ChloExtractor {
public:
class QUIC_NO_EXPORT Delegate {
diff --git a/net/third_party/quiche/src/quiche/quic/core/http/end_to_end_test.cc b/net/third_party/quiche/src/quiche/quic/core/http/end_to_end_test.cc
index 4e2e5cfbd..35fe13a12 100644
--- a/net/third_party/quiche/src/quiche/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/http/end_to_end_test.cc
@@ -7182,10 +7182,11 @@ TEST_P(EndToEndTest, OriginalConnectionIdClearedFromMap) {
server_thread_->Resume();
}
-TEST_P(EndToEndTest, EcnMarksReportedCorrectly) {
+TEST_P(EndToEndTest, ServerReportsEcn) {
// Client connects using not-ECT.
ASSERT_TRUE(Initialize());
QuicConnection* client_connection = GetClientConnection();
+ QuicConnectionPeer::DisableEcnCodepointValidation(client_connection);
QuicEcnCounts* ecn = QuicSentPacketManagerPeer::GetPeerEcnCounts(
QuicConnectionPeer::GetSentPacketManager(client_connection),
APPLICATION_DATA);
@@ -7229,6 +7230,37 @@ TEST_P(EndToEndTest, EcnMarksReportedCorrectly) {
client_->Disconnect();
}
+TEST_P(EndToEndTest, ClientReportsEcn) {
+ ASSERT_TRUE(Initialize());
+ // Wait for handshake to complete, so that we can manipulate the server
+ // connection without race conditions.
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+ QuicConnection* server_connection = GetServerConnection();
+ QuicConnectionPeer::DisableEcnCodepointValidation(server_connection);
+ QuicEcnCounts* ecn = QuicSentPacketManagerPeer::GetPeerEcnCounts(
+ QuicConnectionPeer::GetSentPacketManager(server_connection),
+ APPLICATION_DATA);
+ TestPerPacketOptions options;
+ options.ecn_codepoint = ECN_ECT1;
+ server_connection->set_per_packet_options(&options);
+ client_->SendSynchronousRequest("/foo");
+ // A second request provides a packet for the client ACKs to go with.
+ client_->SendSynchronousRequest("/foo");
+ server_thread_->Pause();
+ EXPECT_EQ(ecn->ect0, 0);
+ EXPECT_EQ(ecn->ce, 0);
+ if (!GetQuicRestartFlag(quic_receive_ecn) ||
+ !GetQuicRestartFlag(quic_quiche_ecn_sockets) ||
+ !VersionHasIetfQuicFrames(version_.transport_version)) {
+ EXPECT_EQ(ecn->ect1, 0);
+ } else {
+ EXPECT_GT(ecn->ect1, 0);
+ }
+ server_connection->set_per_packet_options(nullptr);
+ server_thread_->Resume();
+ client_->Disconnect();
+}
+
TEST_P(EndToEndTest, ClientMigrationAfterHalfwayServerMigration) {
use_preferred_address_ = true;
ASSERT_TRUE(Initialize());
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_connection.cc b/net/third_party/quiche/src/quiche/quic/core/quic_connection.cc
index 271f17290..01e728aa7 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_connection.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_connection.cc
@@ -26,7 +26,6 @@
#include "quiche/quic/core/crypto/crypto_utils.h"
#include "quiche/quic/core/crypto/quic_decrypter.h"
#include "quiche/quic/core/crypto/quic_encrypter.h"
-#include "quiche/quic/core/proto/cached_network_parameters_proto.h"
#include "quiche/quic/core/quic_bandwidth.h"
#include "quiche/quic/core/quic_config.h"
#include "quiche/quic/core/quic_connection_id.h"
@@ -44,9 +43,7 @@
#include "quiche/quic/platform/api/quic_exported_stats.h"
#include "quiche/quic/platform/api/quic_flag_utils.h"
#include "quiche/quic/platform/api/quic_flags.h"
-#include "quiche/quic/platform/api/quic_hostname_utils.h"
#include "quiche/quic/platform/api/quic_logging.h"
-#include "quiche/quic/platform/api/quic_server_stats.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
#include "quiche/common/platform/api/quiche_flag_utils.h"
#include "quiche/common/quiche_text_utils.h"
@@ -3115,7 +3112,6 @@ bool QuicConnection::ValidateReceivedPacketNumber(
void QuicConnection::WriteQueuedPackets() {
QUICHE_DCHECK(!writer_->IsWriteBlocked());
-
QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
buffered_packets_.size(), 1, 1000, 50, "");
@@ -3124,7 +3120,7 @@ void QuicConnection::WriteQueuedPackets() {
break;
}
const BufferedPacket& packet = buffered_packets_.front();
- WriteResult result = writer_->WritePacket(
+ WriteResult result = SendPacketToWriter(
packet.data.get(), packet.length, packet.self_address.host(),
packet.peer_address, per_packet_options_);
QUIC_DVLOG(1) << ENDPOINT << "Sending buffered packet, result: " << result;
@@ -3491,9 +3487,9 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
//
// writer_->WritePacket transfers buffer ownership back to the writer.
packet->release_encrypted_buffer = nullptr;
- result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length,
- send_from_address.host(), send_to_address,
- per_packet_options_);
+ result = SendPacketToWriter(packet->encrypted_buffer, encrypted_length,
+ send_from_address.host(), send_to_address,
+ per_packet_options_);
// This is a work around for an issue with linux UDP GSO batch writers.
// When sending a GSO packet with 2 segments, if the first segment is
// larger than the path MTU, instead of EMSGSIZE, the linux kernel returns
@@ -4148,6 +4144,38 @@ bool QuicConnection::IsKnownServerAddress(
address) != known_server_addresses_.cend();
}
+void QuicConnection::ClearEcnCodepoint() {
+ if (per_packet_options_ != nullptr) {
+ per_packet_options_->ecn_codepoint = ECN_NOT_ECT;
+ }
+}
+
+WriteResult QuicConnection::SendPacketToWriter(
+ const char* buffer, size_t buf_len, const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address, PerPacketOptions* options) {
+ if (!disable_ecn_codepoint_validation_) {
+ switch (GetNextEcnCodepoint()) {
+ case ECN_NOT_ECT:
+ break;
+ case ECN_ECT0:
+ if (!sent_packet_manager_.GetSendAlgorithm()->SupportsECT0()) {
+ ClearEcnCodepoint();
+ }
+ break;
+ case ECN_ECT1:
+ if (!sent_packet_manager_.GetSendAlgorithm()->SupportsECT1()) {
+ ClearEcnCodepoint();
+ }
+ break;
+ case ECN_CE:
+ ClearEcnCodepoint();
+ break;
+ }
+ }
+ return writer_->WritePacket(buffer, buf_len, self_address, peer_address,
+ options);
+}
+
void QuicConnection::OnRetransmissionTimeout() {
ScopedRetransmissionTimeoutIndicator indicator(this);
#ifndef NDEBUG
@@ -5966,7 +5994,7 @@ bool QuicConnection::FlushCoalescedPacket() {
buffer, static_cast<QuicPacketLength>(length),
coalesced_packet_.self_address(), coalesced_packet_.peer_address());
} else {
- WriteResult result = writer_->WritePacket(
+ WriteResult result = SendPacketToWriter(
buffer, length, coalesced_packet_.self_address().host(),
coalesced_packet_.peer_address(), per_packet_options_);
if (IsWriteError(result.status)) {
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_connection.h b/net/third_party/quiche/src/quiche/quic/core/quic_connection.h
index 79de6044e..55714ad50 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_connection.h
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_connection.h
@@ -34,7 +34,6 @@
#include "quiche/quic/core/frames/quic_ack_frequency_frame.h"
#include "quiche/quic/core/frames/quic_max_streams_frame.h"
#include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
-#include "quiche/quic/core/proto/cached_network_parameters_proto.h"
#include "quiche/quic/core/quic_alarm.h"
#include "quiche/quic/core/quic_alarm_factory.h"
#include "quiche/quic/core/quic_blocked_writer_interface.h"
@@ -1961,6 +1960,22 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Returns true if |address| is known server address.
bool IsKnownServerAddress(const QuicSocketAddress& address) const;
+ // Retrieves the ECN codepoint to be sent on the next packet.
+ QuicEcnCodepoint GetNextEcnCodepoint() const {
+ return (per_packet_options_ != nullptr) ? per_packet_options_->ecn_codepoint
+ : ECN_NOT_ECT;
+ }
+
+ // Sets the ECN codepoint to Not-ECT.
+ void ClearEcnCodepoint();
+
+ // Writes the packet to the writer and clears the ECN codepoint in |options|
+ // if it is invalid.
+ WriteResult SendPacketToWriter(const char* buffer, size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options);
+
QuicConnectionContext context_;
QuicFramer framer_;
@@ -2357,6 +2372,14 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// original address.
QuicLRUCache<QuicSocketAddress, bool, QuicSocketAddressHash>
received_client_addresses_cache_;
+
+ // Endpoints should never mark packets with Congestion Experienced (CE), as
+ // this is only done by routers. Endpoints cannot send ECT(0) or ECT(1) if
+ // their congestion control cannot respond to these signals in accordance with
+ // the spec, or if the QUIC implementation doesn't validate ECN feedback. When
+ // true, the connection will not verify that the requested codepoint adheres
+ // to these policies. This is only accessible through QuicConnectionPeer.
+ bool disable_ecn_codepoint_validation_ = false;
};
} // namespace quic
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_connection_test.cc b/net/third_party/quiche/src/quiche/quic/core/quic_connection_test.cc
index 27cf7066c..7853992a9 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_connection_test.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_connection_test.cc
@@ -8,9 +8,7 @@
#include <cstdint>
#include <memory>
-#include <ostream>
#include <string>
-#include <type_traits>
#include <utility>
#include "absl/base/macros.h"
@@ -22,7 +20,6 @@
#include "quiche/quic/core/crypto/null_decrypter.h"
#include "quiche/quic/core/crypto/null_encrypter.h"
#include "quiche/quic/core/crypto/quic_decrypter.h"
-#include "quiche/quic/core/crypto/quic_encrypter.h"
#include "quiche/quic/core/frames/quic_connection_close_frame.h"
#include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
#include "quiche/quic/core/frames/quic_path_response_frame.h"
@@ -56,7 +53,6 @@
#include "quiche/quic/test_tools/quic_test_utils.h"
#include "quiche/quic/test_tools/simple_data_producer.h"
#include "quiche/quic/test_tools/simple_session_notifier.h"
-#include "quiche/common/platform/api/quiche_reference_counted.h"
#include "quiche/common/simple_buffer_allocator.h"
using testing::_;
@@ -17465,6 +17461,57 @@ TEST_P(QuicConnectionTest,
EXPECT_EQ(kSelfAddress, connection_.self_address());
}
+TEST_P(QuicConnectionTest, EcnCodepointsRejected) {
+ TestPerPacketOptions per_packet_options;
+ connection_.set_per_packet_options(&per_packet_options);
+ for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
+ per_packet_options.ecn_codepoint = ecn;
+ if (ecn == ECN_ECT0) {
+ EXPECT_CALL(*send_algorithm_, SupportsECT0()).WillOnce(Return(false));
+ } else if (ecn == ECN_ECT1) {
+ EXPECT_CALL(*send_algorithm_, SupportsECT1()).WillOnce(Return(false));
+ }
+ EXPECT_CALL(connection_, OnSerializedPacket(_));
+ SendPing();
+ EXPECT_EQ(per_packet_options.ecn_codepoint, ECN_NOT_ECT);
+ EXPECT_EQ(writer_->last_ecn_sent(), ECN_NOT_ECT);
+ }
+}
+
+TEST_P(QuicConnectionTest, EcnCodepointsAccepted) {
+ TestPerPacketOptions per_packet_options;
+ connection_.set_per_packet_options(&per_packet_options);
+ for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
+ per_packet_options.ecn_codepoint = ecn;
+ if (ecn == ECN_ECT0) {
+ EXPECT_CALL(*send_algorithm_, SupportsECT0()).WillOnce(Return(true));
+ } else if (ecn == ECN_ECT1) {
+ EXPECT_CALL(*send_algorithm_, SupportsECT1()).WillOnce(Return(true));
+ }
+ EXPECT_CALL(connection_, OnSerializedPacket(_));
+ SendPing();
+ QuicEcnCodepoint expected_codepoint = ecn;
+ if (ecn == ECN_CE) {
+ expected_codepoint = ECN_NOT_ECT;
+ }
+ EXPECT_EQ(per_packet_options.ecn_codepoint, expected_codepoint);
+ EXPECT_EQ(writer_->last_ecn_sent(), expected_codepoint);
+ }
+}
+
+TEST_P(QuicConnectionTest, EcnValidationDisabled) {
+ TestPerPacketOptions per_packet_options;
+ connection_.set_per_packet_options(&per_packet_options);
+ QuicConnectionPeer::DisableEcnCodepointValidation(&connection_);
+ for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
+ per_packet_options.ecn_codepoint = ecn;
+ EXPECT_CALL(connection_, OnSerializedPacket(_));
+ SendPing();
+ EXPECT_EQ(per_packet_options.ecn_codepoint, ecn);
+ EXPECT_EQ(writer_->last_ecn_sent(), ecn);
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.cc b/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.cc
index 0f8c1abfe..9b1b470c3 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.cc
@@ -13,7 +13,6 @@
#include "absl/strings/string_view.h"
#include "quiche/quic/core/chlo_extractor.h"
#include "quiche/quic/core/crypto/crypto_protocol.h"
-#include "quiche/quic/core/crypto/quic_random.h"
#include "quiche/quic/core/quic_connection_id.h"
#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_session.h"
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher_test.cc b/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher_test.cc
index 3ed2330a9..12a62bb1d 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher_test.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher_test.cc
@@ -5,18 +5,15 @@
#include "quiche/quic/core/quic_dispatcher.h"
#include <memory>
-#include <ostream>
#include <string>
#include <utility>
#include "absl/base/macros.h"
#include "absl/strings/str_cat.h"
#include "quiche/quic/core/chlo_extractor.h"
-#include "quiche/quic/core/crypto/crypto_handshake.h"
#include "quiche/quic/core/crypto/crypto_protocol.h"
#include "quiche/quic/core/crypto/quic_crypto_server_config.h"
#include "quiche/quic/core/crypto/quic_random.h"
-#include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
#include "quiche/quic/core/quic_config.h"
#include "quiche/quic/core/quic_connection.h"
#include "quiche/quic/core/quic_connection_id.h"
@@ -31,16 +28,13 @@
#include "quiche/quic/platform/api/quic_logging.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/quic/test_tools/crypto_test_utils.h"
-#include "quiche/quic/test_tools/fake_proof_source.h"
#include "quiche/quic/test_tools/first_flight.h"
#include "quiche/quic/test_tools/mock_connection_id_generator.h"
#include "quiche/quic/test_tools/mock_quic_time_wait_list_manager.h"
#include "quiche/quic/test_tools/quic_buffered_packet_store_peer.h"
#include "quiche/quic/test_tools/quic_connection_peer.h"
-#include "quiche/quic/test_tools/quic_crypto_server_config_peer.h"
#include "quiche/quic/test_tools/quic_dispatcher_peer.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
-#include "quiche/quic/test_tools/quic_time_wait_list_manager_peer.h"
#include "quiche/quic/tools/quic_simple_crypto_server_stream_helper.h"
#include "quiche/common/test_tools/quiche_test_utils.h"
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_types.cc b/net/third_party/quiche/src/quiche/quic/core/quic_types.cc
index e0460923d..3981256f6 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_types.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_types.cc
@@ -446,6 +446,20 @@ QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
return os;
}
+std::string EcnCodepointToString(QuicEcnCodepoint ecn) {
+ switch (ecn) {
+ case ECN_NOT_ECT:
+ return "Not-ECT";
+ case ECN_ECT0:
+ return "ECT(0)";
+ case ECN_ECT1:
+ return "ECT(1)";
+ case ECN_CE:
+ return "CE";
+ }
+ return ""; // Handle compilation on windows for invalid enums
+}
+
#undef RETURN_STRING_LITERAL // undef for jumbo builds
} // namespace quic
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_types.h b/net/third_party/quiche/src/quiche/quic/core/quic_types.h
index 6e2531b9b..b2a100b3b 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_types.h
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_types.h
@@ -885,6 +885,8 @@ enum QuicEcnCodepoint {
ECN_CE = 3,
};
+QUICHE_EXPORT std::string EcnCodepointToString(QuicEcnCodepoint ecn);
+
// This struct reports the Explicit Congestion Notification (ECN) contents of
// the ACK_ECN frame. They are the cumulative number of QUIC packets received
// for that codepoint in a given Packet Number Space.
diff --git a/net/third_party/quiche/src/quiche/quic/core/quic_utils_test.cc b/net/third_party/quiche/src/quiche/quic/core/quic_utils_test.cc
index a4a194f5e..543c8ead0 100644
--- a/net/third_party/quiche/src/quiche/quic/core/quic_utils_test.cc
+++ b/net/third_party/quiche/src/quiche/quic/core/quic_utils_test.cc
@@ -233,6 +233,13 @@ TEST_F(QuicUtilsTest, StatelessResetToken) {
EXPECT_FALSE(QuicUtils::AreStatelessResetTokensEqual(token1a, token2));
}
+TEST_F(QuicUtilsTest, EcnCodepointToString) {
+ EXPECT_EQ(EcnCodepointToString(ECN_NOT_ECT), "Not-ECT");
+ EXPECT_EQ(EcnCodepointToString(ECN_ECT0), "ECT(0)");
+ EXPECT_EQ(EcnCodepointToString(ECN_ECT1), "ECT(1)");
+ EXPECT_EQ(EcnCodepointToString(ECN_CE), "CE");
+}
+
enum class TestEnumClassBit : uint8_t {
BIT_ZERO = 0,
BIT_ONE,
diff --git a/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc b/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc
index 637f18f35..83f164843 100644
--- a/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc
+++ b/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc
@@ -72,7 +72,6 @@ MasqueClientSession::GetOrCreateConnectUdpClientState(
auto it = fake_addresses_.find(target_server_address.host().ToPackedString());
if (it != fake_addresses_.end()) {
target_host = it->second;
- fake_addresses_.erase(it);
} else {
target_host = target_server_address.host().ToString();
}
@@ -517,4 +516,9 @@ quiche::QuicheIpAddress MasqueClientSession::GetFakeAddress(
return address;
}
+void MasqueClientSession::RemoveFakeAddress(
+ const quiche::QuicheIpAddress& fake_address) {
+ fake_addresses_.erase(fake_address.ToPackedString());
+}
+
} // namespace quic
diff --git a/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.h b/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.h
index 4b537b28d..4e317eba4 100644
--- a/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.h
+++ b/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.h
@@ -117,9 +117,13 @@ class QUIC_NO_EXPORT MasqueClientSession : public QuicSpdyClientSession {
void CloseConnectIpStream(EncapsulatedIpSession* encapsulated_ip_session);
// Generate a random Unique Local Address and register a mapping from
- // that address to the corresponding hostname.
+ // that address to the corresponding hostname. The returned address should be
+ // removed by calling RemoveFakeAddress() once it is no longer needed.
quiche::QuicheIpAddress GetFakeAddress(absl::string_view hostname);
+ // Removes a fake address that was previously created by GetFakeAddress().
+ void RemoveFakeAddress(const quiche::QuicheIpAddress& fake_address);
+
private:
// State that the MasqueClientSession keeps for each CONNECT-UDP request.
class QUIC_NO_EXPORT ConnectUdpClientState
diff --git a/net/third_party/quiche/src/quiche/quic/masque/masque_client_tools.cc b/net/third_party/quiche/src/quiche/quic/masque/masque_client_tools.cc
index d77e94dc9..841052911 100644
--- a/net/third_party/quiche/src/quiche/quic/masque/masque_client_tools.cc
+++ b/net/third_party/quiche/src/quiche/quic/masque/masque_client_tools.cc
@@ -4,6 +4,7 @@
#include "quiche/quic/masque/masque_client_tools.h"
+#include "absl/types/optional.h"
#include "quiche/quic/masque/masque_encapsulated_client.h"
#include "quiche/quic/masque/masque_utils.h"
#include "quiche/quic/platform/api/quic_default_proof_providers.h"
@@ -15,6 +16,33 @@
namespace quic {
namespace tools {
+namespace {
+
+// Helper class to ensure a fake address gets properly removed when this goes
+// out of scope.
+class FakeAddressRemover {
+ public:
+ FakeAddressRemover() = default;
+ void IngestFakeAddress(const quiche::QuicheIpAddress& fake_address,
+ MasqueClientSession* masque_client_session) {
+ QUICHE_CHECK(masque_client_session != nullptr);
+ QUICHE_CHECK(!fake_address_.has_value());
+ fake_address_ = fake_address;
+ masque_client_session_ = masque_client_session;
+ }
+ ~FakeAddressRemover() {
+ if (fake_address_.has_value()) {
+ masque_client_session_->RemoveFakeAddress(*fake_address_);
+ }
+ }
+
+ private:
+ absl::optional<quiche::QuicheIpAddress> fake_address_;
+ MasqueClientSession* masque_client_session_ = nullptr;
+};
+
+} // namespace
+
bool SendEncapsulatedMasqueRequest(MasqueClient* masque_client,
QuicEventLoop* event_loop,
std::string url_string,
@@ -31,6 +59,7 @@ bool SendEncapsulatedMasqueRequest(MasqueClient* masque_client,
// Build the client, and try to connect.
QuicSocketAddress addr;
+ FakeAddressRemover fake_address_remover;
if (dns_on_client) {
addr = LookupAddress(address_family_for_lookup, url.host(),
absl::StrCat(url.port()));
@@ -39,9 +68,11 @@ bool SendEncapsulatedMasqueRequest(MasqueClient* masque_client,
return false;
}
} else {
- addr = QuicSocketAddress(
- masque_client->masque_client_session()->GetFakeAddress(url.host()),
- url.port());
+ quiche::QuicheIpAddress fake_address =
+ masque_client->masque_client_session()->GetFakeAddress(url.host());
+ fake_address_remover.IngestFakeAddress(
+ fake_address, masque_client->masque_client_session());
+ addr = QuicSocketAddress(fake_address, url.port());
QUICHE_CHECK(addr.IsInitialized());
}
const QuicServerId server_id(url.host(), url.port());
diff --git a/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.cc b/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.cc
index 038f8d73b..8bddb19ab 100644
--- a/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.cc
@@ -618,5 +618,11 @@ bool QuicConnectionPeer::TestLastReceivedPacketInfoDefaults() {
sizeof(QuicConnection::ReceivedPacketInfo) == 280);
}
+// static
+void QuicConnectionPeer::DisableEcnCodepointValidation(
+ QuicConnection* connection) {
+ connection->disable_ecn_codepoint_validation_ = true;
+}
+
} // namespace test
} // namespace quic
diff --git a/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h b/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h
index 087fcc012..cf8a5a6cf 100644
--- a/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h
+++ b/net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h
@@ -241,6 +241,9 @@ class QuicConnectionPeer {
QuicConnection* connection);
static bool TestLastReceivedPacketInfoDefaults();
+
+ // Overrides restrictions on sending ECN for test purposes.
+ static void DisableEcnCodepointValidation(QuicConnection* connection);
};
} // namespace test
diff --git a/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.cc b/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.cc
index 7eac0215c..e622ed816 100644
--- a/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.cc
+++ b/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.cc
@@ -1304,7 +1304,7 @@ TestPacketWriter::~TestPacketWriter() {
WriteResult TestPacketWriter::WritePacket(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
- PerPacketOptions* /*options*/) {
+ PerPacketOptions* options) {
last_write_source_address_ = self_address;
last_write_peer_address_ = peer_address;
// If the buffer is allocated from the pool, return it back to the pool.
@@ -1377,6 +1377,7 @@ WriteResult TestPacketWriter::WritePacket(const char* buffer, size_t buf_len,
bytes_buffered_ += last_packet_size_;
return WriteResult(WRITE_STATUS_OK, 0);
}
+ last_ecn_sent_ = (options == nullptr) ? ECN_NOT_ECT : options->ecn_codepoint;
return WriteResult(WRITE_STATUS_OK, last_packet_size_);
}
diff --git a/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h b/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h
index 6d7e39544..2835ac167 100644
--- a/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h
@@ -2010,6 +2010,8 @@ class TestPacketWriter : public QuicPacketWriter {
return last_write_peer_address_;
}
+ QuicEcnCodepoint last_ecn_sent() const { return last_ecn_sent_; }
+
private:
char* AllocPacketBuffer();
@@ -2055,6 +2057,7 @@ class TestPacketWriter : public QuicPacketWriter {
QuicIpAddress last_write_source_address_;
QuicSocketAddress last_write_peer_address_;
int write_error_code_{0};
+ QuicEcnCodepoint last_ecn_sent_ = ECN_NOT_ECT;
};
// Parses a packet generated by
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index 4fc061225..10be229f5 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -287,7 +287,7 @@ void URLRequestTestJob::ProcessNextOperation() {
stage_ = DATA_AVAILABLE;
// OK if ReadRawData wasn't called yet.
if (async_buf_) {
- int result = CopyDataForRead(async_buf_, async_buf_size_);
+ int result = CopyDataForRead(async_buf_.get(), async_buf_size_);
if (result < 0)
NOTREACHED() << "Reads should not fail in DATA_AVAILABLE.";
if (NextReadAsync()) {
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index d464244f2..a144685e9 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -173,7 +173,7 @@ class URLRequestTestJob : public URLRequestJob {
int offset_ = 0;
// Holds the buffer for an asynchronous ReadRawData call
- raw_ptr<IOBuffer> async_buf_ = nullptr;
+ scoped_refptr<IOBuffer> async_buf_;
int async_buf_size_ = 0;
LoadTimingInfo load_timing_info_;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 6b0807ffc..48cf06c06 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -10496,8 +10496,9 @@ class HTTPSCertNetFetchingTest : public HTTPSRequestTest {
}
void UpdateCertVerifier(scoped_refptr<CRLSet> crl_set) {
- updatable_cert_verifier_->UpdateVerifyProcData(cert_net_fetcher_,
- std::move(crl_set), nullptr);
+ net::CertVerifyProcFactory::ImplParams params;
+ params.crl_set = std::move(crl_set);
+ updatable_cert_verifier_->UpdateVerifyProcData(cert_net_fetcher_, params);
}
scoped_refptr<CertNetFetcherURLRequest> cert_net_fetcher_;
@@ -11606,16 +11607,15 @@ TEST_F(HTTPSLocalCRLSetTest, KnownInterceptionBlocked) {
// Configure a CRL that will mark |root_ca_cert| as a blocked interception
// root.
std::string crl_set_bytes;
- scoped_refptr<CRLSet> crl_set;
+ net::CertVerifyProcFactory::ImplParams params;
ASSERT_TRUE(
base::ReadFileToString(GetTestCertsDirectory().AppendASCII(
"crlset_blocked_interception_by_root.raw"),
&crl_set_bytes));
- ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
+ ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &params.crl_set));
updatable_cert_verifier_->UpdateVerifyProcData(
- /*cert_net_fetcher=*/nullptr, crl_set,
- /*root_store_data=*/nullptr);
+ /*cert_net_fetcher=*/nullptr, params);
// Verify the connection fails as being a known interception root.
{