summaryrefslogtreecommitdiff
path: root/chromium/net/http
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-09-07 13:12:05 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-11-09 10:02:59 +0000
commit33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (patch)
treef6af110909c79b2759136554f1143d8b0572af0a /chromium/net/http
parent7d2c5d177e9813077a621df8d18c0deda73099b3 (diff)
downloadqtwebengine-chromium-33fc33aa94d4add0878ec30dc818e34e1dd3cc2a.tar.gz
BASELINE: Update Chromium to 104.0.5112.120
Change-Id: I5d2726c2ab018d75d055739b6ba64317904f05bb Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438935 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/http')
-rw-r--r--chromium/net/http/OWNERS2
-rw-r--r--chromium/net/http/bidirectional_stream.cc22
-rw-r--r--chromium/net/http/bidirectional_stream.h2
-rw-r--r--chromium/net/http/bidirectional_stream_request_info.cc6
-rw-r--r--chromium/net/http/bidirectional_stream_request_info.h8
-rw-r--r--chromium/net/http/bidirectional_stream_unittest.cc27
-rw-r--r--chromium/net/http/broken_alternative_services.cc3
-rw-r--r--chromium/net/http/broken_alternative_services.h2
-rw-r--r--chromium/net/http/http_auth.cc2
-rw-r--r--chromium/net/http/http_auth.h4
-rw-r--r--chromium/net/http/http_auth_cache.cc5
-rw-r--r--chromium/net/http/http_auth_cache.h4
-rw-r--r--chromium/net/http/http_auth_controller.cc103
-rw-r--r--chromium/net/http/http_auth_controller.h4
-rw-r--r--chromium/net/http/http_auth_handler.cc15
-rw-r--r--chromium/net/http/http_auth_handler.h8
-rw-r--r--chromium/net/http/http_auth_handler_basic.cc2
-rw-r--r--chromium/net/http/http_auth_handler_digest.cc38
-rw-r--r--chromium/net/http/http_auth_handler_digest.h6
-rw-r--r--chromium/net/http/http_auth_handler_factory.h4
-rw-r--r--chromium/net/http/http_auth_handler_mock.cc13
-rw-r--r--chromium/net/http/http_auth_handler_mock.h19
-rw-r--r--chromium/net/http/http_auth_handler_negotiate.cc4
-rw-r--r--chromium/net/http/http_auth_handler_negotiate.h8
-rw-r--r--chromium/net/http/http_basic_stream.cc6
-rw-r--r--chromium/net/http/http_basic_stream.h2
-rw-r--r--chromium/net/http/http_byte_range.cc4
-rw-r--r--chromium/net/http/http_byte_range.h2
-rw-r--r--chromium/net/http/http_cache.cc138
-rw-r--r--chromium/net/http/http_cache.h48
-rw-r--r--chromium/net/http/http_cache_lookup_manager.cc1
-rw-r--r--chromium/net/http/http_cache_transaction.cc541
-rw-r--r--chromium/net/http/http_cache_transaction.h126
-rw-r--r--chromium/net/http/http_cache_unittest.cc404
-rw-r--r--chromium/net/http/http_cache_writers.cc75
-rw-r--r--chromium/net/http/http_cache_writers.h25
-rw-r--r--chromium/net/http/http_cache_writers_unittest.cc9
-rw-r--r--chromium/net/http/http_chunked_decoder.cc8
-rw-r--r--chromium/net/http/http_chunked_decoder.h10
-rw-r--r--chromium/net/http/http_content_disposition.cc23
-rw-r--r--chromium/net/http/http_content_disposition.h4
-rw-r--r--chromium/net/http/http_network_layer.cc3
-rw-r--r--chromium/net/http/http_network_layer.h2
-rw-r--r--chromium/net/http/http_network_session.cc142
-rw-r--r--chromium/net/http/http_network_session.h45
-rw-r--r--chromium/net/http/http_network_transaction.cc55
-rw-r--r--chromium/net/http/http_network_transaction.h34
-rw-r--r--chromium/net/http/http_network_transaction_unittest.cc63
-rw-r--r--chromium/net/http/http_proxy_client_socket.cc7
-rw-r--r--chromium/net/http/http_proxy_client_socket.h7
-rw-r--r--chromium/net/http/http_proxy_connect_job.cc12
-rw-r--r--chromium/net/http/http_proxy_connect_job.h6
-rw-r--r--chromium/net/http/http_request_headers.cc6
-rw-r--r--chromium/net/http/http_request_headers.h2
-rw-r--r--chromium/net/http/http_request_info.cc9
-rw-r--r--chromium/net/http/http_request_info.h22
-rw-r--r--chromium/net/http/http_response_body_drainer.cc5
-rw-r--r--chromium/net/http/http_response_body_drainer.h6
-rw-r--r--chromium/net/http/http_response_body_drainer_unittest.cc43
-rw-r--r--chromium/net/http/http_response_headers.cc35
-rw-r--r--chromium/net/http/http_response_info.cc22
-rw-r--r--chromium/net/http/http_response_info.h45
-rw-r--r--chromium/net/http/http_security_headers.cc11
-rw-r--r--chromium/net/http/http_server_properties.cc1
-rw-r--r--chromium/net/http/http_server_properties.h2
-rw-r--r--chromium/net/http/http_server_properties_manager.cc297
-rw-r--r--chromium/net/http/http_server_properties_manager.h26
-rw-r--r--chromium/net/http/http_server_properties_manager_unittest.cc203
-rw-r--r--chromium/net/http/http_stream.h6
-rw-r--r--chromium/net/http/http_stream_factory.cc12
-rw-r--r--chromium/net/http/http_stream_factory_job.cc65
-rw-r--r--chromium/net/http/http_stream_factory_job.h31
-rw-r--r--chromium/net/http/http_stream_factory_job_controller.cc36
-rw-r--r--chromium/net/http/http_stream_factory_job_controller.h28
-rw-r--r--chromium/net/http/http_stream_factory_job_controller_unittest.cc257
-rw-r--r--chromium/net/http/http_stream_factory_test_util.cc5
-rw-r--r--chromium/net/http/http_stream_factory_test_util.h6
-rw-r--r--chromium/net/http/http_stream_factory_unittest.cc40
-rw-r--r--chromium/net/http/http_stream_parser.cc41
-rw-r--r--chromium/net/http/http_stream_parser.h24
-rw-r--r--chromium/net/http/http_stream_parser_unittest.cc9
-rw-r--r--chromium/net/http/http_stream_request.cc4
-rw-r--r--chromium/net/http/http_stream_request.h8
-rw-r--r--chromium/net/http/http_stream_request_unittest.cc4
-rw-r--r--chromium/net/http/http_transaction_test_util.cc29
-rw-r--r--chromium/net/http/http_transaction_test_util.h35
-rw-r--r--chromium/net/http/http_util.cc26
-rw-r--r--chromium/net/http/http_util.h4
-rw-r--r--chromium/net/http/http_util_unittest.cc38
-rw-r--r--chromium/net/http/http_vary_data.cc3
-rw-r--r--chromium/net/http/http_vary_data.h2
-rw-r--r--chromium/net/http/mock_http_cache.cc44
-rw-r--r--chromium/net/http/mock_http_cache.h53
-rw-r--r--chromium/net/http/partial_data.cc18
-rw-r--r--chromium/net/http/partial_data.h22
-rw-r--r--chromium/net/http/structured_headers.cc984
-rw-r--r--chromium/net/http/structured_headers.h323
-rw-r--r--chromium/net/http/structured_headers_generated_unittest.cc3178
-rw-r--r--chromium/net/http/structured_headers_unittest.cc748
-rw-r--r--chromium/net/http/transport_security_state.cc33
-rw-r--r--chromium/net/http/transport_security_state.h22
-rw-r--r--chromium/net/http/transport_security_state_static.json.gzbin1353766 -> 1409536 bytes
-rw-r--r--chromium/net/http/transport_security_state_static.pins21
-rw-r--r--chromium/net/http/transport_security_state_static.template4
-rw-r--r--chromium/net/http/transport_security_state_static_unittest.pins6
-rw-r--r--chromium/net/http/transport_security_state_static_unittest_default.pins6
-rw-r--r--chromium/net/http/transport_security_state_unittest.cc122
107 files changed, 2389 insertions, 6756 deletions
diff --git a/chromium/net/http/OWNERS b/chromium/net/http/OWNERS
index c01a1d53643..49c38c96624 100644
--- a/chromium/net/http/OWNERS
+++ b/chromium/net/http/OWNERS
@@ -2,4 +2,6 @@ per-file http_cache_*=shivanisha@chromium.org
per-file transport_security_state_static.*=estark@chromium.org
per-file transport_security_state_static.*=cthomp@chromium.org
per-file transport_security_state_static.*=jdeblasio@chromium.org
+# For automated updates
+per-file transport_security_state_static.*=mdb.chrome-pki-metadata@google.com
per-file *test*=file://net/quic/OWNERS # for QUIC refactors
diff --git a/chromium/net/http/bidirectional_stream.cc b/chromium/net/http/bidirectional_stream.cc
index cdd0aa3586e..13faebf3845 100644
--- a/chromium/net/http/bidirectional_stream.cc
+++ b/chromium/net/http/bidirectional_stream.cc
@@ -39,23 +39,22 @@ namespace {
base::Value NetLogHeadersParams(const spdy::Http2HeaderBlock* headers,
NetLogCaptureMode capture_mode) {
- base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetKey("headers",
- ElideHttp2HeaderBlockForNetLog(*headers, capture_mode));
- return dict;
+ base::Value::Dict dict;
+ dict.Set("headers", ElideHttp2HeaderBlockForNetLog(*headers, capture_mode));
+ return base::Value(std::move(dict));
}
base::Value NetLogParams(const GURL& url,
const std::string& method,
const HttpRequestHeaders* headers,
NetLogCaptureMode capture_mode) {
- base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetStringKey("url", url.possibly_invalid_spec());
- dict.SetStringKey("method", method);
- std::string empty;
- base::Value headers_param(headers->NetLogParams(empty, capture_mode));
- dict.SetKey("headers", std::move(headers_param));
- return dict;
+ base::Value::Dict dict;
+ dict.Set("url", url.possibly_invalid_spec());
+ dict.Set("method", method);
+ base::Value headers_param(
+ headers->NetLogParams(/*request_line=*/std::string(), capture_mode));
+ dict.Set("headers", std::move(headers_param));
+ return base::Value(std::move(dict));
}
} // namespace
@@ -86,7 +85,6 @@ BidirectionalStream::BidirectionalStream(
NetLogSourceType::BIDIRECTIONAL_STREAM)),
session_(session),
send_request_headers_automatically_(send_request_headers_automatically),
- request_headers_sent_(false),
delegate_(delegate),
timer_(std::move(timer)) {
DCHECK(delegate_);
diff --git a/chromium/net/http/bidirectional_stream.h b/chromium/net/http/bidirectional_stream.h
index 17413441445..debf81b1ed0 100644
--- a/chromium/net/http/bidirectional_stream.h
+++ b/chromium/net/http/bidirectional_stream.h
@@ -234,7 +234,7 @@ class NET_EXPORT BidirectionalStream : public BidirectionalStreamImpl::Delegate,
bool send_request_headers_automatically_;
// Whether request headers have been sent, as indicated in OnStreamReady()
// callback.
- bool request_headers_sent_;
+ bool request_headers_sent_ = false;
const raw_ptr<Delegate> delegate_;
diff --git a/chromium/net/http/bidirectional_stream_request_info.cc b/chromium/net/http/bidirectional_stream_request_info.cc
index 18d9ba7b807..2b8cabfd09c 100644
--- a/chromium/net/http/bidirectional_stream_request_info.cc
+++ b/chromium/net/http/bidirectional_stream_request_info.cc
@@ -6,11 +6,7 @@
namespace net {
-BidirectionalStreamRequestInfo::BidirectionalStreamRequestInfo()
- : allow_early_data_override(false),
- priority(LOW),
- end_stream_on_headers(false),
- detect_broken_connection(false) {}
+BidirectionalStreamRequestInfo::BidirectionalStreamRequestInfo() = default;
BidirectionalStreamRequestInfo::~BidirectionalStreamRequestInfo() = default;
diff --git a/chromium/net/http/bidirectional_stream_request_info.h b/chromium/net/http/bidirectional_stream_request_info.h
index 2ed8a22cc4d..51c75ec5d33 100644
--- a/chromium/net/http/bidirectional_stream_request_info.h
+++ b/chromium/net/http/bidirectional_stream_request_info.h
@@ -29,10 +29,10 @@ struct NET_EXPORT BidirectionalStreamRequestInfo {
// Whether to allow early data to be used with this request, overriding the
// early data based on the |method| semantics.
- bool allow_early_data_override;
+ bool allow_early_data_override = false;
// Request priority.
- RequestPriority priority;
+ RequestPriority priority = LOW;
// Socket tag to apply to sockets used to process this request.
SocketTag socket_tag;
@@ -41,11 +41,11 @@ struct NET_EXPORT BidirectionalStreamRequestInfo {
HttpRequestHeaders extra_headers;
// Whether END_STREAM should be set on the request HEADER frame.
- bool end_stream_on_headers;
+ bool end_stream_on_headers = false;
// Whether the implementor of the BidirectionalStream should monitor
// the status of the connection for the lifetime of this stream.
- bool detect_broken_connection;
+ bool detect_broken_connection = false;
// Suggests the period the broken connection detector should use to check
// the status of the connection.
diff --git a/chromium/net/http/bidirectional_stream_unittest.cc b/chromium/net/http/bidirectional_stream_unittest.cc
index 60c45dd446a..d39ee35be51 100644
--- a/chromium/net/http/bidirectional_stream_unittest.cc
+++ b/chromium/net/http/bidirectional_stream_unittest.cc
@@ -104,16 +104,7 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
std::unique_ptr<base::OneShotTimer> timer)
: read_buf_(read_buf),
read_buf_len_(read_buf_len),
- timer_(std::move(timer)),
- loop_(nullptr),
- received_bytes_(0),
- sent_bytes_(0),
- error_(OK),
- on_data_read_count_(0),
- on_data_sent_count_(0),
- do_not_start_read_(false),
- run_until_completion_(false),
- not_expect_callback_(false) {}
+ timer_(std::move(timer)) {}
TestDelegateBase(const TestDelegateBase&) = delete;
TestDelegateBase& operator=(const TestDelegateBase&) = delete;
@@ -298,17 +289,17 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
spdy::Http2HeaderBlock response_headers_;
spdy::Http2HeaderBlock trailers_;
NextProto next_proto_;
- int64_t received_bytes_;
- int64_t sent_bytes_;
+ int64_t received_bytes_ = 0;
+ int64_t sent_bytes_ = 0;
LoadTimingInfo load_timing_info_;
- int error_;
- int on_data_read_count_;
- int on_data_sent_count_;
- bool do_not_start_read_;
- bool run_until_completion_;
+ int error_ = OK;
+ int on_data_read_count_ = 0;
+ int on_data_sent_count_ = 0;
+ bool do_not_start_read_ = false;
+ bool run_until_completion_ = false;
// This is to ensure that delegate callback is not invoked synchronously when
// calling into |stream_|.
- bool not_expect_callback_;
+ bool not_expect_callback_ = false;
CompletionOnceCallback callback_;
};
diff --git a/chromium/net/http/broken_alternative_services.cc b/chromium/net/http/broken_alternative_services.cc
index 9bde04df272..865277568c4 100644
--- a/chromium/net/http/broken_alternative_services.cc
+++ b/chromium/net/http/broken_alternative_services.cc
@@ -82,8 +82,7 @@ BrokenAlternativeServices::BrokenAlternativeServices(
clock_(clock),
recently_broken_alternative_services_(
max_recently_broken_alternative_service_entries),
- initial_delay_(kDefaultBrokenAlternativeProtocolDelay),
- exponential_backoff_on_initial_delay_(true) {
+ initial_delay_(kDefaultBrokenAlternativeProtocolDelay) {
DCHECK(delegate_);
DCHECK(clock_);
}
diff --git a/chromium/net/http/broken_alternative_services.h b/chromium/net/http/broken_alternative_services.h
index 56c8dfd6b74..72a36cbd176 100644
--- a/chromium/net/http/broken_alternative_services.h
+++ b/chromium/net/http/broken_alternative_services.h
@@ -229,7 +229,7 @@ class NET_EXPORT_PRIVATE BrokenAlternativeServices {
// initial_delay_for_broken_alternative_service * (1 << broken_count).
// Otherwise, the delay would be initial_delay_for_broken_alternative_service,
// 5min, 10min.. and so on.
- bool exponential_backoff_on_initial_delay_;
+ bool exponential_backoff_on_initial_delay_ = true;
base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_{this};
};
diff --git a/chromium/net/http/http_auth.cc b/chromium/net/http/http_auth.cc
index bd9cbc1e57e..55240b53bc6 100644
--- a/chromium/net/http/http_auth.cc
+++ b/chromium/net/http/http_auth.cc
@@ -29,7 +29,7 @@ const char* const kSchemeNames[] = {kBasicAuthScheme, kDigestAuthScheme,
kSpdyProxyAuthScheme, kMockAuthScheme};
} // namespace
-HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {}
+HttpAuth::Identity::Identity() = default;
// static
void HttpAuth::ChooseBestChallenge(
diff --git a/chromium/net/http/http_auth.h b/chromium/net/http/http_auth.h
index 4a0f3b84daf..319d2d31189 100644
--- a/chromium/net/http/http_auth.h
+++ b/chromium/net/http/http_auth.h
@@ -128,8 +128,8 @@ class NET_EXPORT_PRIVATE HttpAuth {
struct Identity {
Identity();
- IdentitySource source;
- bool invalid;
+ IdentitySource source = IDENT_SRC_NONE;
+ bool invalid = true;
AuthCredentials credentials;
};
diff --git a/chromium/net/http/http_auth_cache.cc b/chromium/net/http/http_auth_cache.cc
index bbcb9798d68..81f82ea9555 100644
--- a/chromium/net/http/http_auth_cache.cc
+++ b/chromium/net/http/http_auth_cache.cc
@@ -236,10 +236,7 @@ bool HttpAuthCache::Entry::IsEqualForTesting(const Entry& other) const {
return true;
}
-HttpAuthCache::Entry::Entry()
- : scheme_(HttpAuth::AUTH_SCHEME_MAX),
- nonce_count_(0) {
-}
+HttpAuthCache::Entry::Entry() = default;
void HttpAuthCache::Entry::AddPath(const std::string& path) {
std::string parent_dir = GetParentDirectory(path);
diff --git a/chromium/net/http/http_auth_cache.h b/chromium/net/http/http_auth_cache.h
index ef75a9473ee..030de45ddc1 100644
--- a/chromium/net/http/http_auth_cache.h
+++ b/chromium/net/http/http_auth_cache.h
@@ -98,13 +98,13 @@ class NET_EXPORT HttpAuthCache {
// SchemeHostPort of the server.
url::SchemeHostPort scheme_host_port_;
std::string realm_;
- HttpAuth::Scheme scheme_;
+ HttpAuth::Scheme scheme_ = HttpAuth::AUTH_SCHEME_MAX;
// Identity.
std::string auth_challenge_;
AuthCredentials credentials_;
- int nonce_count_;
+ int nonce_count_ = 0;
// List of paths that define the realm's protection space.
PathList paths_;
diff --git a/chromium/net/http/http_auth_controller.cc b/chromium/net/http/http_auth_controller.cc
index 90509517519..576cfb17e12 100644
--- a/chromium/net/http/http_auth_controller.cc
+++ b/chromium/net/http/http_auth_controller.cc
@@ -11,7 +11,6 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "net/base/auth.h"
#include "net/base/url_util.h"
@@ -32,102 +31,6 @@ namespace net {
namespace {
-enum AuthEvent {
- AUTH_EVENT_START = 0,
- AUTH_EVENT_REJECT,
- AUTH_EVENT_MAX,
-};
-
-enum AuthTarget {
- AUTH_TARGET_PROXY = 0,
- AUTH_TARGET_SECURE_PROXY,
- AUTH_TARGET_SERVER,
- AUTH_TARGET_SECURE_SERVER,
- AUTH_TARGET_MAX,
-};
-
-AuthTarget DetermineAuthTarget(const HttpAuthHandler* handler) {
- switch (handler->target()) {
- case HttpAuth::AUTH_PROXY:
- if (GURL::SchemeIsCryptographic(handler->scheme_host_port().scheme()))
- return AUTH_TARGET_SECURE_PROXY;
- else
- return AUTH_TARGET_PROXY;
- case HttpAuth::AUTH_SERVER:
- if (GURL::SchemeIsCryptographic(handler->scheme_host_port().scheme()))
- return AUTH_TARGET_SECURE_SERVER;
- else
- return AUTH_TARGET_SERVER;
- default:
- NOTREACHED();
- return AUTH_TARGET_MAX;
- }
-}
-
-// Records the number of authentication events per authentication scheme.
-void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) {
-#if !defined(NDEBUG)
- // Note: The on-same-thread check is intentionally not using a lock
- // to protect access to first_thread. This method is meant to be only
- // used on the same thread, in which case there are no race conditions. If
- // there are race conditions (say, a read completes during a partial write),
- // the DCHECK will correctly fail.
- static base::PlatformThreadId first_thread =
- base::PlatformThread::CurrentId();
- DCHECK_EQ(first_thread, base::PlatformThread::CurrentId());
-#endif
-
- HttpAuth::Scheme auth_scheme = handler->auth_scheme();
- DCHECK(auth_scheme >= 0 && auth_scheme < HttpAuth::AUTH_SCHEME_MAX);
-
- // Record start and rejection events for authentication.
- //
- // The results map to:
- // Basic Start: 0
- // Basic Reject: 1
- // Digest Start: 2
- // Digest Reject: 3
- // NTLM Start: 4
- // NTLM Reject: 5
- // Negotiate Start: 6
- // Negotiate Reject: 7
- static const int kEventBucketsEnd =
- HttpAuth::AUTH_SCHEME_MAX * AUTH_EVENT_MAX;
- int event_bucket = auth_scheme * AUTH_EVENT_MAX + auth_event;
- DCHECK(event_bucket >= 0 && event_bucket < kEventBucketsEnd);
- UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", event_bucket,
- kEventBucketsEnd);
-
- // Record the target of the authentication.
- //
- // The results map to:
- // Basic Proxy: 0
- // Basic Secure Proxy: 1
- // Basic Server: 2
- // Basic Secure Server: 3
- // Digest Proxy: 4
- // Digest Secure Proxy: 5
- // Digest Server: 6
- // Digest Secure Server: 7
- // NTLM Proxy: 8
- // NTLM Secure Proxy: 9
- // NTLM Server: 10
- // NTLM Secure Server: 11
- // Negotiate Proxy: 12
- // Negotiate Secure Proxy: 13
- // Negotiate Server: 14
- // Negotiate Secure Server: 15
- if (auth_event != AUTH_EVENT_START)
- return;
- static const int kTargetBucketsEnd =
- HttpAuth::AUTH_SCHEME_MAX * AUTH_TARGET_MAX;
- AuthTarget auth_target = DetermineAuthTarget(handler);
- int target_bucket = auth_scheme * AUTH_TARGET_MAX + auth_target;
- DCHECK(target_bucket >= 0 && target_bucket < kTargetBucketsEnd);
- UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthTarget", target_bucket,
- kTargetBucketsEnd);
-}
-
base::Value ControllerParamsToValue(HttpAuth::Target target, const GURL& url) {
base::Value params(base::Value::Type::DICTIONARY);
params.SetStringPath("target", HttpAuth::GetAuthTargetString(target));
@@ -149,8 +52,6 @@ HttpAuthController::HttpAuthController(
auth_scheme_host_port_(auth_url),
auth_path_(auth_url.path()),
network_isolation_key_(network_isolation_key),
- embedded_identity_used_(false),
- default_credentials_used_(false),
http_auth_cache_(http_auth_cache),
http_auth_handler_factory_(http_auth_handler_factory),
host_resolver_(host_resolver) {
@@ -290,7 +191,6 @@ int HttpAuthController::HandleAuthChallenge(
InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
break;
case HttpAuth::AUTHORIZATION_RESULT_REJECT:
- HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT);
InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
break;
case HttpAuth::AUTHORIZATION_RESULT_STALE:
@@ -334,8 +234,6 @@ int HttpAuthController::HandleAuthChallenge(
ssl_info, network_isolation_key_, target_,
auth_scheme_host_port_, disabled_schemes_,
net_log_, host_resolver_, &handler_);
- if (handler_.get())
- HistogramAuthEvent(handler_.get(), AUTH_EVENT_START);
}
if (!handler_.get()) {
@@ -370,7 +268,6 @@ int HttpAuthController::HandleAuthChallenge(
if (!handler_->AllowsExplicitCredentials()) {
// If the handler doesn't accept explicit credentials, then we need to
// choose a different auth scheme.
- HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT);
InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
} else {
// Pass the challenge information back to the client.
diff --git a/chromium/net/http/http_auth_controller.h b/chromium/net/http/http_auth_controller.h
index 5d9b4b04b5a..6b346bd1be7 100644
--- a/chromium/net/http/http_auth_controller.h
+++ b/chromium/net/http/http_auth_controller.h
@@ -226,11 +226,11 @@ class NET_EXPORT_PRIVATE HttpAuthController
// True if we've used the username:password embedded in the URL. This
// makes sure we use the embedded identity only once for the transaction,
// preventing an infinite auth restart loop.
- bool embedded_identity_used_;
+ bool embedded_identity_used_ = false;
// True if default credentials have already been tried for this transaction
// in response to an HTTP authentication challenge.
- bool default_credentials_used_;
+ bool default_credentials_used_ = false;
// These two are owned by the HttpNetworkSession/IOThread, which own the
// objects which reference |this|. Therefore, these raw pointers are valid
diff --git a/chromium/net/http/http_auth_handler.cc b/chromium/net/http/http_auth_handler.cc
index 64f7851e20d..eb138c893c3 100644
--- a/chromium/net/http/http_auth_handler.cc
+++ b/chromium/net/http/http_auth_handler.cc
@@ -16,12 +16,7 @@
namespace net {
-HttpAuthHandler::HttpAuthHandler()
- : auth_scheme_(HttpAuth::AUTH_SCHEME_MAX),
- score_(-1),
- target_(HttpAuth::AUTH_NONE),
- properties_(-1) {
-}
+HttpAuthHandler::HttpAuthHandler() = default;
HttpAuthHandler::~HttpAuthHandler() = default;
@@ -41,8 +36,12 @@ bool HttpAuthHandler::InitFromChallenge(
auth_challenge_ = challenge->challenge_text();
net_log_.BeginEvent(NetLogEventType::AUTH_HANDLER_INIT);
bool ok = Init(challenge, ssl_info, network_isolation_key);
- net_log_.AddEntryWithBoolParams(NetLogEventType::AUTH_HANDLER_INIT,
- NetLogEventPhase::END, "succeeded", ok);
+ net_log_.EndEvent(NetLogEventType::AUTH_HANDLER_INIT, [&]() {
+ base::Value::Dict params;
+ params.Set("succeeded", ok);
+ params.Set("allows_default_credentials", AllowsDefaultCredentials());
+ return base::Value(std::move(params));
+ });
// Init() is expected to set the scheme, realm, score, and properties. The
// realm may be empty.
diff --git a/chromium/net/http/http_auth_handler.h b/chromium/net/http/http_auth_handler.h
index b0b4de856d8..5348b90c000 100644
--- a/chromium/net/http/http_auth_handler.h
+++ b/chromium/net/http/http_auth_handler.h
@@ -208,7 +208,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandler {
HttpAuthChallengeTokenizer* challenge) = 0;
// The auth-scheme as an enumerated value.
- HttpAuth::Scheme auth_scheme_;
+ HttpAuth::Scheme auth_scheme_ = HttpAuth::AUTH_SCHEME_MAX;
// The realm, encoded as UTF-8. Used by "basic" and "digest".
std::string realm_;
@@ -221,14 +221,14 @@ class NET_EXPORT_PRIVATE HttpAuthHandler {
url::SchemeHostPort scheme_host_port_;
// The score for this challenge. Higher numbers are better.
- int score_;
+ int score_ = -1;
// Whether this authentication request is for a proxy server, or an
// origin server.
- HttpAuth::Target target_;
+ HttpAuth::Target target_ = HttpAuth::AUTH_NONE;
// A bitmask of the properties of the authentication scheme.
- int properties_;
+ int properties_ = -1;
private:
void OnGenerateAuthTokenComplete(int rv);
diff --git a/chromium/net/http/http_auth_handler_basic.cc b/chromium/net/http/http_auth_handler_basic.cc
index 009f847dd3b..1b187631747 100644
--- a/chromium/net/http/http_auth_handler_basic.cc
+++ b/chromium/net/http/http_auth_handler_basic.cc
@@ -45,7 +45,7 @@ bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer,
realm->clear();
HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs();
while (parameters.GetNext()) {
- if (!base::LowerCaseEqualsASCII(parameters.name_piece(), "realm"))
+ if (!base::EqualsCaseInsensitiveASCII(parameters.name_piece(), "realm"))
continue;
if (!ConvertToUtf8AndNormalize(parameters.value_piece(), kCharsetLatin1,
diff --git a/chromium/net/http/http_auth_handler_digest.cc b/chromium/net/http/http_auth_handler_digest.cc
index a8018dccbc5..0557b3dc6c5 100644
--- a/chromium/net/http/http_auth_handler_digest.cc
+++ b/chromium/net/http/http_auth_handler_digest.cc
@@ -153,10 +153,11 @@ HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallengeImpl(
// for the new challenge.
std::string original_realm;
while (parameters.GetNext()) {
- if (base::LowerCaseEqualsASCII(parameters.name_piece(), "stale")) {
- if (base::LowerCaseEqualsASCII(parameters.value_piece(), "true"))
+ if (base::EqualsCaseInsensitiveASCII(parameters.name_piece(), "stale")) {
+ if (base::EqualsCaseInsensitiveASCII(parameters.value_piece(), "true"))
return HttpAuth::AUTHORIZATION_RESULT_STALE;
- } else if (base::LowerCaseEqualsASCII(parameters.name_piece(), "realm")) {
+ } else if (base::EqualsCaseInsensitiveASCII(parameters.name_piece(),
+ "realm")) {
original_realm = parameters.value();
}
}
@@ -166,12 +167,9 @@ HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallengeImpl(
}
HttpAuthHandlerDigest::HttpAuthHandlerDigest(
- int nonce_count, const NonceGenerator* nonce_generator)
- : stale_(false),
- algorithm_(ALGORITHM_UNSPECIFIED),
- qop_(QOP_UNSPECIFIED),
- nonce_count_(nonce_count),
- nonce_generator_(nonce_generator) {
+ int nonce_count,
+ const NonceGenerator* nonce_generator)
+ : nonce_count_(nonce_count), nonce_generator_(nonce_generator) {
DCHECK(nonce_generator_);
}
@@ -234,32 +232,32 @@ bool HttpAuthHandlerDigest::ParseChallenge(
bool HttpAuthHandlerDigest::ParseChallengeProperty(base::StringPiece name,
base::StringPiece value) {
- if (base::LowerCaseEqualsASCII(name, "realm")) {
+ if (base::EqualsCaseInsensitiveASCII(name, "realm")) {
std::string realm;
if (!ConvertToUtf8AndNormalize(value, kCharsetLatin1, &realm))
return false;
realm_ = realm;
original_realm_ = std::string(value);
- } else if (base::LowerCaseEqualsASCII(name, "nonce")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "nonce")) {
nonce_ = std::string(value);
- } else if (base::LowerCaseEqualsASCII(name, "domain")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "domain")) {
domain_ = std::string(value);
- } else if (base::LowerCaseEqualsASCII(name, "opaque")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "opaque")) {
opaque_ = std::string(value);
- } else if (base::LowerCaseEqualsASCII(name, "stale")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "stale")) {
// Parse the stale boolean.
- stale_ = base::LowerCaseEqualsASCII(value, "true");
- } else if (base::LowerCaseEqualsASCII(name, "algorithm")) {
+ stale_ = base::EqualsCaseInsensitiveASCII(value, "true");
+ } else if (base::EqualsCaseInsensitiveASCII(name, "algorithm")) {
// Parse the algorithm.
- if (base::LowerCaseEqualsASCII(value, "md5")) {
+ if (base::EqualsCaseInsensitiveASCII(value, "md5")) {
algorithm_ = ALGORITHM_MD5;
- } else if (base::LowerCaseEqualsASCII(value, "md5-sess")) {
+ } else if (base::EqualsCaseInsensitiveASCII(value, "md5-sess")) {
algorithm_ = ALGORITHM_MD5_SESS;
} else {
DVLOG(1) << "Unknown value of algorithm";
return false; // FAIL -- unsupported value of algorithm.
}
- } else if (base::LowerCaseEqualsASCII(name, "qop")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "qop")) {
// Parse the comma separated list of qops.
// auth is the only supported qop, and all other values are ignored.
//
@@ -270,7 +268,7 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(base::StringPiece name,
',');
qop_ = QOP_UNSPECIFIED;
while (qop_values.GetNext()) {
- if (base::LowerCaseEqualsASCII(qop_values.value_piece(), "auth")) {
+ if (base::EqualsCaseInsensitiveASCII(qop_values.value_piece(), "auth")) {
qop_ = QOP_AUTH;
break;
}
diff --git a/chromium/net/http/http_auth_handler_digest.h b/chromium/net/http/http_auth_handler_digest.h
index dad4683147d..a170f7a81e1 100644
--- a/chromium/net/http/http_auth_handler_digest.h
+++ b/chromium/net/http/http_auth_handler_digest.h
@@ -174,9 +174,9 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerDigest : public HttpAuthHandler {
std::string nonce_;
std::string domain_;
std::string opaque_;
- bool stale_;
- DigestAlgorithm algorithm_;
- QualityOfProtection qop_;
+ bool stale_ = false;
+ DigestAlgorithm algorithm_ = ALGORITHM_UNSPECIFIED;
+ QualityOfProtection qop_ = QOP_UNSPECIFIED;
// The realm as initially encoded over-the-wire. This is used in the
// challenge text, rather than |realm_| which has been converted to
diff --git a/chromium/net/http/http_auth_handler_factory.h b/chromium/net/http/http_auth_handler_factory.h
index 683b63f3f26..d9b9138cc91 100644
--- a/chromium/net/http/http_auth_handler_factory.h
+++ b/chromium/net/http/http_auth_handler_factory.h
@@ -45,7 +45,7 @@ class NET_EXPORT HttpAuthHandlerFactory {
CREATE_PREEMPTIVE, // Create a handler preemptively.
};
- HttpAuthHandlerFactory() : http_auth_preferences_(nullptr) {}
+ HttpAuthHandlerFactory() = default;
HttpAuthHandlerFactory(const HttpAuthHandlerFactory&) = delete;
HttpAuthHandlerFactory& operator=(const HttpAuthHandlerFactory&) = delete;
@@ -163,7 +163,7 @@ class NET_EXPORT HttpAuthHandlerFactory {
private:
// The preferences for HTTP authentication.
- raw_ptr<const HttpAuthPreferences> http_auth_preferences_;
+ raw_ptr<const HttpAuthPreferences> http_auth_preferences_ = nullptr;
};
// The HttpAuthHandlerRegistryFactory dispatches create requests out
diff --git a/chromium/net/http/http_auth_handler_mock.cc b/chromium/net/http/http_auth_handler_mock.cc
index 0e7fb96c345..9e76f02a001 100644
--- a/chromium/net/http/http_auth_handler_mock.cc
+++ b/chromium/net/http/http_auth_handler_mock.cc
@@ -41,15 +41,7 @@ void PrintTo(const HttpAuthHandlerMock::State& state, ::std::ostream* os) {
}
}
-HttpAuthHandlerMock::HttpAuthHandlerMock()
- : state_(State::WAIT_FOR_INIT),
- generate_async_(false),
- generate_rv_(OK),
- auth_token_(nullptr),
- first_round_(true),
- connection_based_(false),
- allows_default_credentials_(false),
- allows_explicit_credentials_(true) {}
+HttpAuthHandlerMock::HttpAuthHandlerMock() = default;
HttpAuthHandlerMock::~HttpAuthHandlerMock() = default;
@@ -147,8 +139,7 @@ void HttpAuthHandlerMock::OnGenerateAuthToken() {
std::move(callback_).Run(generate_rv_);
}
-HttpAuthHandlerMock::Factory::Factory()
- : do_init_from_challenge_(false) {
+HttpAuthHandlerMock::Factory::Factory() {
// TODO(cbentzel): Default do_init_from_challenge_ to true.
}
diff --git a/chromium/net/http/http_auth_handler_mock.h b/chromium/net/http/http_auth_handler_mock.h
index b98a92478cd..ef2be2f1686 100644
--- a/chromium/net/http/http_auth_handler_mock.h
+++ b/chromium/net/http/http_auth_handler_mock.h
@@ -13,6 +13,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
#include "url/gurl.h"
@@ -62,7 +63,7 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
private:
std::vector<std::unique_ptr<HttpAuthHandler>>
handlers_[HttpAuth::AUTH_NUM_TARGETS];
- bool do_init_from_challenge_;
+ bool do_init_from_challenge_ = false;
};
HttpAuthHandlerMock();
@@ -108,15 +109,15 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
private:
void OnGenerateAuthToken();
- State state_;
+ State state_ = State::WAIT_FOR_INIT;
CompletionOnceCallback callback_;
- bool generate_async_;
- int generate_rv_;
- raw_ptr<std::string> auth_token_;
- bool first_round_;
- bool connection_based_;
- bool allows_default_credentials_;
- bool allows_explicit_credentials_;
+ bool generate_async_ = false;
+ int generate_rv_ = OK;
+ raw_ptr<std::string> auth_token_ = nullptr;
+ bool first_round_ = true;
+ bool connection_based_ = false;
+ bool allows_default_credentials_ = false;
+ bool allows_explicit_credentials_ = true;
GURL request_url_;
base::WeakPtrFactory<HttpAuthHandlerMock> weak_factory_{this};
};
diff --git a/chromium/net/http/http_auth_handler_negotiate.cc b/chromium/net/http/http_auth_handler_negotiate.cc
index 73d2b47132e..bab8b1b551a 100644
--- a/chromium/net/http/http_auth_handler_negotiate.cc
+++ b/chromium/net/http/http_auth_handler_negotiate.cc
@@ -150,10 +150,6 @@ HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(
HostResolver* resolver)
: auth_system_(std::move(auth_system)),
resolver_(resolver),
- already_called_(false),
- has_credentials_(false),
- auth_token_(nullptr),
- next_state_(STATE_NONE),
http_auth_preferences_(prefs) {}
HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() = default;
diff --git a/chromium/net/http/http_auth_handler_negotiate.h b/chromium/net/http/http_auth_handler_negotiate.h
index ed0551f1afb..73f2c22780c 100644
--- a/chromium/net/http/http_auth_handler_negotiate.h
+++ b/chromium/net/http/http_auth_handler_negotiate.h
@@ -141,17 +141,17 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler {
std::unique_ptr<HostResolver::ResolveHostRequest> resolve_host_request_;
// Things which should be consistent after first call to GenerateAuthToken.
- bool already_called_;
- bool has_credentials_;
+ bool already_called_ = false;
+ bool has_credentials_ = false;
AuthCredentials credentials_;
std::string spn_;
std::string channel_bindings_;
// Things which vary each round.
CompletionOnceCallback callback_;
- raw_ptr<std::string> auth_token_;
+ raw_ptr<std::string> auth_token_ = nullptr;
- State next_state_;
+ State next_state_ = STATE_NONE;
raw_ptr<const HttpAuthPreferences> http_auth_preferences_;
};
diff --git a/chromium/net/http/http_basic_stream.cc b/chromium/net/http/http_basic_stream.cc
index d82e153e47e..1dcf2b018f0 100644
--- a/chromium/net/http/http_basic_stream.cc
+++ b/chromium/net/http/http_basic_stream.cc
@@ -176,11 +176,11 @@ void HttpBasicStream::GetSSLCertRequestInfo(
parser()->GetSSLCertRequestInfo(cert_request_info);
}
-bool HttpBasicStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
+int HttpBasicStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
if (!state_.connection() || !state_.connection()->socket())
- return false;
+ return ERR_SOCKET_NOT_CONNECTED;
- return state_.connection()->socket()->GetPeerAddress(endpoint) == OK;
+ return state_.connection()->socket()->GetPeerAddress(endpoint);
}
void HttpBasicStream::Drain(HttpNetworkSession* session) {
diff --git a/chromium/net/http/http_basic_stream.h b/chromium/net/http/http_basic_stream.h
index 8c765a8e13c..2d1c561a2c0 100644
--- a/chromium/net/http/http_basic_stream.h
+++ b/chromium/net/http/http_basic_stream.h
@@ -87,7 +87,7 @@ class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream {
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
- bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
+ int GetRemoteEndpoint(IPEndPoint* endpoint) override;
void Drain(HttpNetworkSession* session) override;
diff --git a/chromium/net/http/http_byte_range.cc b/chromium/net/http/http_byte_range.cc
index 30a5d72629c..95a46785606 100644
--- a/chromium/net/http/http_byte_range.cc
+++ b/chromium/net/http/http_byte_range.cc
@@ -20,9 +20,7 @@ namespace net {
HttpByteRange::HttpByteRange()
: first_byte_position_(kPositionNotSpecified),
last_byte_position_(kPositionNotSpecified),
- suffix_length_(kPositionNotSpecified),
- has_computed_bounds_(false) {
-}
+ suffix_length_(kPositionNotSpecified) {}
// static
HttpByteRange HttpByteRange::Bounded(int64_t first_byte_position,
diff --git a/chromium/net/http/http_byte_range.h b/chromium/net/http/http_byte_range.h
index f83187407b7..5b6a76c9858 100644
--- a/chromium/net/http/http_byte_range.h
+++ b/chromium/net/http/http_byte_range.h
@@ -64,7 +64,7 @@ class NET_EXPORT HttpByteRange {
int64_t first_byte_position_;
int64_t last_byte_position_;
int64_t suffix_length_;
- bool has_computed_bounds_;
+ bool has_computed_bounds_ = false;
};
} // namespace net
diff --git a/chromium/net/http/http_cache.cc b/chromium/net/http/http_cache.cc
index 5aed1148698..9515e6f0915 100644
--- a/chromium/net/http/http_cache.cc
+++ b/chromium/net/http/http_cache.cc
@@ -67,14 +67,20 @@ bool g_enable_split_cache = false;
const char HttpCache::kDoubleKeyPrefix[] = "_dk_";
const char HttpCache::kDoubleKeySeparator[] = " ";
const char HttpCache::kSubframeDocumentResourcePrefix[] = "s_";
-
-HttpCache::DefaultBackend::DefaultBackend(CacheType type,
- BackendType backend_type,
- const base::FilePath& path,
- int max_bytes,
- bool hard_reset)
+const char HttpCache::kSingleKeyPrefix[] = "_sk_";
+const char HttpCache::kSingleKeySeparator[] = " ";
+
+HttpCache::DefaultBackend::DefaultBackend(
+ CacheType type,
+ BackendType backend_type,
+ scoped_refptr<disk_cache::BackendFileOperationsFactory>
+ file_operations_factory,
+ const base::FilePath& path,
+ int max_bytes,
+ bool hard_reset)
: type_(type),
backend_type_(backend_type),
+ file_operations_factory_(std::move(file_operations_factory)),
path_(path),
max_bytes_(max_bytes),
hard_reset_(hard_reset) {}
@@ -85,6 +91,7 @@ HttpCache::DefaultBackend::~DefaultBackend() = default;
std::unique_ptr<HttpCache::BackendFactory> HttpCache::DefaultBackend::InMemory(
int max_bytes) {
return std::make_unique<DefaultBackend>(MEMORY_CACHE, CACHE_BACKEND_DEFAULT,
+ /*file_operations_factory=*/nullptr,
base::FilePath(), max_bytes, false);
}
@@ -100,13 +107,13 @@ int HttpCache::DefaultBackend::CreateBackend(
#if BUILDFLAG(IS_ANDROID)
if (app_status_listener_) {
return disk_cache::CreateCacheBackend(
- type_, backend_type_, /*file_operations=*/nullptr, path_, max_bytes_,
+ type_, backend_type_, file_operations_factory_, path_, max_bytes_,
reset_handling, net_log, backend, std::move(callback),
app_status_listener_);
}
#endif
return disk_cache::CreateCacheBackend(
- type_, backend_type_, /*file_operations=*/nullptr, path_, max_bytes_,
+ type_, backend_type_, file_operations_factory_, path_, max_bytes_,
reset_handling, net_log, backend, std::move(callback));
}
@@ -120,13 +127,12 @@ void HttpCache::DefaultBackend::SetAppStatusListener(
//-----------------------------------------------------------------------------
HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry, bool opened_in)
- : disk_entry(entry), opened(opened_in) {}
+ : disk_entry(entry), opened(opened_in) {
+ DCHECK(disk_entry);
+}
HttpCache::ActiveEntry::~ActiveEntry() {
- if (disk_entry) {
- disk_entry->Close();
- disk_entry = nullptr;
- }
+ disk_entry->Close();
}
bool HttpCache::ActiveEntry::HasNoTransactions() {
@@ -149,12 +155,11 @@ bool HttpCache::ActiveEntry::TransactionInReaders(
// This structure keeps track of work items that are attempting to create or
// open cache entries or the backend itself.
struct HttpCache::PendingOp {
- PendingOp()
- : entry(nullptr), entry_opened(false), callback_will_delete(false) {}
+ PendingOp() = default;
~PendingOp() = default;
- raw_ptr<disk_cache::Entry> entry;
- bool entry_opened; // rather than created.
+ raw_ptr<disk_cache::Entry> entry = nullptr;
+ bool entry_opened = false; // rather than created.
std::unique_ptr<disk_cache::Backend> backend;
std::unique_ptr<WorkItem> writer;
@@ -162,7 +167,7 @@ struct HttpCache::PendingOp {
// |this| without removing it from |pending_ops_|. Note that since
// OnPendingOpComplete() is static, it will not get cancelled when HttpCache
// is destroyed.
- bool callback_will_delete;
+ bool callback_will_delete = false;
WorkItemList pending_queue;
};
@@ -192,7 +197,6 @@ class HttpCache::WorkItem {
// Calls back the transaction with the result of the operation.
void NotifyTransaction(int result, ActiveEntry* entry) {
- DCHECK(!entry || entry->disk_entry);
if (entry_)
*entry_ = entry;
if (transaction_)
@@ -232,25 +236,11 @@ class HttpCache::WorkItem {
//-----------------------------------------------------------------------------
-HttpCache::HttpCache(HttpNetworkSession* session,
- std::unique_ptr<BackendFactory> backend_factory,
- bool is_main_cache)
- : HttpCache(std::make_unique<HttpNetworkLayer>(session),
- std::move(backend_factory),
- is_main_cache) {
- g_init_cache = true;
-}
-
HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
- std::unique_ptr<BackendFactory> backend_factory,
- bool is_main_cache)
+ std::unique_ptr<BackendFactory> backend_factory)
: net_log_(nullptr),
backend_factory_(std::move(backend_factory)),
- building_backend_(false),
- bypass_lock_for_test_(false),
- bypass_lock_after_headers_for_test_(false),
- fail_conditionalization_for_test_(false),
- mode_(NORMAL),
+
network_layer_(std::move(network_layer)),
clock_(base::DefaultClock::GetInstance()) {
g_init_cache = true;
@@ -262,8 +252,6 @@ HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
return;
net_log_ = session->net_log();
- if (!is_main_cache)
- return;
session->SetServerPushDelegate(
std::make_unique<HttpCacheLookupManager>(this));
@@ -373,7 +361,8 @@ void HttpCache::OnExternalCacheHit(
request_info.load_flags |= ~LOAD_DO_NOT_SAVE_COOKIES;
}
- std::string key = GenerateCacheKey(&request_info);
+ std::string key =
+ GenerateCacheKey(&request_info, /*use_single_keyed_cache=*/false);
disk_cache_->OnExternalCacheHit(key);
}
@@ -445,6 +434,11 @@ std::string HttpCache::GetResourceURLFromHttpCacheKey(const std::string& key) {
DCHECK_NE(pos, std::string::npos);
pos += strlen(kDoubleKeySeparator);
DCHECK_LE(pos, key.size() - 1);
+ } else if (pos == key.find(kSingleKeyPrefix, pos)) {
+ pos = key.rfind(kSingleKeySeparator);
+ DCHECK_NE(pos, std::string::npos);
+ pos += strlen(kSingleKeySeparator);
+ DCHECK_LE(pos, key.size() - 1);
}
return key.substr(pos);
}
@@ -464,7 +458,10 @@ Error HttpCache::CheckResourceExistence(
request_info.network_isolation_key = network_isolation_key;
request_info.is_subframe_document_resource = is_subframe;
- std::string key = GenerateCacheKey(&request_info);
+ // TODO(https://crbug.com/1325315): Support looking in the single-keyed cache
+ // for the resource.
+ std::string key =
+ GenerateCacheKey(&request_info, /*use_single_keyed_cache=*/false);
disk_cache::EntryResult entry_result = disk_cache_->OpenEntry(
key, net::IDLE,
base::BindOnce(&HttpCache::ResourceExistenceCheckCallback, GetWeakPtr(),
@@ -478,7 +475,7 @@ Error HttpCache::CheckResourceExistence(
// static
std::string HttpCache::GenerateCacheKeyForTest(const HttpRequestInfo* request) {
- return GenerateCacheKey(request);
+ return GenerateCacheKey(request, /*use_single_keyed_cache=*/false);
}
// static
@@ -578,18 +575,35 @@ int HttpCache::GetBackendForTransaction(Transaction* transaction) {
// static
// Generate a key that can be used inside the cache.
-std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
- const char credential_key = (base::FeatureList::IsEnabled(
- features::kSplitCacheByIncludeCredentials) &&
- (request->load_flags & LOAD_DO_NOT_SAVE_COOKIES))
- ? '0'
- : '1';
+std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request,
+ bool use_single_keyed_cache) {
+ // The first character of the key may vary depending on whether or not sending
+ // credentials is permitted for this request. This only happens if the
+ // SplitCacheByIncludeCredentials feature is enabled, or if the single-keyed
+ // cache is enabled. The single-keyed cache must always be split by
+ // credentials in order to make coep:credentialless work safely.
+ const char credential_key =
+ ((base::FeatureList::IsEnabled(
+ features::kSplitCacheByIncludeCredentials) ||
+ use_single_keyed_cache) &&
+ (request->load_flags & LOAD_DO_NOT_SAVE_COOKIES))
+ ? '0'
+ : '1';
const int64_t post_key = request->upload_data_stream
? request->upload_data_stream->identifier()
: int64_t(0);
std::string isolation_key;
- if (IsSplitCacheEnabled()) {
+ if (use_single_keyed_cache) {
+ DCHECK(IsSplitCacheEnabled());
+ DCHECK(!request->checksum.empty());
+ DCHECK(!(request->load_flags &
+ (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE |
+ net::LOAD_SKIP_CACHE_VALIDATION | net::LOAD_ONLY_FROM_CACHE |
+ net::LOAD_DISABLE_CACHE | net::LOAD_SKIP_VARY_CHECK)));
+ isolation_key = base::StrCat(
+ {kSingleKeyPrefix, request->checksum, kSingleKeySeparator});
+ } else if (IsSplitCacheEnabled()) {
// Prepend the key with |kDoubleKeyPrefix| = "_dk_" to mark it as
// double-keyed (and makes it an invalid url so that it doesn't get
// confused with a single-keyed entry). Separate the origin and url
@@ -686,7 +700,11 @@ void HttpCache::DoomMainEntryForUrl(const GURL& url,
temp_info.method = "GET";
temp_info.network_isolation_key = isolation_key;
temp_info.is_subframe_document_resource = is_subframe_document_resource;
- std::string key = GenerateCacheKey(&temp_info);
+ // This method is always used for "POST" requests, which never use the
+ // single-keyed cache, so therefore it is correct that use_single_keyed_cache
+ // be false.
+ std::string key =
+ GenerateCacheKey(&temp_info, /*use_single_keyed_cache=*/false);
// Defer to DoomEntry if there is an active entry, otherwise call
// AsyncDoomEntry without triggering a callback.
@@ -720,7 +738,6 @@ HttpCache::ActiveEntry* HttpCache::ActivateEntry(disk_cache::Entry* disk_entry,
void HttpCache::DeactivateEntry(ActiveEntry* entry) {
DCHECK(!entry->doomed);
- DCHECK(entry->disk_entry);
DCHECK(entry->SafeToDestroy());
std::string key = entry->disk_entry->GetKey();
@@ -1144,8 +1161,6 @@ void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
ParallelWritingPattern parallel_writing_pattern =
CanTransactionJoinExistingWriters(transaction);
if (IsWritingInProgress(entry)) {
- transaction->MaybeSetParallelWritingPatternForMetrics(
- parallel_writing_pattern);
if (parallel_writing_pattern != PARALLEL_WRITING_JOIN) {
// TODO(shivanisha): Returning from here instead of checking the next
// transaction in the queue because the FIFO order is maintained
@@ -1172,14 +1187,10 @@ void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
transaction->WriteModeTransactionAboutToBecomeReader();
auto return_val = entry->readers.insert(transaction);
DCHECK(return_val.second);
- transaction->MaybeSetParallelWritingPatternForMetrics(
- PARALLEL_WRITING_NONE_CACHE_READ);
}
} else { // mode READ
auto return_val = entry->readers.insert(transaction);
DCHECK(return_val.second);
- transaction->MaybeSetParallelWritingPatternForMetrics(
- PARALLEL_WRITING_NONE_CACHE_READ);
}
}
@@ -1197,8 +1208,6 @@ void HttpCache::AddTransactionToWriters(
ParallelWritingPattern parallel_writing_pattern) {
if (!entry->writers) {
entry->writers = std::make_unique<Writers>(this, entry);
- transaction->MaybeSetParallelWritingPatternForMetrics(
- PARALLEL_WRITING_CREATE);
} else {
ParallelWritingPattern writers_pattern;
DCHECK(entry->writers->CanAddWriters(&writers_pattern));
@@ -1345,15 +1354,8 @@ void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
// wait till the response is complete. If the response is not yet started, the
// done_headers_queue transaction should start writing it.
if (!entry->done_headers_queue.empty()) {
- ParallelWritingPattern reason = PARALLEL_WRITING_NONE;
- if (entry->writers && !entry->writers->CanAddWriters(&reason)) {
- if (reason != PARALLEL_WRITING_NONE) {
- for (auto* done_headers_transaction : entry->done_headers_queue) {
- done_headers_transaction->MaybeSetParallelWritingPatternForMetrics(
- reason);
- }
- }
- } else {
+ ParallelWritingPattern unused_reason;
+ if (!entry->writers || entry->writers->CanAddWriters(&unused_reason)) {
ProcessDoneHeadersQueue(entry);
return;
}
@@ -1380,6 +1382,7 @@ void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
// Anything after a Doom has to be restarted.
try_restart_requests = true;
} else if (item->IsValid()) {
+ DCHECK(pending_op->entry);
key = pending_op->entry->GetKey();
entry = ActivateEntry(pending_op->entry, pending_op->entry_opened);
} else {
@@ -1404,8 +1407,7 @@ void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
// to move the callback used to be a CancelableOnceCallback. By the way, for
// this to happen the action (to cancel B) has to be synchronous to the
// notification for request A.
- WorkItemList pending_items;
- pending_items.swap(pending_op->pending_queue);
+ WorkItemList pending_items = std::move(pending_op->pending_queue);
DeletePendingOp(pending_op);
item->NotifyTransaction(result, entry);
diff --git a/chromium/net/http/http_cache.h b/chromium/net/http/http_cache.h
index 6dcf81a1bed..c97adfe07fa 100644
--- a/chromium/net/http/http_cache.h
+++ b/chromium/net/http/http_cache.h
@@ -47,6 +47,7 @@ class ApplicationStatusListener;
namespace disk_cache {
class Backend;
+class BackendFileOperationsFactory;
class Entry;
class EntryResult;
} // namespace disk_cache
@@ -94,10 +95,14 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
// A default backend factory for the common use cases.
class NET_EXPORT DefaultBackend : public BackendFactory {
public:
- // |path| is the destination for any files used by the backend. If
- // |max_bytes| is zero, a default value will be calculated automatically.
+ // `file_operations_factory` can be null, in that case
+ // TrivialFileOperationsFactory is used. `path` is the destination for any
+ // files used by the backend. If `max_bytes` is zero, a default value
+ // will be calculated automatically.
DefaultBackend(CacheType type,
BackendType backend_type,
+ scoped_refptr<disk_cache::BackendFileOperationsFactory>
+ file_operations_factory,
const base::FilePath& path,
int max_bytes,
bool hard_reset);
@@ -119,6 +124,8 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
private:
CacheType type_;
BackendType backend_type_;
+ const scoped_refptr<disk_cache::BackendFileOperationsFactory>
+ file_operations_factory_;
const base::FilePath path_;
int max_bytes_;
bool hard_reset_;
@@ -164,26 +171,10 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
// again without validation.
static const int kPrefetchReuseMins = 5;
- // The disk cache is initialized lazily (by CreateTransaction) in this case.
- // Provide an existing HttpNetworkSession, the cache can construct a
- // network layer with a shared HttpNetworkSession in order for multiple
- // network layers to share information (e.g. authentication data). The
- // HttpCache takes ownership of the |backend_factory|.
- //
- // The HttpCache must be destroyed before the HttpNetworkSession.
- //
- // If |is_main_cache| is true, configures the cache to track
- // information about servers supporting QUIC.
- // TODO(zhongyi): remove |is_main_cache| when we get rid of cache split.
- HttpCache(HttpNetworkSession* session,
- std::unique_ptr<BackendFactory> backend_factory,
- bool is_main_cache);
-
// Initialize the cache from its component parts. |network_layer| and
// |backend_factory| will be destroyed when the HttpCache is.
HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
- std::unique_ptr<BackendFactory> backend_factory,
- bool is_main_cache);
+ std::unique_ptr<BackendFactory> backend_factory);
HttpCache(const HttpCache&) = delete;
HttpCache& operator=(const HttpCache&) = delete;
@@ -369,7 +360,7 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
bool TransactionInReaders(Transaction* transaction) const;
- raw_ptr<disk_cache::Entry> disk_entry = nullptr;
+ const raw_ptr<disk_cache::Entry> disk_entry;
// Indicates if the disk_entry was opened or not (i.e.: created).
// It is set to true when a transaction is added to an entry so that other,
@@ -429,7 +420,8 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
int GetBackendForTransaction(Transaction* transaction);
// Generates the cache key for this request.
- static std::string GenerateCacheKey(const HttpRequestInfo*);
+ static std::string GenerateCacheKey(const HttpRequestInfo*,
+ bool use_single_keyed_cache);
// Dooms the entry selected by |key|, if it is currently in the list of active
// entries.
@@ -654,18 +646,22 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory {
static const char kDoubleKeySeparator[];
static const char kSubframeDocumentResourcePrefix[];
+ // Used for single-keyed entries if the cache is split.
+ static const char kSingleKeyPrefix[];
+ static const char kSingleKeySeparator[];
+
// Variables ----------------------------------------------------------------
raw_ptr<NetLog> net_log_;
// Used when lazily constructing the disk_cache_.
std::unique_ptr<BackendFactory> backend_factory_;
- bool building_backend_;
- bool bypass_lock_for_test_;
- bool bypass_lock_after_headers_for_test_;
- bool fail_conditionalization_for_test_;
+ bool building_backend_ = false;
+ bool bypass_lock_for_test_ = false;
+ bool bypass_lock_after_headers_for_test_ = false;
+ bool fail_conditionalization_for_test_ = false;
- Mode mode_;
+ Mode mode_ = NORMAL;
std::unique_ptr<HttpTransactionFactory> network_layer_;
diff --git a/chromium/net/http/http_cache_lookup_manager.cc b/chromium/net/http/http_cache_lookup_manager.cc
index 3f71c650c1b..6ed9cd0d36e 100644
--- a/chromium/net/http/http_cache_lookup_manager.cc
+++ b/chromium/net/http/http_cache_lookup_manager.cc
@@ -30,7 +30,6 @@ HttpCacheLookupManager::LookupTransaction::LookupTransaction(
NetLog* net_log)
: push_helper_(std::move(server_push_helper)),
request_(new HttpRequestInfo()),
- transaction_(nullptr),
net_log_(NetLogWithSource::Make(
net_log,
NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION)) {}
diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc
index 6bb6deaafdb..764fd4d65bc 100644
--- a/chromium/net/http/http_cache_transaction.cc
+++ b/chromium/net/http/http_cache_transaction.cc
@@ -19,6 +19,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
+#include "base/containers/fixed_flat_set.h"
#include "base/cxx17_backports.h"
#include "base/format_macros.h"
#include "base/location.h"
@@ -27,13 +28,15 @@
#include "base/power_monitor/power_monitor.h"
#include "base/strings/string_number_conversions.h" // For HexEncode.
#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h" // For LowerCaseEqualsASCII.
+#include "base/strings/string_util.h" // For EqualsCaseInsensitiveASCII.
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
#include "net/base/auth.h"
#include "net/base/cache_metrics.h"
#include "net/base/features.h"
@@ -49,6 +52,7 @@
#include "net/http/http_log_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
+#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/http/webfonts_histogram.h"
#include "net/log/net_log_event_type.h"
@@ -87,6 +91,12 @@ enum ExternallyConditionalizedType {
EXTERNALLY_CONDITIONALIZED_MAX
};
+void RecordPervasivePayloadIndex(const char* histogram_name, int index) {
+ if (index != -1) {
+ base::UmaHistogramExactLinear(histogram_name, index, 101);
+ }
+}
+
} // namespace
#define CACHE_STATUS_HISTOGRAMS(type) \
@@ -141,7 +151,7 @@ static bool HeaderMatches(const HttpRequestHeaders& headers,
HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ',');
while (v.GetNext()) {
- if (base::LowerCaseEqualsASCII(v.value_piece(), search->value))
+ if (base::EqualsCaseInsensitiveASCII(v.value_piece(), search->value))
return true;
}
}
@@ -151,40 +161,8 @@ static bool HeaderMatches(const HttpRequestHeaders& headers,
//-----------------------------------------------------------------------------
HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
- : initial_request_(nullptr),
- request_(nullptr),
- priority_(priority),
- cache_(cache->GetWeakPtr()),
- entry_(nullptr),
- new_entry_(nullptr),
- new_response_(nullptr),
- mode_(NONE),
- reading_(false),
- invalid_range_(false),
- truncated_(false),
- is_sparse_(false),
- range_requested_(false),
- handling_206_(false),
- cache_pending_(false),
- done_headers_create_new_entry_(false),
- vary_mismatch_(false),
- couldnt_conditionalize_request_(false),
- bypass_lock_for_test_(false),
- bypass_lock_after_headers_for_test_(false),
- fail_conditionalization_for_test_(false),
- read_buf_len_(0),
- io_buf_len_(0),
- read_offset_(0),
- effective_load_flags_(0),
- shared_writing_error_(OK),
- cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED),
- validation_cause_(VALIDATION_CAUSE_UNDEFINED),
- recorded_histograms_(false),
- parallel_writing_pattern_(PARALLEL_WRITING_NONE),
- moved_network_transaction_to_writers_(false),
- websocket_handshake_stream_base_create_helper_(nullptr),
- in_do_loop_(false) {
- TRACE_EVENT1("io", "HttpCacheTransaction::Transaction", "priority",
+ : priority_(priority), cache_(cache->GetWeakPtr()) {
+ TRACE_EVENT1("net", "HttpCacheTransaction::Transaction", "priority",
RequestPriorityToString(priority));
static_assert(HttpCache::Transaction::kNumValidationHeaders ==
std::size(kValidationHeaders),
@@ -195,7 +173,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
}
HttpCache::Transaction::~Transaction() {
- TRACE_EVENT0("io", "HttpCacheTransaction::~Transaction");
+ TRACE_EVENT0("net", "HttpCacheTransaction::~Transaction");
RecordHistograms();
// We may have to issue another IO, but we should never invoke the callback_
@@ -233,9 +211,9 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
const NetLogWithSource& net_log) {
DCHECK(request);
DCHECK(!callback.is_null());
- TRACE_EVENT_WITH_FLOW1("io", "HttpCacheTransaction::Start",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::Start",
net_log.source().id, TRACE_EVENT_FLAG_FLOW_OUT, "url",
- request->url);
+ request->url.spec());
// Ensure that we only have one asynchronous call at a time.
DCHECK(callback_.is_null());
@@ -632,6 +610,10 @@ void HttpCache::Transaction::SetValidatingCannotProceed() {
}
void HttpCache::Transaction::WriterAboutToBeRemovedFromEntry(int result) {
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::WriterAboutToBeRemovedFromEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
// Since the transaction can no longer access the network transaction, save
// all network related info now.
if (moved_network_transaction_to_writers_ &&
@@ -650,6 +632,10 @@ void HttpCache::Transaction::WriterAboutToBeRemovedFromEntry(int result) {
}
void HttpCache::Transaction::WriteModeTransactionAboutToBecomeReader() {
+ TRACE_EVENT_WITH_FLOW0(
+ "net", "HttpCacheTransaction::WriteModeTransactionAboutToBecomeReader",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
mode_ = READ;
if (moved_network_transaction_to_writers_ &&
entry_->writers->network_transaction()) {
@@ -657,13 +643,23 @@ void HttpCache::Transaction::WriteModeTransactionAboutToBecomeReader() {
}
}
-void HttpCache::Transaction::MaybeSetParallelWritingPatternForMetrics(
- HttpCache::ParallelWritingPattern pattern) {
- // It's possible a transaction could not join existing writers and then
- // creates a new writers. In that case the original reason for not being able
- // to join writers should be logged.
- if (parallel_writing_pattern_ == PARALLEL_WRITING_NONE)
- parallel_writing_pattern_ = pattern;
+bool HttpCache::Transaction::ResponseChecksumMatches(
+ std::unique_ptr<crypto::SecureHash> checksum) const {
+ DCHECK(checksum);
+ uint8_t result[crypto::kSHA256Length];
+ checksum->Finish(result, crypto::kSHA256Length);
+ const std::string hex_result = base::HexEncode(result);
+ if (hex_result != request_->checksum) {
+ DVLOG(2) << "Pervasive payload checksum mismatch for \"" << request_->url
+ << "\": got " << hex_result << ", expected " << request_->checksum;
+ RecordPervasivePayloadIndex("Network.CacheTransparency.MismatchedChecksums",
+ request_->pervasive_payloads_index_for_logging);
+ return false;
+ }
+ RecordPervasivePayloadIndex(
+ "Network.CacheTransparency.SingleKeyedCacheIsUsed",
+ request_->pervasive_payloads_index_for_logging);
+ return true;
}
//-----------------------------------------------------------------------------
@@ -980,6 +976,13 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_NETWORK_READ_COMPLETE:
rv = DoNetworkReadComplete(rv);
break;
+ case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
+ DCHECK_EQ(0, rv); // Here "rv" is a count of bytes.
+ rv = DoMarkSingleKeyedCacheEntryUnusable();
+ break;
+ case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
+ rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
+ break;
default:
NOTREACHED() << "bad state " << state;
rv = ERR_FAILED;
@@ -1020,7 +1023,12 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) {
mode_ = NONE;
if (!ShouldPassThrough()) {
- cache_key_ = cache_->GenerateCacheKey(request_);
+ // The flag LOAD_USE_SINGLE_KEYED_CACHE will have been changed to false if
+ // the entry was marked unusable and the transaction was restarted in
+ // DoCacheReadResponseComplete(), so it will no longer match the value in
+ // `request_`. So we pass it through explicitly.
+ cache_key_ = cache_->GenerateCacheKey(
+ request_, effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE);
// Requested cache access mode.
if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
@@ -1086,7 +1094,7 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) {
}
int HttpCache::Transaction::DoInitEntry() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoInitEntry",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoInitEntry",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
@@ -1106,7 +1114,7 @@ int HttpCache::Transaction::DoInitEntry() {
}
int HttpCache::Transaction::DoOpenOrCreateEntry() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoOpenOrCreateEntry",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoOpenOrCreateEntry",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
@@ -1114,6 +1122,9 @@ int HttpCache::Transaction::DoOpenOrCreateEntry() {
cache_pending_ = true;
net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_OR_CREATE_ENTRY);
first_cache_access_since_ = TimeTicks::Now();
+ const bool has_opened_or_created_entry = has_opened_or_created_entry_;
+ has_opened_or_created_entry_ = true;
+ record_entry_open_or_creation_time_ = false;
// See if we already have something working with this cache key.
new_entry_ = cache_->FindActiveEntry(cache_key_);
@@ -1142,6 +1153,10 @@ int HttpCache::Transaction::DoOpenOrCreateEntry() {
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
}
+ if (!has_opened_or_created_entry) {
+ record_entry_open_or_creation_time_ = true;
+ }
+
// mode_ can be anything but NONE or WRITE at this point (READ, UPDATE, or
// READ_WRITE).
// READ, UPDATE, certain READ_WRITEs, and some methods shouldn't create, so
@@ -1159,10 +1174,18 @@ int HttpCache::Transaction::DoOpenOrCreateEntry() {
}
int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io",
- "HttpCacheTransaction::DoOpenOrCreateEntryComplete",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoOpenOrCreateEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result",
+ (result == OK ? (new_entry_->opened ? "opened" : "created") : "failed"));
+
+ const bool record_uma =
+ record_entry_open_or_creation_time_ && cache_ &&
+ cache_->GetCurrentBackend() &&
+ cache_->GetCurrentBackend()->GetCacheType() != MEMORY_CACHE;
+ record_entry_open_or_creation_time_ = false;
+
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
@@ -1172,7 +1195,19 @@ int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
cache_pending_ = false;
if (result == OK) {
- if (new_entry_->opened == false) {
+ if (new_entry_->opened) {
+ if (record_uma) {
+ base::UmaHistogramTimes(
+ "HttpCache.OpenDiskEntry",
+ base::TimeTicks::Now() - first_cache_access_since_);
+ }
+ } else {
+ if (record_uma) {
+ base::UmaHistogramTimes(
+ "HttpCache.CreateDiskEntry",
+ base::TimeTicks::Now() - first_cache_access_since_);
+ }
+
// Entry was created so mode changes to WRITE.
mode_ = WRITE;
}
@@ -1230,7 +1265,7 @@ int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
}
int HttpCache::Transaction::DoDoomEntry() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoDoomEntry",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoDoomEntry",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_DOOM_ENTRY_COMPLETE);
@@ -1242,9 +1277,9 @@ int HttpCache::Transaction::DoDoomEntry() {
}
int HttpCache::Transaction::DoDoomEntryComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoDoomEntryComplete",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoDoomEntryComplete", net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
result);
cache_pending_ = false;
@@ -1255,7 +1290,7 @@ int HttpCache::Transaction::DoDoomEntryComplete(int result) {
}
int HttpCache::Transaction::DoCreateEntry() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCreateEntry",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCreateEntry",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
@@ -1266,9 +1301,10 @@ int HttpCache::Transaction::DoCreateEntry() {
}
int HttpCache::Transaction::DoCreateEntryComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCreateEntryComplete",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoCreateEntryComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result);
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
@@ -1308,7 +1344,7 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) {
}
int HttpCache::Transaction::DoAddToEntry() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoAddToEntry",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoAddToEntry",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(new_entry_);
@@ -1384,9 +1420,10 @@ void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) {
}
int HttpCache::Transaction::DoAddToEntryComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoAddToEntryComplete",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoAddToEntryComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY,
result);
const base::TimeDelta entry_lock_wait =
@@ -1450,6 +1487,10 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) {
}
int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoDoneHeadersAddToEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
// This transaction's response headers did not match its ActiveEntry so it
// created a new ActiveEntry (new_entry_) to write to (and doomed the old
// one). Now that the new entry has been created, start writing the response.
@@ -1470,7 +1511,7 @@ int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
}
entry_ = new_entry_;
- DCHECK_NE(response_.headers->response_code(), 304);
+ DCHECK_NE(response_.headers->response_code(), net::HTTP_NOT_MODIFIED);
DCHECK(cache_->CanTransactionWriteResponseHeaders(
entry_, this, partial_ != nullptr, false));
TransitionToState(STATE_CACHE_WRITE_RESPONSE);
@@ -1478,7 +1519,7 @@ int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
}
int HttpCache::Transaction::DoCacheReadResponse() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadResponse",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCacheReadResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(entry_);
@@ -1493,10 +1534,11 @@ int HttpCache::Transaction::DoCacheReadResponse() {
}
int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io",
+ TRACE_EVENT_WITH_FLOW2("net",
"HttpCacheTransaction::DoCacheReadResponseComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result, "io_buf_len", io_buf_len_);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_INFO,
result);
@@ -1508,6 +1550,25 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
return OnCacheReadError(result, true);
}
+ if (response_.single_keyed_cache_entry_unusable) {
+ RecordPervasivePayloadIndex("Network.CacheTransparency.MarkedUnusable",
+ request_->pervasive_payloads_index_for_logging);
+
+ // We've read the single keyed entry and it turned out to be unusable. Let's
+ // retry reading from the split cache.
+ if (effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE) {
+ DCHECK(!network_trans_);
+ effective_load_flags_ &= ~LOAD_USE_SINGLE_KEYED_CACHE;
+ DoneWithEntryForRestartWithCache();
+ TransitionToState(STATE_GET_BACKEND);
+ return OK;
+ } else {
+ LOG(WARNING) << "Unusable flag set on non-single-keyed cache entry; "
+ << "possible disk corruption? (cache key: " << cache_key_
+ << ")";
+ }
+ }
+
// TODO(crbug.com/713354) Only get data size if there is no other transaction
// currently writing the response body due to the data race mentioned in the
// associated bug.
@@ -1525,7 +1586,8 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
// the following logic is put in place to defer such requests to the
// network. The cache should not be storing multi gigabyte resources. See
// http://crbug.com/89567.
- if ((truncated_ || response_.headers->response_code() == 206) &&
+ if ((truncated_ ||
+ response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT) &&
!range_requested_ &&
full_response_length > std::numeric_limits<int32_t>::max()) {
DCHECK(!partial_);
@@ -1575,7 +1637,7 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {
TRACE_EVENT_WITH_FLOW0(
- "io", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponse",
+ "net", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(updated_prefetch_response_);
@@ -1589,7 +1651,8 @@ int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {
int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponseComplete(
int result) {
TRACE_EVENT_WITH_FLOW0(
- "io", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponseComplete",
+ "net",
+ "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponseComplete",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
updated_prefetch_response_.reset();
@@ -1598,7 +1661,7 @@ int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponseComplete(
}
int HttpCache::Transaction::DoCacheDispatchValidation() {
- TRACE_EVENT_WITH_FLOW0("io",
+ TRACE_EVENT_WITH_FLOW0("net",
"HttpCacheTransaction::DoCacheDispatchValidation",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
@@ -1694,7 +1757,7 @@ int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {
TRACE_EVENT_WITH_FLOW0(
- "io", "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeout",
+ "net", "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeout",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
response_.stale_revalidate_timeout =
@@ -1706,7 +1769,7 @@ int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {
int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete(
int result) {
TRACE_EVENT_WITH_FLOW0(
- "io",
+ "net",
"HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
@@ -1716,7 +1779,7 @@ int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete(
}
int HttpCache::Transaction::DoSendRequest() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoSendRequest",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoSendRequest",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(mode_ & WRITE || mode_ == NONE);
@@ -1755,9 +1818,10 @@ int HttpCache::Transaction::DoSendRequest() {
}
int HttpCache::Transaction::DoSendRequestComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoSendRequestComplete",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoSendRequestComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result);
if (!cache_.get()) {
TransitionToState(STATE_FINISH_HEADERS);
return ERR_UNEXPECTED;
@@ -1802,14 +1866,15 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
// We received the response headers and there is no error.
int HttpCache::Transaction::DoSuccessfulSendRequest() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoSuccessfulSendRequest",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoSuccessfulSendRequest",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_response_);
const HttpResponseInfo* new_response = network_trans_->GetResponseInfo();
- if (new_response->headers->response_code() == 401 ||
- new_response->headers->response_code() == 407) {
+ if (new_response->headers->response_code() == net::HTTP_UNAUTHORIZED ||
+ new_response->headers->response_code() ==
+ net::HTTP_PROXY_AUTHENTICATION_REQUIRED) {
SetAuthResponse(*new_response);
if (!reading_) {
TransitionToState(STATE_FINISH_HEADERS);
@@ -1840,6 +1905,17 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
return ERR_CACHE_AUTH_FAILURE_AFTER_READ;
}
+ // The single-keyed cache only accepts responses with code 200 or 304.
+ // Anything else is considered unusable.
+ if ((effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE) &&
+ !(new_response->headers->response_code() == 200 ||
+ new_response->headers->response_code() == 304)) {
+ // Either the new response will be written back to the cache, in which case
+ // it will not be reused due to the flag, or it will not be, in which case
+ // it will not be reused anyway.
+ mark_single_keyed_cache_entry_unusable_ = true;
+ }
+
new_response_ = new_response;
if (!ValidatePartialResponse() && !auth_response_.headers.get()) {
// Something went wrong with this request and we have to restart it.
@@ -1890,7 +1966,8 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
request_->is_subframe_document_resource);
}
- if (new_response_->headers->response_code() == 416 &&
+ if (new_response_->headers->response_code() ==
+ net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE &&
(method_ == "GET" || method_ == "POST")) {
// If there is an active entry it may be destroyed with this transaction.
SetResponse(*new_response_);
@@ -1900,7 +1977,8 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// Are we expecting a response to a conditional query?
if (mode_ == READ_WRITE || mode_ == UPDATE) {
- if (new_response->headers->response_code() == 304 || handling_206_) {
+ if (new_response->headers->response_code() == net::HTTP_NOT_MODIFIED ||
+ handling_206_) {
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_VALIDATED);
TransitionToState(STATE_UPDATE_CACHED_RESPONSE);
return OK;
@@ -1915,7 +1993,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// We received 304 or 206 and we want to update the cached response headers.
int HttpCache::Transaction::DoUpdateCachedResponse() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoUpdateCachedResponse",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoUpdateCachedResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
int rv = OK;
@@ -1930,6 +2008,12 @@ int HttpCache::Transaction::DoUpdateCachedResponse() {
response_.restricted_prefetch = new_response_->restricted_prefetch;
response_.ssl_info = new_response_->ssl_info;
response_.dns_aliases = new_response_->dns_aliases;
+
+ // Be careful never to set single_keyed_cache_entry_unusable back to false
+ // from true.
+ if (mark_single_keyed_cache_entry_unusable_) {
+ response_.single_keyed_cache_entry_unusable = true;
+ }
if (new_response_->vary_data.is_valid()) {
response_.vary_data = new_response_->vary_data;
} else if (response_.vary_data.is_valid()) {
@@ -1947,6 +2031,11 @@ int HttpCache::Transaction::DoUpdateCachedResponse() {
}
TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
} else {
+ if (effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE) {
+ DCHECK_EQ(method_, "GET");
+ ChecksumHeaders();
+ }
+
// If we are already reading, we already updated the headers for this
// request; doing it again will change Content-Length.
if (!reading_) {
@@ -1961,7 +2050,7 @@ int HttpCache::Transaction::DoUpdateCachedResponse() {
}
int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {
- TRACE_EVENT_WITH_FLOW0("io",
+ TRACE_EVENT_WITH_FLOW0("net",
"HttpCacheTransaction::DoCacheWriteUpdatedResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
@@ -1971,7 +2060,7 @@ int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {
int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {
TRACE_EVENT_WITH_FLOW0(
- "io", "HttpCacheTransaction::DoCacheWriteUpdatedResponseComplete",
+ "net", "HttpCacheTransaction::DoCacheWriteUpdatedResponseComplete",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
@@ -1979,10 +2068,10 @@ int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {
}
int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io",
- "HttpCacheTransaction::DoUpdateCachedResponseComplete",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoUpdateCachedResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
if (mode_ == UPDATE) {
DCHECK(!handling_206_);
// We got a "not modified" response and already updated the corresponding
@@ -2018,7 +2107,7 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
}
int HttpCache::Transaction::DoOverwriteCachedResponse() {
- TRACE_EVENT_WITH_FLOW0("io",
+ TRACE_EVENT_WITH_FLOW0("net",
"HttpCacheTransaction::DoOverwriteCachedResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
@@ -2033,6 +2122,11 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() {
SetResponse(*new_response_);
+ if (effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE) {
+ DCHECK_EQ(method_, "GET");
+ ChecksumHeaders();
+ }
+
if (method_ == "HEAD") {
// This response is replacing the cached one.
DoneWithEntry(false);
@@ -2056,16 +2150,16 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() {
}
int HttpCache::Transaction::DoCacheWriteResponse() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheWriteResponse",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCacheWriteResponse",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ DCHECK(response_.headers);
// Invalidate any current entry with a successful response if this transaction
// cannot write to this entry. This transaction then continues to read from
// the network without writing to the backend.
- bool is_match = response_.headers->response_code() == 304;
- if (entry_ && response_.headers &&
- !cache_->CanTransactionWriteResponseHeaders(
- entry_, this, partial_ != nullptr, is_match)) {
+ bool is_match = response_.headers->response_code() == net::HTTP_NOT_MODIFIED;
+ if (entry_ && !cache_->CanTransactionWriteResponseHeaders(
+ entry_, this, partial_ != nullptr, is_match)) {
done_headers_create_new_entry_ = true;
// The transaction needs to overwrite this response. Doom the current entry,
@@ -2080,21 +2174,27 @@ int HttpCache::Transaction::DoCacheWriteResponse() {
return OK;
}
+ // Be careful never to set single_keyed_cache_entry_unusable back to false
+ // from true.
+ if (mark_single_keyed_cache_entry_unusable_) {
+ response_.single_keyed_cache_entry_unusable = true;
+ }
+
TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
return WriteResponseInfoToEntry(response_, truncated_);
}
int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io",
- "HttpCacheTransaction::DoCacheWriteResponseComplete",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoCacheWriteResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
TransitionToState(STATE_TRUNCATE_CACHED_DATA);
return OnWriteResponseInfoToEntryComplete(result);
}
int HttpCache::Transaction::DoTruncateCachedData() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoTruncateCachedData",
+ TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoTruncateCachedData",
net_log().source().id,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_TRUNCATE_CACHED_DATA_COMPLETE);
@@ -2102,14 +2202,16 @@ int HttpCache::Transaction::DoTruncateCachedData() {
return OK;
net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_DATA);
// Truncate the stream.
- return WriteToEntry(kResponseContentIndex, 0, nullptr, 0, io_callback_);
+ return entry_->disk_entry->WriteData(kResponseContentIndex, /*offset=*/0,
+ /*buf=*/nullptr, /*buf_len=*/0,
+ io_callback_, /*truncate=*/true);
}
int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io",
- "HttpCacheTransaction::DoTruncateCachedDataComplete",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoTruncateCachedDataComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
if (entry_) {
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_DATA,
result);
@@ -2160,6 +2262,9 @@ int HttpCache::Transaction::DoHeadersPhaseCannotProceed(int result) {
}
int HttpCache::Transaction::DoFinishHeaders(int result) {
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoFinishHeaders", net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
if (!cache_.get() || !entry_ || result != OK) {
TransitionToState(STATE_NONE);
return result;
@@ -2190,6 +2295,10 @@ int HttpCache::Transaction::DoFinishHeaders(int result) {
}
int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoFinishHeadersComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", rv);
entry_lock_waiting_since_ = TimeTicks();
if (rv == ERR_CACHE_RACE || rv == ERR_CACHE_LOCK_TIMEOUT) {
TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
@@ -2197,7 +2306,8 @@ int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
}
if (network_trans_ && InWriters()) {
- entry_->writers->SetNetworkTransaction(this, std::move(network_trans_));
+ entry_->writers->SetNetworkTransaction(this, std::move(network_trans_),
+ std::move(checksum_));
moved_network_transaction_to_writers_ = true;
}
@@ -2214,19 +2324,21 @@ int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
}
int HttpCache::Transaction::DoNetworkReadCacheWrite() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkReadCacheWrite",
+ TRACE_EVENT_WITH_FLOW2("net", "HttpCacheTransaction::DoNetworkReadCacheWrite",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "read_offset", read_offset_, "read_buf_len",
+ read_buf_len_);
DCHECK(InWriters());
TransitionToState(STATE_NETWORK_READ_CACHE_WRITE_COMPLETE);
return entry_->writers->Read(read_buf_, read_buf_len_, io_callback_, this);
}
int HttpCache::Transaction::DoNetworkReadCacheWriteComplete(int result) {
- TRACE_EVENT_WITH_FLOW0(
- "io", "HttpCacheTransaction::DoNetworkReadCacheWriteComplete",
+ TRACE_EVENT_WITH_FLOW1(
+ "net", "HttpCacheTransaction::DoNetworkReadCacheWriteComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
if (!cache_.get()) {
TransitionToState(STATE_NONE);
return ERR_UNEXPECTED;
@@ -2253,6 +2365,8 @@ int HttpCache::Transaction::DoNetworkReadCacheWriteComplete(int result) {
DCHECK(!entry_);
} else {
read_offset_ += result;
+ if (checksum_)
+ checksum_->Update(read_buf_->data(), result);
}
TransitionToState(STATE_NONE);
return result;
@@ -2293,17 +2407,19 @@ int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
}
int HttpCache::Transaction::DoNetworkRead() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkRead",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW2(
+ "net", "HttpCacheTransaction::DoNetworkRead", net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "read_offset",
+ read_offset_, "read_buf_len", read_buf_len_);
TransitionToState(STATE_NETWORK_READ_COMPLETE);
return network_trans_->Read(read_buf_.get(), read_buf_len_, io_callback_);
}
int HttpCache::Transaction::DoNetworkReadComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkReadComplete",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoNetworkReadComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result);
if (!cache_.get()) {
TransitionToState(STATE_NONE);
@@ -2318,9 +2434,10 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) {
}
int HttpCache::Transaction::DoCacheReadData() {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadData",
- net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW2(
+ "net", "HttpCacheTransaction::DoCacheReadData", net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "read_offset",
+ read_offset_, "read_buf_len", read_buf_len_);
if (method_ == "HEAD") {
TransitionToState(STATE_NONE);
@@ -2342,9 +2459,10 @@ int HttpCache::Transaction::DoCacheReadData() {
}
int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
- TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadDataComplete",
+ TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoCacheReadDataComplete",
net_log().source().id,
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "result", result);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_DATA,
result);
@@ -2362,7 +2480,14 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
if (result > 0) {
read_offset_ += result;
+ if (checksum_)
+ checksum_->Update(read_buf_->data(), result);
} else if (result == 0) { // End of file.
+ if (!FinishAndCheckChecksum()) {
+ TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE);
+ return result;
+ }
+
DoneWithEntry(true);
} else {
return OnCacheReadError(result, false);
@@ -2372,6 +2497,25 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
return result;
}
+int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusable() {
+ DCHECK(effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE);
+ response_.single_keyed_cache_entry_unusable = true;
+ TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE);
+ return WriteResponseInfoToEntry(response_, /*truncated=*/false);
+}
+
+int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusableComplete(
+ int result) {
+ DCHECK_NE(result, ERR_IO_PENDING);
+ TransitionToState(STATE_NONE);
+ DoneWithEntry(/*entry_is_complete=*/true);
+ if (result < 0)
+ return result;
+
+ // Return 0 to indicate that we've finished reading the body.
+ return 0;
+}
+
//-----------------------------------------------------------------------------
void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {
@@ -2532,7 +2676,8 @@ bool HttpCache::Transaction::ShouldPassThrough() {
int HttpCache::Transaction::BeginCacheRead() {
// We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
// TODO(jkarlin): Either handle this case or DCHECK.
- if (response_.headers->response_code() == 206 || partial_) {
+ if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT ||
+ partial_) {
NOTREACHED();
TransitionToState(STATE_FINISH_HEADERS);
return ERR_CACHE_MISS;
@@ -2573,8 +2718,8 @@ int HttpCache::Transaction::BeginCacheValidation() {
response_.stale_revalidate_timeout.is_null();
}
- if (method_ == "HEAD" &&
- (truncated_ || response_.headers->response_code() == 206)) {
+ if (method_ == "HEAD" && (truncated_ || response_.headers->response_code() ==
+ net::HTTP_PARTIAL_CONTENT)) {
DCHECK(!partial_);
if (skip_validation) {
DCHECK(!reading_);
@@ -2638,7 +2783,7 @@ int HttpCache::Transaction::BeginCacheValidation() {
if (partial_)
return DoRestartPartialRequest();
- DCHECK_NE(206, response_.headers->response_code());
+ DCHECK_NE(net::HTTP_PARTIAL_CONTENT, response_.headers->response_code());
}
TransitionToState(STATE_SEND_REQUEST);
}
@@ -2648,7 +2793,8 @@ int HttpCache::Transaction::BeginCacheValidation() {
int HttpCache::Transaction::BeginPartialCacheValidation() {
DCHECK_EQ(mode_, READ_WRITE);
- if (response_.headers->response_code() != 206 && !partial_ && !truncated_)
+ if (response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT &&
+ !partial_ && !truncated_)
return BeginCacheValidation();
// Partial requests should not be recorded in histograms.
@@ -2681,7 +2827,7 @@ int HttpCache::Transaction::ValidateEntryHeadersAndContinue() {
return DoRestartPartialRequest();
}
- if (response_.headers->response_code() == 206)
+ if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT)
is_sparse_ = true;
if (!partial_->IsRequestedRangeOK()) {
@@ -2718,7 +2864,7 @@ bool HttpCache::Transaction::
int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
DCHECK_EQ(UPDATE, mode_);
- if (response_.headers->response_code() != 200 || truncated_ ||
+ if (response_.headers->response_code() != net::HTTP_OK || truncated_ ||
!ExternallyConditionalizedValidationHeadersMatchEntry()) {
// The externally conditionalized request is not a validation request
// for our existing cache entry. Proceed with caching disabled.
@@ -2843,8 +2989,8 @@ bool HttpCache::Transaction::IsResponseConditionalizable(
DCHECK(response_.headers.get());
// This only makes sense for cached 200 or 206 responses.
- if (response_.headers->response_code() != 200 &&
- response_.headers->response_code() != 206) {
+ if (response_.headers->response_code() != net::HTTP_OK &&
+ response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT) {
return false;
}
@@ -2884,7 +3030,7 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
if (!IsResponseConditionalizable(&etag_value, &last_modified_value))
return false;
- DCHECK(response_.headers->response_code() != 206 ||
+ DCHECK(response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT ||
response_.headers->HasStrongValidators());
if (vary_mismatch_) {
@@ -2997,7 +3143,7 @@ bool HttpCache::Transaction::ComputeUnusablePerCachingHeaders() {
bool HttpCache::Transaction::ValidatePartialResponse() {
const HttpResponseHeaders* headers = new_response_->headers.get();
int response_code = headers->response_code();
- bool partial_response = (response_code == 206);
+ bool partial_response = (response_code == net::HTTP_PARTIAL_CONTENT);
handling_206_ = false;
if (!entry_ || method_ != "GET")
@@ -3008,11 +3154,11 @@ bool HttpCache::Transaction::ValidatePartialResponse() {
// server is ok with the request, delete the entry, otherwise just ignore
// this request
DCHECK(!reading_);
- if (partial_response || response_code == 200) {
+ if (partial_response || response_code == net::HTTP_OK) {
DoomPartialEntry(true);
mode_ = NONE;
} else {
- if (response_code == 304) {
+ if (response_code == net::HTTP_NOT_MODIFIED) {
// Change the response code of the request to be 416 (Requested range
// not satisfiable).
SetResponse(*new_response_);
@@ -3032,14 +3178,16 @@ bool HttpCache::Transaction::ValidatePartialResponse() {
}
// TODO(rvargas): Do we need to consider other results here?.
- bool failure = response_code == 200 || response_code == 416;
+ bool failure = response_code == net::HTTP_OK ||
+ response_code == net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE;
if (partial_->IsCurrentRangeCached()) {
// We asked for "If-None-Match: " so a 206 means a new object.
if (partial_response)
failure = true;
- if (response_code == 304 && partial_->ResponseHeadersOK(headers))
+ if (response_code == net::HTTP_NOT_MODIFIED &&
+ partial_->ResponseHeadersOK(headers))
return true;
} else {
// We asked for "If-Range: " so a 206 means just another range.
@@ -3057,8 +3205,9 @@ bool HttpCache::Transaction::ValidatePartialResponse() {
// If the server sends 200, just store it. If it sends an error, redirect
// or something else, we may store the response as long as we didn't have
// anything already stored.
- if (response_code == 200 ||
- (!truncated_ && response_code != 304 && response_code != 416)) {
+ if (response_code == net::HTTP_OK ||
+ (!truncated_ && response_code != net::HTTP_NOT_MODIFIED &&
+ response_code != net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE)) {
// The server is sending something else, and we can save it.
DCHECK((truncated_ && !partial_->IsLastRange()) || range_requested_);
partial_.reset();
@@ -3116,9 +3265,10 @@ int HttpCache::Transaction::DoConnectedCallback() {
return OK;
}
+ auto type = response_.was_fetched_via_proxy ? TransportType::kCachedFromProxy
+ : TransportType::kCached;
return connected_callback_.Run(
- TransportInfo(TransportType::kCached, response_.remote_endpoint, ""),
- io_callback_);
+ TransportInfo(type, response_.remote_endpoint, ""), io_callback_);
}
int HttpCache::Transaction::DoConnectedCallbackComplete(int result) {
@@ -3165,7 +3315,7 @@ void HttpCache::Transaction::DoomInconsistentEntry() {
}
void HttpCache::Transaction::FixHeadersForHead() {
- if (response_.headers->response_code() == 206) {
+ if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT) {
response_.headers->RemoveHeader("Content-Range");
response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK");
}
@@ -3183,8 +3333,9 @@ int HttpCache::Transaction::DoSetupEntryForRead() {
if (partial_) {
if (truncated_ || is_sparse_ ||
- (!invalid_range_ && (response_.headers->response_code() == 200 ||
- response_.headers->response_code() == 206))) {
+ (!invalid_range_ &&
+ (response_.headers->response_code() == net::HTTP_OK ||
+ response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT))) {
// We are going to return the saved response headers to the caller, so
// we may need to adjust them first. In cases we are handling a range
// request to a regular entry, we want the response to be a 200 or 206,
@@ -3206,28 +3357,11 @@ int HttpCache::Transaction::DoSetupEntryForRead() {
return OK;
}
-int HttpCache::Transaction::WriteToEntry(int index,
- int offset,
- IOBuffer* data,
- int data_len,
- CompletionOnceCallback callback) {
- if (!entry_)
- return data_len;
-
- int rv = 0;
- if (!partial_ || !data_len) {
- rv = entry_->disk_entry->WriteData(index, offset, data, data_len,
- std::move(callback), true);
- } else {
- rv = partial_->CacheWrite(entry_->disk_entry, data, data_len,
- std::move(callback));
- }
- return rv;
-}
-
int HttpCache::Transaction::WriteResponseInfoToEntry(
const HttpResponseInfo& response,
bool truncated) {
+ DCHECK(response.headers);
+
if (!entry_)
return OK;
@@ -3254,7 +3388,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(
}
if (truncated)
- DCHECK_EQ(200, response.headers->response_code());
+ DCHECK_EQ(net::HTTP_OK, response.headers->response_code());
// When writing headers, we normally only write the non-transient headers.
bool skip_transient_headers = true;
@@ -3313,6 +3447,16 @@ void HttpCache::Transaction::DoneWithEntry(bool entry_is_complete) {
mode_ = NONE; // switch to 'pass through' mode
}
+void HttpCache::Transaction::DoneWithEntryForRestartWithCache() {
+ if (!entry_)
+ return;
+
+ cache_->DoneWithEntry(entry_, this, /*entry_is_complete=*/true,
+ partial_ != nullptr);
+ entry_ = nullptr;
+ new_entry_ = nullptr;
+}
+
int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
DLOG(ERROR) << "ReadData failed: " << result;
const int result_for_histogram = std::max(0, -result);
@@ -3530,9 +3674,6 @@ void HttpCache::Transaction::RecordHistograms() {
cache_entry_status_,
HttpCache::GetResourceURLFromHttpCacheKey(cache_key_));
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ParallelWritingPattern",
- parallel_writing_pattern_, PARALLEL_WRITING_MAX);
-
if (CacheEntryStatus::ENTRY_UNDEFINED == cache_entry_status_)
return;
@@ -3742,7 +3883,8 @@ bool HttpCache::Transaction::ShouldDisableCaching(
std::string mime_type;
base::CompareCase insensitive_ascii = base::CompareCase::INSENSITIVE_ASCII;
if (headers.GetContentLength() > kMaxContentSize &&
- headers.response_code() != 304 && headers.GetMimeType(&mime_type) &&
+ headers.response_code() != net::HTTP_NOT_MODIFIED &&
+ headers.GetMimeType(&mime_type) &&
(base::StartsWith(mime_type, "video", insensitive_ascii) ||
base::StartsWith(mime_type, "audio", insensitive_ascii))) {
disable_caching = true;
@@ -3769,4 +3911,69 @@ void HttpCache::Transaction::UpdateSecurityHeadersBeforeForwarding() {
return;
}
+void HttpCache::Transaction::ChecksumHeaders() {
+ DCHECK(effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE);
+ DCHECK(!checksum_);
+ checksum_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
+ // For efficiency and concision, we list known headers matching a wildcard
+ // explicitly rather than doing prefix matching.
+ constexpr auto kHeadersToInclude = base::MakeFixedFlatSet<base::StringPiece>({
+ "access-control-allow-credentials",
+ "access-control-allow-headers",
+ "access-control-allow-methods",
+ "access-control-allow-origin",
+ "access-control-expose-headers",
+ "access-control-max-age",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "clear-site-data",
+ "content-encoding",
+ "content-security-policy",
+ "content-type",
+ "cross-origin-embedder-policy",
+ "cross-origin-opener-policy",
+ "cross-origin-resource-policy",
+ "location"
+ "sec-websocket-accept",
+ "sec-websocket-extensions",
+ "sec-websocket-key",
+ "sec-websocket-protocol",
+ "sec-websocket-version",
+ "upgrade",
+ "vary",
+ });
+ // Iterate the response headers looking for matches.
+ size_t iter = 0;
+ std::string name;
+ std::string value;
+ // Pairs of (lower_case_header_name, header_value).
+ std::vector<std::pair<std::string, std::string>> filtered_headers;
+ // It's good to set the initial allocation size of the vector to the
+ // expected size to avoid a lot of reallocations. This value was chosen as
+ // it is a nice round number.
+ filtered_headers.reserve(16);
+ while (response_.headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ std::string lowered_name = base::ToLowerASCII(name);
+ if (kHeadersToInclude.contains(lowered_name)) {
+ filtered_headers.emplace_back(lowered_name, value);
+ }
+ }
+ std::sort(filtered_headers.begin(), filtered_headers.end());
+ for (const auto& [name, value] : filtered_headers) {
+ checksum_->Update(name.data(), name.size());
+ checksum_->Update(": ", 2);
+ checksum_->Update(value.data(), value.size());
+ checksum_->Update("\n", 1);
+ }
+ checksum_->Update("\n", 1);
+}
+
+bool HttpCache::Transaction::FinishAndCheckChecksum() {
+ if (!checksum_)
+ return true;
+
+ DCHECK(effective_load_flags_ & LOAD_USE_SINGLE_KEYED_CACHE);
+ return ResponseChecksumMatches(std::move(checksum_));
+}
+
} // namespace net
diff --git a/chromium/net/http/http_cache_transaction.h b/chromium/net/http/http_cache_transaction.h
index cc359647d7c..88ed80876e4 100644
--- a/chromium/net/http/http_cache_transaction.h
+++ b/chromium/net/http/http_cache_transaction.h
@@ -24,6 +24,7 @@
#include "net/base/ip_endpoint.h"
#include "net/base/load_states.h"
#include "net/base/net_error_details.h"
+#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/http/http_cache.h"
#include "net/http/http_request_headers.h"
@@ -35,6 +36,10 @@
#include "net/socket/connection_attempts.h"
#include "net/websockets/websocket_handshake_stream_base.h"
+namespace crypto {
+class SecureHash;
+} // namespace crypto
+
namespace net {
class PartialData;
@@ -188,18 +193,17 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// entry has finished writing.
void WriteModeTransactionAboutToBecomeReader();
- // Invoked when HttpCache decides whether this transaction should join
- // parallel writing or create a new writers object. This is then used
- // for logging metrics. Can be called repeatedly, but doesn't change once the
- // value has been set to something other than PARALLEL_WRITING_NONE.
- void MaybeSetParallelWritingPatternForMetrics(ParallelWritingPattern pattern);
+ // True if the passed checksum calculated from the response matches the
+ // expected value from the HttpRequestInfo. Consumes `checksum`.
+ bool ResponseChecksumMatches(
+ std::unique_ptr<crypto::SecureHash> checksum) const;
private:
static const size_t kNumValidationHeaders = 2;
// Helper struct to pair a header name with its value, for
// headers used to validate cache entries.
struct ValidationHeaders {
- ValidationHeaders() : initialized(false) {}
+ ValidationHeaders() = default;
std::string values[kNumValidationHeaders];
void Reset() {
@@ -207,7 +211,7 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
for (auto& value : values)
value.clear();
}
- bool initialized;
+ bool initialized = false;
};
struct NetworkTransactionInfo {
@@ -287,6 +291,11 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// by the network layer (skipping the cache entirely).
STATE_NETWORK_READ,
STATE_NETWORK_READ_COMPLETE,
+
+ // These states are only entered a single-keyed cache entry needs to be
+ // marked unusable.
+ STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE,
+ STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE,
};
// Used for categorizing validation triggers in histograms.
@@ -365,6 +374,8 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
int DoCacheReadDataComplete(int result);
int DoNetworkRead();
int DoNetworkReadComplete(int result);
+ int DoMarkSingleKeyedCacheEntryUnusable();
+ int DoMarkSingleKeyedCacheEntryUnusableComplete(int result);
// Adds time out handling while waiting to be added to entry or after headers
// phase is complete.
@@ -456,15 +467,6 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// Fixes the response headers to match expectations for a HEAD request.
void FixHeadersForHead();
- // Called to write data to the cache entry. If the write fails, then the
- // cache entry is destroyed. Future calls to this function will just do
- // nothing without side-effect. Returns a network error code.
- int WriteToEntry(int index,
- int offset,
- IOBuffer* data,
- int data_len,
- CompletionOnceCallback callback);
-
// Called to write a response to the cache entry. |truncated| indicates if the
// entry should be marked as incomplete.
int WriteResponseInfoToEntry(const HttpResponseInfo& response,
@@ -492,6 +494,10 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// resumed or not.
void DoneWithEntry(bool entry_is_complete);
+ // Informs the HttpCache that this transaction is done with the entry and
+ // resets related fields.
+ void DoneWithEntryForRestartWithCache();
+
// Dooms the given entry so that it will not be re-used for other requests,
// then calls `DoneWithEntry()`.
//
@@ -589,6 +595,15 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// headers.
bool ShouldDisableCaching(const HttpResponseHeaders& headers) const;
+ // Checksum headers in `request_` for matching against the single-keyed cache
+ // checksum. Initializes `checksum_`.
+ void ChecksumHeaders();
+
+ // Finishes the checksum and validates that it matches the expected value.
+ // Returns true if the checksum matches. Returns false if it does not
+ // match. If no checksumming is taking place then returns true.
+ bool FinishAndCheckChecksum();
+
// 304 revalidations of resources that set security headers and that get
// forwarded might need to set these headers again to avoid being blocked.
void UpdateSecurityHeadersBeforeForwarding();
@@ -596,9 +611,9 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
State next_state_{STATE_NONE};
// Initial request with which Start() was invoked.
- raw_ptr<const HttpRequestInfo> initial_request_;
+ raw_ptr<const HttpRequestInfo> initial_request_ = nullptr;
- raw_ptr<const HttpRequestInfo> request_;
+ raw_ptr<const HttpRequestInfo> request_ = nullptr;
std::string method_;
RequestPriority priority_;
@@ -609,8 +624,8 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// |external_validation_| contains the value of those headers.
ValidationHeaders external_validation_;
base::WeakPtr<HttpCache> cache_;
- raw_ptr<HttpCache::ActiveEntry> entry_;
- HttpCache::ActiveEntry* new_entry_;
+ raw_ptr<HttpCache::ActiveEntry> entry_ = nullptr;
+ HttpCache::ActiveEntry* new_entry_ = nullptr;
std::unique_ptr<HttpTransaction> network_trans_;
CompletionOnceCallback callback_; // Consumer's callback.
HttpResponseInfo response_;
@@ -625,56 +640,64 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// WriteResponseInfoToEntry() resets this to absl::nullopt.
std::unique_ptr<HttpResponseInfo> updated_prefetch_response_;
- raw_ptr<const HttpResponseInfo> new_response_;
+ raw_ptr<const HttpResponseInfo> new_response_ = nullptr;
std::string cache_key_;
- Mode mode_;
- bool reading_; // We are already reading. Never reverts to false once set.
- bool invalid_range_; // We may bypass the cache for this request.
- bool truncated_; // We don't have all the response data.
- bool is_sparse_; // The data is stored in sparse byte ranges.
- bool range_requested_; // The user requested a byte range.
- bool handling_206_; // We must deal with this 206 response.
- bool cache_pending_; // We are waiting for the HttpCache.
+ Mode mode_ = NONE;
+ bool reading_ = false; // We are already reading. Never reverts to
+ // false once set.
+ bool invalid_range_ = false; // We may bypass the cache for this request.
+ bool truncated_ = false; // We don't have all the response data.
+ bool is_sparse_ = false; // The data is stored in sparse byte ranges.
+ bool range_requested_ = false; // The user requested a byte range.
+ bool handling_206_ = false; // We must deal with this 206 response.
+ bool cache_pending_ = false; // We are waiting for the HttpCache.
// Headers have been received from the network and it's not a match with the
// existing entry.
- bool done_headers_create_new_entry_;
-
- bool vary_mismatch_; // The request doesn't match the stored vary data.
- bool couldnt_conditionalize_request_;
- bool bypass_lock_for_test_; // A test is exercising the cache lock.
- bool bypass_lock_after_headers_for_test_; // A test is exercising the cache
- // lock.
- bool fail_conditionalization_for_test_; // Fail ConditionalizeRequest.
+ bool done_headers_create_new_entry_ = false;
+
+ bool vary_mismatch_ = false; // The request doesn't match the stored vary
+ // data.
+ bool couldnt_conditionalize_request_ = false;
+ bool bypass_lock_for_test_ = false; // A test is exercising the cache lock.
+ bool bypass_lock_after_headers_for_test_ = false; // A test is exercising the
+ // cache lock.
+ bool fail_conditionalization_for_test_ =
+ false; // Fail ConditionalizeRequest.
+ bool mark_single_keyed_cache_entry_unusable_ =
+ false; // Set single_keyed_cache_entry_unusable.
+
scoped_refptr<IOBuffer> read_buf_;
// Length of the buffer passed in Read().
- int read_buf_len_;
+ int read_buf_len_ = 0;
- int io_buf_len_;
- int read_offset_;
- int effective_load_flags_;
+ int io_buf_len_ = 0;
+ int read_offset_ = 0;
+ int effective_load_flags_ = 0;
std::unique_ptr<PartialData> partial_; // We are dealing with range requests.
CompletionRepeatingCallback io_callback_;
// Error code to be returned from a subsequent Read call if shared writing
// failed in a separate transaction.
- int shared_writing_error_;
+ int shared_writing_error_ = OK;
// Members used to track data for histograms.
// This cache_entry_status_ takes precedence over
// response_.cache_entry_status. In fact, response_.cache_entry_status must be
// kept in sync with cache_entry_status_ (via SetResponse and
// UpdateCacheEntryStatus).
- HttpResponseInfo::CacheEntryStatus cache_entry_status_;
- ValidationCause validation_cause_;
+ HttpResponseInfo::CacheEntryStatus cache_entry_status_ =
+ HttpResponseInfo::CacheEntryStatus::ENTRY_UNDEFINED;
+ ValidationCause validation_cause_ = VALIDATION_CAUSE_UNDEFINED;
base::TimeTicks entry_lock_waiting_since_;
base::TimeTicks first_cache_access_since_;
base::TimeTicks send_request_since_;
base::TimeTicks read_headers_since_;
base::Time open_entry_last_used_;
- bool recorded_histograms_;
- ParallelWritingPattern parallel_writing_pattern_;
+ bool recorded_histograms_ = false;
+ bool has_opened_or_created_entry_ = false;
+ bool record_entry_open_or_creation_time_ = false;
NetworkTransactionInfo network_transaction_info_;
@@ -685,14 +708,19 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// TODO(shivanisha) Note that if this transaction dies mid-way and there are
// other writer transactions, no transaction then accounts for those
// statistics.
- bool moved_network_transaction_to_writers_;
+ bool moved_network_transaction_to_writers_ = false;
// The helper object to use to create WebSocketHandshakeStreamBase
// objects. Only relevant when establishing a WebSocket connection.
// This is passed to the underlying network transaction. It is stored here in
// case the transaction does not exist yet.
raw_ptr<WebSocketHandshakeStreamBase::CreateHelper>
- websocket_handshake_stream_base_create_helper_;
+ websocket_handshake_stream_base_create_helper_ = nullptr;
+
+ // Set if we are currently calculating a checksum of the resource to validate
+ // it against the expected checksum for the single-keyed cache. Accumulates a
+ // hash of selected headers and the body of the response.
+ std::unique_ptr<crypto::SecureHash> checksum_;
BeforeNetworkStartCallback before_network_start_callback_;
ConnectedCallback connected_callback_;
@@ -701,7 +729,7 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
ResponseHeadersCallback response_headers_callback_;
// True if the Transaction is currently processing the DoLoop.
- bool in_do_loop_;
+ bool in_do_loop_ = false;
base::WeakPtrFactory<Transaction> weak_factory_{this};
};
diff --git a/chromium/net/http/http_cache_unittest.cc b/chromium/net/http/http_cache_unittest.cc
index ec0d6f2589c..09f1f94f4a6 100644
--- a/chromium/net/http/http_cache_unittest.cc
+++ b/chromium/net/http/http_cache_unittest.cc
@@ -685,9 +685,9 @@ struct Response {
};
struct Context {
- Context() : result(ERR_IO_PENDING) {}
+ Context() = default;
- int result;
+ int result = ERR_IO_PENDING;
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
};
@@ -1075,6 +1075,54 @@ TEST_F(HttpCacheTest,
}
}
+// This test verifies that the callback passed to SetConnectedCallback() is
+// called with the right transport type when the cached entry was originally
+// fetched via proxy.
+TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitFromProxy) {
+ MockHttpCache cache;
+
+ TransportInfo proxied_transport_info = TestTransportInfo();
+ proxied_transport_info.type = TransportType::kProxied;
+
+ {
+ // Populate the cache.
+ ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
+ mock_transaction.transport_info = proxied_transport_info;
+ RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
+ }
+
+ // Establish a baseline.
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+
+ // Load from the cache (only), observe the callback being called.
+
+ ConnectedHandler connected_handler;
+ MockHttpRequest request(kSimpleGET_Transaction);
+
+ std::unique_ptr<HttpTransaction> transaction;
+ EXPECT_THAT(cache.CreateTransaction(&transaction), IsOk());
+ ASSERT_THAT(transaction, NotNull());
+
+ transaction->SetConnectedCallback(connected_handler.Callback());
+
+ TestCompletionCallback callback;
+ ASSERT_THAT(
+ transaction->Start(&request, callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+ // Still only 1 transaction for the previous request. The connected callback
+ // was not called by a second network transaction.
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+
+ // The transport info mentions both the cache and the original proxy.
+ TransportInfo expected_transport_info = TestTransportInfo();
+ expected_transport_info.type = TransportType::kCachedFromProxy;
+
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(expected_transport_info));
+}
+
class HttpCacheTest_SplitCacheFeature
: public HttpCacheTest,
public ::testing::WithParamInterface<bool> {
@@ -1194,8 +1242,6 @@ TEST_F(HttpCacheTest, ReleaseBuffer) {
TEST_F(HttpCacheTest, SimpleGETWithDiskFailures) {
MockHttpCache cache;
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
cache.disk_cache()->set_soft_failures_mask(MockDiskEntry::FAIL_ALL);
@@ -1212,11 +1258,6 @@ TEST_F(HttpCacheTest, SimpleGETWithDiskFailures) {
EXPECT_EQ(2, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
EXPECT_EQ(2, cache.disk_cache()->create_count());
-
- // Since the transactions were in headers phase when failed,
- // PARALLEL_WRITING_NONE should be logged.
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_NONE), 2);
}
// Tests that disk failures after the transaction has started don't cause the
@@ -1388,8 +1429,6 @@ TEST_F(HttpCacheTest, SimpleGET_LoadOnlyFromCache_Miss) {
TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_Hit) {
MockHttpCache cache;
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
// write to the cache
RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
@@ -1403,12 +1442,6 @@ TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_Hit) {
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
-
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1);
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NONE_CACHE_READ), 1);
}
TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_Miss) {
@@ -2836,8 +2869,6 @@ TEST_F(HttpCacheTest, RangeGET_ParallelValidationNoMatchDoomEntry1) {
// Tests parallel validation on range requests with non-overlapping ranges.
TEST_F(HttpCacheTest, RangeGET_ParallelValidationDifferentRanges) {
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
MockHttpCache cache;
ScopedMockTransaction transaction(kRangeGET_TransactionOK);
@@ -2937,11 +2968,6 @@ TEST_F(HttpCacheTest, RangeGET_ParallelValidationDifferentRanges) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
context_list.clear();
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE), 1);
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 2);
}
// Tests that a request does not create Writers when readers is not empty.
@@ -3670,7 +3696,8 @@ TEST_F(HttpCacheTest, RangeGET_Enormous) {
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
auto backend_factory = std::make_unique<HttpCache::DefaultBackend>(
- DISK_CACHE, CACHE_BACKEND_BLOCKFILE, temp_dir.GetPath(), 1024 * 1024,
+ DISK_CACHE, CACHE_BACKEND_BLOCKFILE,
+ /*file_operations_factory=*/nullptr, temp_dir.GetPath(), 1024 * 1024,
false);
MockHttpCache cache(std::move(backend_factory));
@@ -4420,8 +4447,6 @@ TEST_F(HttpCacheTest, SimpleGET_ParallelWritingCacheWriteFailed) {
// like the code should disallow two POSTs without LOAD_ONLY_FROM_CACHE with the
// same upload data identifier to map to the same entry.
TEST_F(HttpCacheTest, SimplePOST_ParallelWritingDisallowed) {
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
MockHttpCache cache;
MockTransaction transaction(kSimplePOST_Transaction);
@@ -4478,18 +4503,11 @@ TEST_F(HttpCacheTest, SimplePOST_ParallelWritingDisallowed) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
context_list.clear();
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_METHOD_NOT_GET), 1);
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1);
}
// Tests the case when parallel writing succeeds. Tests both idle and waiting
// transactions.
TEST_F(HttpCacheTest, SimpleGET_ParallelWritingSuccess) {
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
MockHttpCache cache;
MockHttpRequest request(kSimpleGET_Transaction);
@@ -4567,22 +4585,12 @@ TEST_F(HttpCacheTest, SimpleGET_ParallelWritingSuccess) {
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
}
- // Verify metrics.
context_list.clear();
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1);
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_JOIN), 2);
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_READ_ONLY), 1);
}
// Tests the case when parallel writing involves things bigger than what cache
// can store. In this case, the best we can do is re-fetch it.
TEST_F(HttpCacheTest, SimpleGET_ParallelWritingHuge) {
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
MockHttpCache cache;
cache.disk_cache()->set_max_file_size(10);
@@ -4647,15 +4655,7 @@ TEST_F(HttpCacheTest, SimpleGET_ParallelWritingHuge) {
// Sadly all of them have to hit the network
EXPECT_EQ(kNumTransactions, cache.network_layer()->transaction_count());
- // Verify metrics.
context_list.clear();
- histograms.ExpectBucketCount(
- histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1);
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_TOO_BIG_FOR_CACHE),
- kNumTransactions - 1);
-
RemoveMockTransaction(&transaction);
}
@@ -6765,8 +6765,6 @@ TEST_F(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Miss) {
TEST_F(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Hit) {
MockHttpCache cache;
- base::HistogramTester histograms;
- const std::string histogram_name = "HttpCache.ParallelWritingPattern";
// Test that we hit the cache for POST requests.
@@ -6798,10 +6796,6 @@ TEST_F(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Hit) {
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
-
- histograms.ExpectBucketCount(
- histogram_name,
- static_cast<int>(HttpCache::PARALLEL_WRITING_NONE_CACHE_READ), 1);
}
// Test that we don't hit the cache for POST requests if there is a byte range.
@@ -13506,4 +13500,298 @@ TEST_F(HttpCacheTest, SecurityHeadersAreCopiedToConditionalizedResponse) {
EXPECT_EQ("cross-origin", response_corp_header);
}
+class HttpCacheSingleKeyedCacheTest : public HttpCacheTest {
+ public:
+ void SetUp() override {
+ // The single-keyed cache feature is meaningless when the split cache is not
+ // enabled. The //net layer doesn't care whether or not the
+ // "CacheTransparency" feature is enabled.
+ feature_list_.InitWithFeatureState(
+ net::features::kSplitCacheByNetworkIsolationKey, true);
+ HttpCacheTest::SetUp();
+ }
+
+ void RunTransactionTestForSingleKeyedCache(
+ HttpCache* cache,
+ const MockTransaction& trans_info,
+ const NetworkIsolationKey& network_isolation_key,
+ const std::string& checksum) {
+ MockTransaction transaction(trans_info);
+ transaction.load_flags |= LOAD_USE_SINGLE_KEYED_CACHE;
+
+ AddMockTransaction(&transaction);
+ MockHttpRequest request(transaction);
+ request.network_isolation_key = network_isolation_key;
+ request.checksum = checksum;
+
+ HttpResponseInfo response_info;
+ RunTransactionTestWithRequest(cache, transaction, request, &response_info);
+ }
+
+ void RunSimpleTransactionTestForSingleKeyedCache(
+ HttpCache* cache,
+ const NetworkIsolationKey& network_isolation_key,
+ const std::string& checksum) {
+ RunTransactionTestForSingleKeyedCache(cache, kSimpleGET_Transaction,
+ network_isolation_key, checksum);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+constexpr char kChecksumForSimpleGET[] =
+ "80B4C37CEF5CFE69B4A90830282AA2BB772DC4CBC00491A219CE5F2AD75C7B58";
+
+TEST_F(HttpCacheSingleKeyedCacheTest, SuccessfulGET) {
+ MockHttpCache cache;
+ // The first request adds the item to the cache.
+ {
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ RunSimpleTransactionTestForSingleKeyedCache(
+ cache.http_cache(), NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request verifies that the same cache entry is used with a
+ // different NetworkIsolationKey
+ {
+ const auto site_b = SchemefulSite(GURL("https://b.com/"));
+ RunSimpleTransactionTestForSingleKeyedCache(
+ cache.http_cache(), NetworkIsolationKey(site_b, site_b),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+}
+
+TEST_F(HttpCacheSingleKeyedCacheTest, GETWithChecksumMismatch) {
+ MockHttpCache cache;
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ // The first request adds the item to the cache.
+ {
+ RunSimpleTransactionTestForSingleKeyedCache(
+ cache.http_cache(), NetworkIsolationKey(site_a, site_a),
+ "000000000000000000000000000000000000000000000000000000000000000");
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request doesn't use the item that was added to the single-keyed
+ // cache, but adds it to the split cache instead.
+ {
+ RunSimpleTransactionTestForSingleKeyedCache(
+ cache.http_cache(), NetworkIsolationKey(site_a, site_a),
+ "000000000000000000000000000000000000000000000000000000000000000");
+
+ // Fetches from the network again, this time into the split cache.
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+ }
+
+ // The third request uses the split cache.
+ {
+ RunSimpleTransactionTestForSingleKeyedCache(
+ cache.http_cache(), NetworkIsolationKey(site_a, site_a),
+ "000000000000000000000000000000000000000000000000000000000000000");
+
+ // Fetches from the split cache.
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(3, cache.disk_cache()->open_count()); // opens both cache entries
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+ }
+}
+
+TEST_F(HttpCacheSingleKeyedCacheTest, GETWithBadResponseCode) {
+ MockHttpCache cache;
+ MockTransaction transaction = kSimpleGET_Transaction;
+ transaction.status = "HTTP/1.1 404 Not Found";
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ // The first request adds the item to the single-keyed cache.
+ {
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request verifies that the cache entry is not re-used
+ // but a new one is created in the split cache.
+ {
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+ }
+}
+
+TEST_F(HttpCacheSingleKeyedCacheTest, SuccessfulRevalidation) {
+ MockHttpCache cache;
+ MockTransaction transaction = kSimpleGET_Transaction;
+ // Add a cache control header to permit the entry to be cached, with max-age 0
+ // to force relatidation next time. Add Etag to permit it to be revalidated.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=0\n";
+ {
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request revalidates the existing entry.
+ {
+ const auto site_b = SchemefulSite(GURL("https://b.com/"));
+ transaction.status = "HTTP/1.1 304 Not Modified";
+ // Allow it to be reused without validation next time by increasing max-age.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=10000\n";
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_b, site_b),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The third request re-uses the entry.
+ {
+ const auto site_c = SchemefulSite(GURL("https://c.com/"));
+ // Load from cache again.
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_c, site_c),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+}
+
+TEST_F(HttpCacheSingleKeyedCacheTest, RevalidationChangingUncheckedHeader) {
+ MockHttpCache cache;
+ MockTransaction transaction = kSimpleGET_Transaction;
+ // Add a cache control header to permit the entry to be cached, with max-age 0
+ // to force relatidation next time. Add Etag to permit it to be revalidated.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=0\n";
+ {
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request revalidates the existing entry.
+ {
+ const auto site_b = SchemefulSite(GURL("https://b.com/"));
+ transaction.status = "HTTP/1.1 304 Not Modified";
+ // Add a response header. This is the only difference from the
+ // SuccessfulRevalidation test.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=10000\n"
+ "X-Unchecked-Header: 1\n";
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_b, site_b),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The third request re-uses the entry.
+ {
+ const auto site_c = SchemefulSite(GURL("https://c.com/"));
+ // Load from cache again.
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_c, site_c),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+}
+
+TEST_F(HttpCacheSingleKeyedCacheTest, RevalidationChangingCheckedHeader) {
+ MockHttpCache cache;
+ MockTransaction transaction = kSimpleGET_Transaction;
+ // Add a cache control header to permit the entry to be cached, with max-age 0
+ // to force relatidation next time. Add Etag to permit it to be revalidated.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=0\n";
+ {
+ const auto site_a = SchemefulSite(GURL("https://a.com/"));
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_a, site_a),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The second request marks the single-keyed cache entry unusable because the
+ // checksum no longer matches.
+ {
+ const auto site_b = SchemefulSite(GURL("https://b.com/"));
+ transaction.status = "HTTP/1.1 304 Not Modified";
+ // Add the "Vary" response header.
+ transaction.response_headers =
+ "Etag: \"foo\"\n"
+ "Cache-Control: max-age=10000\n"
+ "Vary: Cookie\n";
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_b, site_b),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+ }
+
+ // The third request has to go to the network because the single-keyed cache
+ // entry is unusable. It writes a new entry to the split cache.
+ {
+ const auto site_c = SchemefulSite(GURL("https://c.com/"));
+ RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
+ NetworkIsolationKey(site_c, site_c),
+ kChecksumForSimpleGET);
+
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(2, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+ }
+}
+
} // namespace net
diff --git a/chromium/net/http/http_cache_writers.cc b/chromium/net/http/http_cache_writers.cc
index 5842b09cf3d..9a9b3b9647a 100644
--- a/chromium/net/http/http_cache_writers.cc
+++ b/chromium/net/http/http_cache_writers.cc
@@ -15,10 +15,13 @@
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache_transaction.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_status_code.h"
#include "net/http/partial_data.h"
namespace net {
@@ -44,8 +47,9 @@ bool IsValidResponseForWriter(bool is_partial,
// Return false if the response code sent by the server is garbled.
// Both 200 and 304 are valid since concurrent writing is supported.
- if (!is_partial && (response_info->headers->response_code() != 200 &&
- response_info->headers->response_code() != 304)) {
+ if (!is_partial &&
+ (response_info->headers->response_code() != net::HTTP_OK &&
+ response_info->headers->response_code() != net::HTTP_NOT_MODIFIED)) {
return false;
}
@@ -65,7 +69,10 @@ HttpCache::Writers::TransactionInfo::TransactionInfo(const TransactionInfo&) =
default;
HttpCache::Writers::Writers(HttpCache* cache, HttpCache::ActiveEntry* entry)
- : cache_(cache), entry_(entry) {}
+ : cache_(cache), entry_(entry) {
+ DCHECK(cache_);
+ DCHECK(entry_);
+}
HttpCache::Writers::~Writers() = default;
@@ -161,12 +168,15 @@ void HttpCache::Writers::AddTransaction(
void HttpCache::Writers::SetNetworkTransaction(
Transaction* transaction,
- std::unique_ptr<HttpTransaction> network_transaction) {
+ std::unique_ptr<HttpTransaction> network_transaction,
+ std::unique_ptr<crypto::SecureHash> checksum) {
DCHECK_EQ(1u, all_writers_.count(transaction));
DCHECK(network_transaction);
DCHECK(!network_transaction_);
network_transaction_ = std::move(network_transaction);
network_transaction_->SetPriority(priority_);
+ DCHECK(!checksum_);
+ checksum_ = std::move(checksum);
}
void HttpCache::Writers::ResetNetworkTransaction() {
@@ -329,7 +339,6 @@ HttpCache::Writers::WaitingForRead::WaitingForRead(
CompletionOnceCallback consumer_callback)
: read_buf(std::move(buf)),
read_buf_len(len),
- write_len(0),
callback(std::move(consumer_callback)) {
DCHECK(read_buf);
DCHECK_GT(len, 0);
@@ -361,6 +370,14 @@ int HttpCache::Writers::DoLoop(int result) {
case State::CACHE_WRITE_DATA_COMPLETE:
rv = DoCacheWriteDataComplete(rv);
break;
+ case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
+ // `rv` is bytes here.
+ DCHECK_EQ(0, rv);
+ rv = DoMarkSingleKeyedCacheEntryUnusable();
+ break;
+ case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
+ rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
+ break;
case State::UNSET:
NOTREACHED() << "bad state";
rv = ERR_FAILED;
@@ -488,6 +505,20 @@ int HttpCache::Writers::DoCacheWriteData(int num_bytes) {
int HttpCache::Writers::DoCacheWriteDataComplete(int result) {
DCHECK(!all_writers_.empty());
next_state_ = State::NONE;
+ if (checksum_) {
+ if (write_len_ > 0) {
+ checksum_->Update(read_buf_->data(), write_len_);
+ } else {
+ // The write to the cache may have failed if result < 0, but even in that
+ // case we want to check whether the data we've read from the network is
+ // valid or not.
+ CHECK(active_transaction_);
+ if (!active_transaction_->ResponseChecksumMatches(std::move(checksum_))) {
+ next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE;
+ }
+ }
+ }
+
if (result != write_len_) {
// Note that it is possible for cache write to fail if the size of the file
// exceeds the per-file limit.
@@ -501,6 +532,40 @@ int HttpCache::Writers::DoCacheWriteDataComplete(int result) {
return result;
}
+int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusable() {
+ // `response_info_truncation_` is not actually truncated.
+ // TODO(ricea): Maybe change the name of the member?
+ response_info_truncation_.single_keyed_cache_entry_unusable = true;
+ next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE;
+
+ // Update cache metadata. This is a subset of what
+ // HttpCache::Transaction::WriteResponseInfoToEntry does.
+ auto data = base::MakeRefCounted<PickledIOBuffer>();
+ response_info_truncation_.Persist(data->pickle(),
+ /*skip_transient_headers=*/true,
+ /*response_truncated=*/false);
+ data->Done();
+ io_buf_len_ = data->pickle()->size();
+ CompletionOnceCallback io_callback = base::BindOnce(
+ &HttpCache::Writers::OnIOComplete, weak_factory_.GetWeakPtr());
+ return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
+ io_buf_len_, std::move(io_callback),
+ true);
+}
+
+int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusableComplete(
+ int result) {
+ next_state_ = State::NONE;
+
+ if (result < 0) {
+ OnCacheWriteFailure();
+ }
+
+ // DoLoop() wants the size of the data write, not the size of the metadata
+ // write.
+ return write_len_;
+}
+
void HttpCache::Writers::OnDataReceived(int result) {
DCHECK(!all_writers_.empty());
diff --git a/chromium/net/http/http_cache_writers.h b/chromium/net/http/http_cache_writers.h
index 4909ad652a1..7de8dde0c7c 100644
--- a/chromium/net/http/http_cache_writers.h
+++ b/chromium/net/http/http_cache_writers.h
@@ -14,6 +14,10 @@
#include "net/http/http_cache.h"
#include "net/http/http_response_info.h"
+namespace crypto {
+class SecureHash;
+}
+
namespace net {
class HttpResponseInfo;
@@ -138,10 +142,12 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
LoadState GetLoadState() const;
// Sets the network transaction argument to |network_transaction_|. Must be
- // invoked before Read can be invoked.
+ // invoked before Read can be invoked. If |checksum| is set it will be
+ // validated and the cache entry will be marked unusable if it doesn't match.
void SetNetworkTransaction(
Transaction* transaction,
- std::unique_ptr<HttpTransaction> network_transaction);
+ std::unique_ptr<HttpTransaction> network_transaction,
+ std::unique_ptr<crypto::SecureHash> checksum);
// Resets the network transaction to nullptr. Required for range requests as
// they might use the current network transaction only for part of the
@@ -163,6 +169,8 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
NETWORK_READ_COMPLETE,
CACHE_WRITE_DATA,
CACHE_WRITE_DATA_COMPLETE,
+ MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE,
+ MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE,
};
// These transactions are waiting on Read. After the active transaction
@@ -171,7 +179,7 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
struct WaitingForRead {
scoped_refptr<IOBuffer> read_buf;
int read_buf_len;
- int write_len;
+ int write_len = 0;
CompletionOnceCallback callback;
WaitingForRead(scoped_refptr<IOBuffer> read_buf,
int len,
@@ -192,6 +200,8 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
int DoNetworkReadComplete(int result);
int DoCacheWriteData(int num_bytes);
int DoCacheWriteDataComplete(int result);
+ int DoMarkSingleKeyedCacheEntryUnusable();
+ int DoMarkSingleKeyedCacheEntryUnusableComplete(int result);
// Helper functions for callback.
void OnNetworkReadFailure(int result);
@@ -236,10 +246,10 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
// True if only reading from network and not writing to cache.
bool network_read_only_ = false;
- raw_ptr<HttpCache> cache_ = nullptr;
+ raw_ptr<HttpCache> const cache_ = nullptr;
// Owner of |this|.
- raw_ptr<ActiveEntry> entry_ = nullptr;
+ raw_ptr<ActiveEntry> const entry_ = nullptr;
std::unique_ptr<HttpTransaction> network_transaction_;
@@ -285,6 +295,11 @@ class NET_EXPORT_PRIVATE HttpCache::Writers {
// written.
bool should_keep_entry_ = true;
+ // Set if we are currently calculating a checksum of the resource to validate
+ // it against the expected checksum for the single-keyed cache. Initialised
+ // with selected headers and accumulates the body of the response.
+ std::unique_ptr<crypto::SecureHash> checksum_;
+
CompletionOnceCallback callback_; // Callback for active_transaction_.
// Since cache_ can destroy |this|, |cache_callback_| is only invoked at the
diff --git a/chromium/net/http/http_cache_writers_unittest.cc b/chromium/net/http/http_cache_writers_unittest.cc
index 9fe72473b29..275b6b7ad3d 100644
--- a/chromium/net/http/http_cache_writers_unittest.cc
+++ b/chromium/net/http/http_cache_writers_unittest.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
+#include "crypto/secure_hash.h"
#include "net/http/http_cache.h"
#include "net/http/http_cache_transaction.h"
#include "net/http/http_response_info.h"
@@ -54,8 +55,7 @@ class TestHttpCache : public HttpCache {
public:
TestHttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
std::unique_ptr<BackendFactory> backend_factory)
- : HttpCache(std::move(network_layer), std::move(backend_factory), false) {
- }
+ : HttpCache(std::move(network_layer), std::move(backend_factory)) {}
void WritersDoneWritingToEntry(ActiveEntry* entry,
bool success,
@@ -83,7 +83,6 @@ class WritersTest : public TestWithTaskEnvironment {
enum class DeleteTransactionType { NONE, ACTIVE, WAITING, IDLE };
WritersTest()
: scoped_transaction_(kSimpleGET_Transaction),
- disk_entry_(nullptr),
test_cache_(std::make_unique<MockNetworkLayer>(),
std::make_unique<MockBackendFactory>()),
request_(kSimpleGET_Transaction) {
@@ -143,7 +142,7 @@ class WritersTest : public TestWithTaskEnvironment {
writers_->AddTransaction(transaction.get(), parallel_writing_pattern_,
transaction->priority(), info);
writers_->SetNetworkTransaction(transaction.get(),
- std::move(network_transaction));
+ std::move(network_transaction), nullptr);
EXPECT_TRUE(writers_->HasTransaction(transaction.get()));
transactions_.push_back(std::move(transaction));
}
@@ -498,7 +497,7 @@ class WritersTest : public TestWithTaskEnvironment {
ScopedMockTransaction scoped_transaction_;
MockHttpCache cache_;
std::unique_ptr<HttpCache::Writers> writers_;
- disk_cache::Entry* disk_entry_;
+ disk_cache::Entry* disk_entry_ = nullptr;
std::unique_ptr<HttpCache::ActiveEntry> entry_;
TestHttpCache test_cache_;
diff --git a/chromium/net/http/http_chunked_decoder.cc b/chromium/net/http/http_chunked_decoder.cc
index fab94342adb..c6ae91fbd6e 100644
--- a/chromium/net/http/http_chunked_decoder.cc
+++ b/chromium/net/http/http_chunked_decoder.cc
@@ -58,13 +58,7 @@ namespace net {
// extensions.
const size_t HttpChunkedDecoder::kMaxLineBufLen = 16384;
-HttpChunkedDecoder::HttpChunkedDecoder()
- : chunk_remaining_(0),
- chunk_terminator_remaining_(false),
- reached_last_chunk_(false),
- reached_eof_(false),
- bytes_after_eof_(0) {
-}
+HttpChunkedDecoder::HttpChunkedDecoder() = default;
int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
int result = 0;
diff --git a/chromium/net/http/http_chunked_decoder.h b/chromium/net/http/http_chunked_decoder.h
index 2ff55f98291..99afb0b0d90 100644
--- a/chromium/net/http/http_chunked_decoder.h
+++ b/chromium/net/http/http_chunked_decoder.h
@@ -111,22 +111,22 @@ class NET_EXPORT_PRIVATE HttpChunkedDecoder {
static bool ParseChunkSize(const char* start, int len, int64_t* out);
// Indicates the number of bytes remaining for the current chunk.
- int64_t chunk_remaining_;
+ int64_t chunk_remaining_ = 0;
// A small buffer used to store a partial chunk marker.
std::string line_buf_;
// True if waiting for the terminal CRLF of a chunk's data.
- bool chunk_terminator_remaining_;
+ bool chunk_terminator_remaining_ = false;
// Set to true when FilterBuf encounters the last-chunk.
- bool reached_last_chunk_;
+ bool reached_last_chunk_ = false;
// Set to true when FilterBuf encounters the final CRLF.
- bool reached_eof_;
+ bool reached_eof_ = false;
// The number of extraneous unfiltered bytes after the final CRLF.
- int bytes_after_eof_;
+ int bytes_after_eof_ = 0;
};
} // namespace net
diff --git a/chromium/net/http/http_content_disposition.cc b/chromium/net/http/http_content_disposition.cc
index 17b0a6ffa02..c007c3caba9 100644
--- a/chromium/net/http/http_content_disposition.cc
+++ b/chromium/net/http/http_content_disposition.cc
@@ -6,12 +6,12 @@
#include "base/base64.h"
#include "base/check_op.h"
+#include "base/strings/escape.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/escape.h"
#include "net/base/net_string_util.h"
#include "net/http/http_util.h"
@@ -189,8 +189,8 @@ bool DecodeWord(base::StringPiece encoded_word,
// web browser.
// What IE6/7 does: %-escaped UTF-8.
- decoded_word =
- base::UnescapeBinaryURLComponent(encoded_word, UnescapeRule::NORMAL);
+ decoded_word = base::UnescapeBinaryURLComponent(encoded_word,
+ base::UnescapeRule::NORMAL);
if (decoded_word != encoded_word)
*parse_result_flags |= HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS;
if (base::IsStringUTF8(decoded_word)) {
@@ -326,7 +326,7 @@ bool DecodeExtValue(const std::string& param_value, std::string* decoded) {
}
std::string unescaped =
- base::UnescapeBinaryURLComponent(value, UnescapeRule::NORMAL);
+ base::UnescapeBinaryURLComponent(value, base::UnescapeRule::NORMAL);
return ConvertToUtf8AndNormalize(unescaped, charset.c_str(), decoded);
}
@@ -334,9 +334,8 @@ bool DecodeExtValue(const std::string& param_value, std::string* decoded) {
} // namespace
HttpContentDisposition::HttpContentDisposition(
- const std::string& header, const std::string& referrer_charset)
- : type_(INLINE),
- parse_result_flags_(INVALID) {
+ const std::string& header,
+ const std::string& referrer_charset) {
Parse(header, referrer_charset);
}
@@ -360,9 +359,9 @@ std::string::const_iterator HttpContentDisposition::ConsumeDispositionType(
DCHECK(type.find('=') == base::StringPiece::npos);
- if (base::LowerCaseEqualsASCII(type, "inline")) {
+ if (base::EqualsCaseInsensitiveASCII(type, "inline")) {
type_ = INLINE;
- } else if (base::LowerCaseEqualsASCII(type, "attachment")) {
+ } else if (base::EqualsCaseInsensitiveASCII(type, "attachment")) {
type_ = ATTACHMENT;
} else {
parse_result_flags_ |= HAS_UNKNOWN_DISPOSITION_TYPE;
@@ -404,7 +403,7 @@ void HttpContentDisposition::Parse(const std::string& header,
HttpUtil::NameValuePairsIterator iter(pos, end, ';');
while (iter.GetNext()) {
if (filename.empty() &&
- base::LowerCaseEqualsASCII(iter.name_piece(), "filename")) {
+ base::EqualsCaseInsensitiveASCII(iter.name_piece(), "filename")) {
DecodeFilenameValue(iter.value(), referrer_charset, &filename,
&parse_result_flags_);
if (!filename.empty()) {
@@ -412,8 +411,8 @@ void HttpContentDisposition::Parse(const std::string& header,
if (filename[0] == '\'')
parse_result_flags_ |= HAS_SINGLE_QUOTED_FILENAME;
}
- } else if (ext_filename.empty() &&
- base::LowerCaseEqualsASCII(iter.name_piece(), "filename*")) {
+ } else if (ext_filename.empty() && base::EqualsCaseInsensitiveASCII(
+ iter.name_piece(), "filename*")) {
DecodeExtValue(iter.raw_value(), &ext_filename);
if (!ext_filename.empty())
parse_result_flags_ |= HAS_EXT_FILENAME;
diff --git a/chromium/net/http/http_content_disposition.h b/chromium/net/http/http_content_disposition.h
index 82424018f67..476eebeabf7 100644
--- a/chromium/net/http/http_content_disposition.h
+++ b/chromium/net/http/http_content_disposition.h
@@ -72,9 +72,9 @@ class NET_EXPORT HttpContentDisposition {
std::string::const_iterator ConsumeDispositionType(
std::string::const_iterator begin, std::string::const_iterator end);
- Type type_;
+ Type type_ = INLINE;
std::string filename_;
- int parse_result_flags_;
+ int parse_result_flags_ = INVALID;
};
} // namespace net
diff --git a/chromium/net/http/http_network_layer.cc b/chromium/net/http/http_network_layer.cc
index a02911e5eaf..a9415436277 100644
--- a/chromium/net/http/http_network_layer.cc
+++ b/chromium/net/http/http_network_layer.cc
@@ -23,8 +23,7 @@
namespace net {
HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
- : session_(session),
- suspended_(false) {
+ : session_(session) {
DCHECK(session_);
#if BUILDFLAG(IS_WIN)
base::PowerMonitor::AddPowerSuspendObserver(this);
diff --git a/chromium/net/http/http_network_layer.h b/chromium/net/http/http_network_layer.h
index 0b8e361d2b0..4bbf32f1f2b 100644
--- a/chromium/net/http/http_network_layer.h
+++ b/chromium/net/http/http_network_layer.h
@@ -44,7 +44,7 @@ class NET_EXPORT HttpNetworkLayer : public HttpTransactionFactory,
private:
const raw_ptr<HttpNetworkSession> session_;
- bool suspended_;
+ bool suspended_ = false;
THREAD_CHECKER(thread_checker_);
};
diff --git a/chromium/net/http/http_network_session.cc b/chromium/net/http/http_network_session.cc
index fd3c01b7fc9..457bb677150 100644
--- a/chromium/net/http/http_network_session.cc
+++ b/chromium/net/http/http_network_session.cc
@@ -78,34 +78,9 @@ spdy::SettingsMap AddDefaultHttp2Settings(spdy::SettingsMap http2_settings) {
} // unnamed namespace
HttpNetworkSessionParams::HttpNetworkSessionParams()
- : enable_server_push_cancellation(false),
- ignore_certificate_errors(false),
- testing_fixed_http_port(0),
- testing_fixed_https_port(0),
- enable_user_alternate_protocol_ports(false),
- enable_spdy_ping_based_connection_checking(true),
- enable_http2(true),
- spdy_session_max_recv_window_size(kSpdySessionMaxRecvWindowSize),
+ : spdy_session_max_recv_window_size(kSpdySessionMaxRecvWindowSize),
spdy_session_max_queued_capped_frames(kSpdySessionMaxQueuedCappedFrames),
-// For OSs that terminate TCP connections upon relevant network changes,
-// attempt to preserve active streams by marking all sessions as going
-// away, rather than explicitly closing them. Streams may still fail due
-// to a generated TCP reset.
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
- spdy_go_away_on_ip_change(true),
-#else
- spdy_go_away_on_ip_change(false),
-#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
- enable_http2_settings_grease(false),
- http2_end_stream_with_data_frame(false),
- time_func(&base::TimeTicks::Now),
- enable_http2_alternative_service(false),
- enable_quic(true),
- enable_quic_proxies_for_https_urls(false),
- disable_idle_sockets_close_on_memory_pressure(false),
- key_auth_cache_server_entries_by_network_isolation_key(false),
- enable_priority_update(false),
- ignore_ip_address_changes(false) {
+ time_func(&base::TimeTicks::Now) {
enable_early_data =
base::FeatureList::IsEnabled(features::kEnableTLS13EarlyData);
}
@@ -167,7 +142,6 @@ HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params,
context.ct_policy_enforcer,
&ssl_client_session_cache_,
context.sct_auditing_delegate),
- push_delegate_(nullptr),
quic_stream_factory_(context.net_log,
context.host_resolver,
context.ssl_config_service,
@@ -274,7 +248,7 @@ ClientSocketPool* HttpNetworkSession::GetSocketPool(
return GetSocketPoolManager(pool_type)->GetSocketPool(proxy_server);
}
-std::unique_ptr<base::Value> HttpNetworkSession::SocketPoolInfoToValue() const {
+base::Value HttpNetworkSession::SocketPoolInfoToValue() const {
// TODO(yutak): Should merge values from normal pools and WebSocket pools.
return normal_socket_pool_manager_->SocketPoolInfoToValue();
}
@@ -285,74 +259,74 @@ std::unique_ptr<base::Value> HttpNetworkSession::SpdySessionPoolInfoToValue()
}
base::Value HttpNetworkSession::QuicInfoToValue() const {
- base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetKey("sessions",
- base::Value::FromUniquePtrValue(
- quic_stream_factory_.QuicStreamFactoryInfoToValue()));
- dict.SetBoolKey("quic_enabled", IsQuicEnabled());
+ base::Value::Dict dict;
+ dict.Set("sessions", quic_stream_factory_.QuicStreamFactoryInfoToValue());
+ dict.Set("quic_enabled", IsQuicEnabled());
const QuicParams* quic_params = context_.quic_context->params();
- base::Value connection_options(base::Value::Type::LIST);
+ base::Value::List connection_options;
for (const auto& option : quic_params->connection_options)
connection_options.Append(quic::QuicTagToString(option));
- dict.SetKey("connection_options", std::move(connection_options));
+ dict.Set("connection_options", std::move(connection_options));
- base::Value supported_versions(base::Value::Type::LIST);
+ base::Value::List supported_versions;
for (const auto& version : quic_params->supported_versions)
supported_versions.Append(ParsedQuicVersionToString(version));
- dict.SetKey("supported_versions", std::move(supported_versions));
+ dict.Set("supported_versions", std::move(supported_versions));
- base::Value origins_to_force_quic_on(base::Value::Type::LIST);
+ base::Value::List origins_to_force_quic_on;
for (const auto& origin : quic_params->origins_to_force_quic_on)
origins_to_force_quic_on.Append(origin.ToString());
- dict.SetKey("origins_to_force_quic_on", std::move(origins_to_force_quic_on));
-
- dict.SetIntKey("max_packet_length", quic_params->max_packet_length);
- dict.SetIntKey("max_server_configs_stored_in_properties",
- quic_params->max_server_configs_stored_in_properties);
- dict.SetIntKey("idle_connection_timeout_seconds",
- quic_params->idle_connection_timeout.InSeconds());
- dict.SetIntKey("reduced_ping_timeout_seconds",
- quic_params->reduced_ping_timeout.InSeconds());
- dict.SetBoolKey("retry_without_alt_svc_on_quic_errors",
- quic_params->retry_without_alt_svc_on_quic_errors);
- dict.SetBoolKey("disable_bidirectional_streams",
- quic_params->disable_bidirectional_streams);
- dict.SetBoolKey("close_sessions_on_ip_change",
- quic_params->close_sessions_on_ip_change);
- dict.SetBoolKey("goaway_sessions_on_ip_change",
- quic_params->goaway_sessions_on_ip_change);
- dict.SetBoolKey("migrate_sessions_on_network_change_v2",
- quic_params->migrate_sessions_on_network_change_v2);
- dict.SetBoolKey("migrate_sessions_early_v2",
- quic_params->migrate_sessions_early_v2);
- dict.SetIntKey("retransmittable_on_wire_timeout_milliseconds",
- quic_params->retransmittable_on_wire_timeout.InMilliseconds());
- dict.SetBoolKey("retry_on_alternate_network_before_handshake",
- quic_params->retry_on_alternate_network_before_handshake);
- dict.SetBoolKey("migrate_idle_sessions", quic_params->migrate_idle_sessions);
- dict.SetIntKey("idle_session_migration_period_seconds",
- quic_params->idle_session_migration_period.InSeconds());
- dict.SetIntKey("max_time_on_non_default_network_seconds",
- quic_params->max_time_on_non_default_network.InSeconds());
- dict.SetIntKey(
- "max_num_migrations_to_non_default_network_on_write_error",
- quic_params->max_migrations_to_non_default_network_on_write_error);
- dict.SetIntKey(
+ dict.Set("origins_to_force_quic_on", std::move(origins_to_force_quic_on));
+
+ dict.Set("max_packet_length",
+ static_cast<int>(quic_params->max_packet_length));
+ dict.Set(
+ "max_server_configs_stored_in_properties",
+ static_cast<int>(quic_params->max_server_configs_stored_in_properties));
+ dict.Set("idle_connection_timeout_seconds",
+ static_cast<int>(quic_params->idle_connection_timeout.InSeconds()));
+ dict.Set("reduced_ping_timeout_seconds",
+ static_cast<int>(quic_params->reduced_ping_timeout.InSeconds()));
+ dict.Set("retry_without_alt_svc_on_quic_errors",
+ quic_params->retry_without_alt_svc_on_quic_errors);
+ dict.Set("disable_bidirectional_streams",
+ quic_params->disable_bidirectional_streams);
+ dict.Set("close_sessions_on_ip_change",
+ quic_params->close_sessions_on_ip_change);
+ dict.Set("goaway_sessions_on_ip_change",
+ quic_params->goaway_sessions_on_ip_change);
+ dict.Set("migrate_sessions_on_network_change_v2",
+ quic_params->migrate_sessions_on_network_change_v2);
+ dict.Set("migrate_sessions_early_v2", quic_params->migrate_sessions_early_v2);
+ dict.Set("retransmittable_on_wire_timeout_milliseconds",
+ static_cast<int>(
+ quic_params->retransmittable_on_wire_timeout.InMilliseconds()));
+ dict.Set("retry_on_alternate_network_before_handshake",
+ quic_params->retry_on_alternate_network_before_handshake);
+ dict.Set("migrate_idle_sessions", quic_params->migrate_idle_sessions);
+ dict.Set(
+ "idle_session_migration_period_seconds",
+ static_cast<int>(quic_params->idle_session_migration_period.InSeconds()));
+ dict.Set("max_time_on_non_default_network_seconds",
+ static_cast<int>(
+ quic_params->max_time_on_non_default_network.InSeconds()));
+ dict.Set("max_num_migrations_to_non_default_network_on_write_error",
+ quic_params->max_migrations_to_non_default_network_on_write_error);
+ dict.Set(
"max_num_migrations_to_non_default_network_on_path_degrading",
quic_params->max_migrations_to_non_default_network_on_path_degrading);
- dict.SetBoolKey("allow_server_migration",
- quic_params->allow_server_migration);
- dict.SetBoolKey("race_stale_dns_on_connection",
- quic_params->race_stale_dns_on_connection);
- dict.SetBoolKey("estimate_initial_rtt", quic_params->estimate_initial_rtt);
- dict.SetBoolKey("server_push_cancellation",
- params_.enable_server_push_cancellation);
- dict.SetIntKey("initial_rtt_for_handshake_milliseconds",
- quic_params->initial_rtt_for_handshake.InMilliseconds());
-
- return dict;
+ dict.Set("allow_server_migration", quic_params->allow_server_migration);
+ dict.Set("race_stale_dns_on_connection",
+ quic_params->race_stale_dns_on_connection);
+ dict.Set("estimate_initial_rtt", quic_params->estimate_initial_rtt);
+ dict.Set("server_push_cancellation", params_.enable_server_push_cancellation);
+ dict.Set("initial_rtt_for_handshake_milliseconds",
+ static_cast<int>(
+ quic_params->initial_rtt_for_handshake.InMilliseconds()));
+
+ return base::Value(std::move(dict));
}
void HttpNetworkSession::CloseAllConnections(int net_error,
diff --git a/chromium/net/http/http_network_session.h b/chromium/net/http/http_network_session.h
index 3b96c6c062f..e963d52b9dd 100644
--- a/chromium/net/http/http_network_session.h
+++ b/chromium/net/http/http_network_session.h
@@ -22,6 +22,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
+#include "base/values.h"
#include "build/buildflag.h"
#include "net/base/host_mapping_rules.h"
#include "net/base/host_port_pair.h"
@@ -88,22 +89,30 @@ struct NET_EXPORT HttpNetworkSessionParams {
HttpNetworkSessionParams(const HttpNetworkSessionParams& other);
~HttpNetworkSessionParams();
- bool enable_server_push_cancellation;
+ bool enable_server_push_cancellation = false;
HostMappingRules host_mapping_rules;
- bool ignore_certificate_errors;
- uint16_t testing_fixed_http_port;
- uint16_t testing_fixed_https_port;
- bool enable_user_alternate_protocol_ports;
+ bool ignore_certificate_errors = false;
+ uint16_t testing_fixed_http_port = 0;
+ uint16_t testing_fixed_https_port = 0;
+ bool enable_user_alternate_protocol_ports = false;
// Use SPDY ping frames to test for connection health after idle.
- bool enable_spdy_ping_based_connection_checking;
- bool enable_http2;
+ bool enable_spdy_ping_based_connection_checking = true;
+ bool enable_http2 = true;
size_t spdy_session_max_recv_window_size;
// Maximum number of capped frames that can be queued at any time.
int spdy_session_max_queued_capped_frames;
// Whether SPDY pools should mark sessions as going away upon relevant network
// changes (instead of closing them). Default value is OS specific.
- bool spdy_go_away_on_ip_change;
+ // For OSs that terminate TCP connections upon relevant network changes,
+ // attempt to preserve active streams by marking all sessions as going
+ // away, rather than explicitly closing them. Streams may still fail due
+ // to a generated TCP reset.
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
+ bool spdy_go_away_on_ip_change = true;
+#else
+ bool spdy_go_away_on_ip_change = false;
+#endif
// HTTP/2 connection settings.
// Unknown settings will still be sent to the server.
// Might contain unknown setting identifiers from a predefined set that
@@ -117,7 +126,7 @@ struct NET_EXPORT HttpNetworkSessionParams {
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
// The setting identifier and value will be drawn independently for each
// connection to prevent tracking of the client.
- bool enable_http2_settings_grease;
+ bool enable_http2_settings_grease = false;
// If set, an HTTP/2 frame with a reserved frame type will be sent after
// every HTTP/2 SETTINGS frame and before every HTTP/2 DATA frame.
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
@@ -131,35 +140,35 @@ struct NET_EXPORT HttpNetworkSessionParams {
// If unset, the HEADERS frame will have the END_STREAM flag set on.
// This is useful in conjunction with |greased_http2_frame| so that a frame
// of reserved type can be sent out even on requests without a body.
- bool http2_end_stream_with_data_frame;
+ bool http2_end_stream_with_data_frame = false;
// Source of time for SPDY connections.
SpdySessionPool::TimeFunc time_func;
// Whether to enable HTTP/2 Alt-Svc entries.
- bool enable_http2_alternative_service;
+ bool enable_http2_alternative_service = false;
// Enables 0-RTT support.
bool enable_early_data;
// Enables QUIC support.
- bool enable_quic;
+ bool enable_quic = true;
// If true, HTTPS URLs can be sent to QUIC proxies.
- bool enable_quic_proxies_for_https_urls;
+ bool enable_quic_proxies_for_https_urls = false;
// If non-empty, QUIC will only be spoken to hosts in this list.
base::flat_set<std::string> quic_host_allowlist;
// If true, idle sockets won't be closed when memory pressure happens.
- bool disable_idle_sockets_close_on_memory_pressure;
+ bool disable_idle_sockets_close_on_memory_pressure = false;
- bool key_auth_cache_server_entries_by_network_isolation_key;
+ bool key_auth_cache_server_entries_by_network_isolation_key = false;
// If true, enable sending PRIORITY_UPDATE frames until SETTINGS frame
// arrives. After SETTINGS frame arrives, do not send PRIORITY_UPDATE
// frames any longer if SETTINGS_DEPRECATE_HTTP2_PRIORITIES is missing or
// has zero 0, but continue and also stop sending HTTP/2-style priority
// information in HEADERS frames and PRIORITY frames if it has value 1.
- bool enable_priority_update;
+ bool enable_priority_update = false;
// If true, objects used by a HttpNetworkTransaction are asked not to perform
// disruptive work after there has been an IP address change (which usually
@@ -168,7 +177,7 @@ struct NET_EXPORT HttpNetworkSessionParams {
// network: for these, the underlying network does never change, even if the
// default network does (hence underlying objects should not drop their
// state).
- bool ignore_ip_address_changes;
+ bool ignore_ip_address_changes = false;
};
// Structure with pointers to the dependencies of the HttpNetworkSession.
@@ -261,7 +270,7 @@ class NET_EXPORT HttpNetworkSession {
#endif
// Creates a Value summary of the state of the socket pools.
- std::unique_ptr<base::Value> SocketPoolInfoToValue() const;
+ base::Value SocketPoolInfoToValue() const;
// Creates a Value summary of the state of the SPDY sessions.
std::unique_ptr<base::Value> SpdySessionPoolInfoToValue() const;
diff --git a/chromium/net/http/http_network_transaction.cc b/chromium/net/http/http_network_transaction.cc
index 7ae9b23194e..5f530c81fcc 100644
--- a/chromium/net/http/http_network_transaction.cc
+++ b/chromium/net/http/http_network_transaction.cc
@@ -113,32 +113,10 @@ const int HttpNetworkTransaction::kDrainBodyBufferSize;
HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority,
HttpNetworkSession* session)
- : pending_auth_target_(HttpAuth::AUTH_NONE),
- io_callback_(base::BindRepeating(&HttpNetworkTransaction::OnIOComplete,
+ : io_callback_(base::BindRepeating(&HttpNetworkTransaction::OnIOComplete,
base::Unretained(this))),
session_(session),
- request_(nullptr),
- priority_(priority),
- headers_valid_(false),
- can_send_early_data_(false),
- configured_client_cert_for_server_(false),
- request_headers_(),
-#if BUILDFLAG(ENABLE_REPORTING)
- network_error_logging_report_generated_(false),
- request_reporting_upload_depth_(0),
-#endif // BUILDFLAG(ENABLE_REPORTING)
- read_buf_len_(0),
- total_received_bytes_(0),
- total_sent_bytes_(0),
- next_state_(STATE_NONE),
- establishing_tunnel_(false),
- enable_ip_based_pooling_(true),
- enable_alternative_services_(true),
- websocket_handshake_stream_base_create_helper_(nullptr),
- net_error_details_(),
- retry_attempts_(0),
- num_restarts_(0) {
-}
+ priority_(priority) {}
HttpNetworkTransaction::~HttpNetworkTransaction() {
#if BUILDFLAG(ENABLE_REPORTING)
@@ -908,9 +886,18 @@ int HttpNetworkTransaction::DoConnectedCallback() {
// HttpStream::GetAcceptChViaAlps() needs the HttpRequestInfo to retrieve
// the ACCEPT_CH frame payload.
stream_->RegisterRequest(request_);
- stream_->GetRemoteEndpoint(&remote_endpoint_);
next_state_ = STATE_CONNECTED_CALLBACK_COMPLETE;
+ int result = stream_->GetRemoteEndpoint(&remote_endpoint_);
+ if (result != OK) {
+ // `GetRemoteEndpoint()` fails when the underlying socket is not connected
+ // anymore, even though the peer's address is known. This can happen when
+ // we picked a socket from socket pools while it was still connected, but
+ // the remote side closes it before we get a chance to send our request.
+ // See if we should retry the request based on the error code we got.
+ return HandleIOError(result);
+ }
+
if (connected_callback_.is_null()) {
return OK;
}
@@ -1486,6 +1473,13 @@ void HttpNetworkTransaction::GenerateNetworkErrorLoggingReport(int rv) {
details.user_agent = request_user_agent_;
if (!remote_endpoint_.address().empty()) {
details.server_ip = remote_endpoint_.address();
+ } else if (!connection_attempts_.empty()) {
+ // When we failed to connect to the server, `remote_endpoint_` is not set.
+ // In such case, we use the last endpoint address of `connection_attempts_`
+ // for the NEL report. This address information is important for the
+ // downgrade step to protect against port scan attack.
+ // https://www.w3.org/TR/network-error-logging/#generate-a-network-error-report
+ details.server_ip = connection_attempts_.back().endpoint.address();
} else {
details.server_ip = IPAddress();
}
@@ -1574,9 +1568,10 @@ int HttpNetworkTransaction::HandleSSLClientAuthError(int error) {
}
// This method determines whether it is safe to resend the request after an
-// IO error. It can only be called in response to request header or body
-// write errors or response header read errors. It should not be used in
-// other cases, such as a Connect error.
+// IO error. It should only be called in response to errors received before
+// final set of response headers have been successfully parsed, that the
+// transaction may need to be retried on.
+// It should not be used in other cases, such as a Connect error.
int HttpNetworkTransaction::HandleIOError(int error) {
// Because the peer may request renegotiation with client authentication at
// any time, check and handle client authentication errors.
@@ -1723,9 +1718,7 @@ bool HttpNetworkTransaction::ShouldResendRequest() const {
// NOTE: we resend a request only if we reused a keep-alive connection.
// This automatically prevents an infinite resend loop because we'll run
// out of the cached keep-alive connections eventually.
- if (connection_is_proven && !has_received_headers)
- return true;
- return false;
+ return connection_is_proven && !has_received_headers;
}
bool HttpNetworkTransaction::HasExceededMaxRetries() const {
diff --git a/chromium/net/http/http_network_transaction.h b/chromium/net/http/http_network_transaction.h
index 38120f07544..525a4b1f9de 100644
--- a/chromium/net/http/http_network_transaction.h
+++ b/chromium/net/http/http_network_transaction.h
@@ -318,7 +318,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// Whether this transaction is waiting for proxy auth, server auth, or is
// not waiting for any auth at all. |pending_auth_target_| is read and
// cleared by RestartWithAuth().
- HttpAuth::Target pending_auth_target_;
+ HttpAuth::Target pending_auth_target_ = HttpAuth::AUTH_NONE;
CompletionRepeatingCallback io_callback_;
CompletionOnceCallback callback_;
@@ -328,7 +328,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
NetLogWithSource net_log_;
// Reset to null at the start of the Read state machine.
- raw_ptr<const HttpRequestInfo> request_;
+ raw_ptr<const HttpRequestInfo> request_ = nullptr;
// The requested URL.
GURL url_;
@@ -346,14 +346,14 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
std::unique_ptr<HttpStream> stream_;
// True if we've validated the headers that the stream parser has returned.
- bool headers_valid_;
+ bool headers_valid_ = false;
// True if we can send the request over early data.
- bool can_send_early_data_;
+ bool can_send_early_data_ = false;
// True if the client certificate for the server (rather than the proxy) was
// configured in this transaction.
- bool configured_client_cert_for_server_;
+ bool configured_client_cert_for_server_ = false;
// SSL configuration used for the server and proxy, respectively. Note
// |server_ssl_config_| may be updated from the HttpStreamFactory, which will
@@ -368,14 +368,14 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
HttpRequestHeaders request_headers_;
#if BUILDFLAG(ENABLE_REPORTING)
// Whether a NEL report has already been generated. Reset when restarting.
- bool network_error_logging_report_generated_;
+ bool network_error_logging_report_generated_ = false;
// Cache some fields from |request_| that we'll need to construct a NEL
// report about the request. (NEL report construction happens after we've
// cleared the |request_| pointer.)
std::string request_method_;
std::string request_referrer_;
std::string request_user_agent_;
- int request_reporting_upload_depth_;
+ int request_reporting_upload_depth_ = 0;
base::TimeTicks start_timeticks_;
#endif
@@ -386,15 +386,15 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// User buffer and length passed to the Read method.
scoped_refptr<IOBuffer> read_buf_;
- int read_buf_len_;
+ int read_buf_len_ = 0;
// Total number of bytes received on all destroyed HttpStreams for this
// transaction.
- int64_t total_received_bytes_;
+ int64_t total_received_bytes_ = 0;
// Total number of bytes sent on all destroyed HttpStreams for this
// transaction.
- int64_t total_sent_bytes_;
+ int64_t total_sent_bytes_ = 0;
// When the transaction started / finished sending the request, including
// the body, if present. |send_start_time_| is set to |base::TimeTicks()|
@@ -403,18 +403,18 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
base::TimeTicks send_end_time_;
// The next state in the state machine.
- State next_state_;
+ State next_state_ = STATE_NONE;
// True when the tunnel is in the process of being established - we can't
// read from the socket until the tunnel is done.
- bool establishing_tunnel_;
+ bool establishing_tunnel_ = false;
// Enable pooling to a SpdySession with matching IP and certificate
// even if the SpdySessionKey is different.
- bool enable_ip_based_pooling_;
+ bool enable_ip_based_pooling_ = true;
// Enable using alternative services for the request.
- bool enable_alternative_services_;
+ bool enable_alternative_services_ = true;
// When a request is retried because of errors with the alternative service,
// this will store the alternative service used.
@@ -423,7 +423,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// The helper object to use to create WebSocketHandshakeStreamBase
// objects. Only relevant when establishing a WebSocket connection.
raw_ptr<WebSocketHandshakeStreamBase::CreateHelper>
- websocket_handshake_stream_base_create_helper_;
+ websocket_handshake_stream_base_create_helper_ = nullptr;
BeforeNetworkStartCallback before_network_start_callback_;
ConnectedCallback connected_callback_;
@@ -443,10 +443,10 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// This count excludes retries on reused sockets since a well
// behaved server may time those out and thus the number
// of times we can retry a request on reused sockets is limited.
- size_t retry_attempts_;
+ size_t retry_attempts_ = 0;
// Number of times the transaction was restarted via a RestartWith* call.
- size_t num_restarts_;
+ size_t num_restarts_ = 0;
bool close_connection_on_destruction_ = false;
};
diff --git a/chromium/net/http/http_network_transaction_unittest.cc b/chromium/net/http/http_network_transaction_unittest.cc
index d9225864e3a..26120aade9c 100644
--- a/chromium/net/http/http_network_transaction_unittest.cc
+++ b/chromium/net/http/http_network_transaction_unittest.cc
@@ -9368,7 +9368,6 @@ TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2WithWebsockets) {
ssl1.next_protos_expected_in_ssl_config = NextProtoVector{kProtoHTTP11};
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.enable_websocket_over_http2 = true;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
HttpRequestInfo initial_request_info;
@@ -15171,8 +15170,8 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
MockWrite write;
MockRead read;
int expected_rv;
- const MockWrite* extra_write;
- const MockRead* extra_read;
+ raw_ptr<const MockWrite> extra_write;
+ raw_ptr<const MockRead> extra_read;
};
static const int kNoSSL = 500;
@@ -20330,12 +20329,54 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, CreateReportSuccess) {
}
TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
+ CreateReportDNSErrorAfterStartSync) {
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+ auto trans =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+
+ session_deps_.host_resolver->set_synchronous_mode(true);
+ session_deps_.host_resolver->rules()->AddRule(GURL(url_).host(),
+ ERR_NAME_NOT_RESOLVED);
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
+
+ trans.reset();
+
+ ASSERT_EQ(1u, network_error_logging_service()->errors().size());
+ CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
+ IPAddress() /* server_ip */);
+}
+
+TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
+ CreateReportDNSErrorAfterStartAsync) {
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+ auto trans =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+
+ session_deps_.host_resolver->set_synchronous_mode(false);
+ session_deps_.host_resolver->rules()->AddRule(GURL(url_).host(),
+ ERR_NAME_NOT_RESOLVED);
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
+
+ trans.reset();
+
+ ASSERT_EQ(1u, network_error_logging_service()->errors().size());
+ CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
+ IPAddress() /* server_ip */);
+}
+
+TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
CreateReportErrorAfterStart) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
auto trans =
std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(SYNCHRONOUS, ERR_NAME_NOT_RESOLVED);
+ MockConnect mock_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
StaticSocketDataProvider data;
data.set_connect_data(mock_connect);
session_deps_.socket_factory->AddSocketDataProvider(&data);
@@ -20343,13 +20384,13 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
TestCompletionCallback callback;
int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
trans.reset();
ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
- IPAddress() /* server_ip */);
+ CheckReport(0 /* index */, 0 /* status_code */, ERR_CONNECTION_REFUSED,
+ IPAddress::IPv4Localhost() /* server_ip */);
}
// Same as above except the error is ASYNC
@@ -20359,7 +20400,7 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
auto trans =
std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(ASYNC, ERR_NAME_NOT_RESOLVED);
+ MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
StaticSocketDataProvider data;
data.set_connect_data(mock_connect);
session_deps_.socket_factory->AddSocketDataProvider(&data);
@@ -20367,13 +20408,13 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
TestCompletionCallback callback;
int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
trans.reset();
ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
- IPAddress() /* server_ip */);
+ CheckReport(0 /* index */, 0 /* status_code */, ERR_CONNECTION_REFUSED,
+ IPAddress::IPv4Localhost() /* server_ip */);
}
TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
diff --git a/chromium/net/http/http_proxy_client_socket.cc b/chromium/net/http/http_proxy_client_socket.cc
index 195c1cf93a8..80623ee1e66 100644
--- a/chromium/net/http/http_proxy_client_socket.cc
+++ b/chromium/net/http/http_proxy_client_socket.cc
@@ -41,9 +41,7 @@ HttpProxyClientSocket::HttpProxyClientSocket(
const NetworkTrafficAnnotationTag& traffic_annotation)
: io_callback_(base::BindRepeating(&HttpProxyClientSocket::OnIOComplete,
base::Unretained(this))),
- next_state_(STATE_NONE),
socket_(std::move(socket)),
- is_reused_(false),
endpoint_(endpoint),
auth_(http_auth_controller),
proxy_server_(proxy_server),
@@ -151,11 +149,6 @@ bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
-void HttpProxyClientSocket::GetConnectionAttempts(
- ConnectionAttempts* out) const {
- out->clear();
-}
-
int64_t HttpProxyClientSocket::GetTotalReceivedBytes() const {
return socket_->GetTotalReceivedBytes();
}
diff --git a/chromium/net/http/http_proxy_client_socket.h b/chromium/net/http/http_proxy_client_socket.h
index 369701fa771..4c82607381c 100644
--- a/chromium/net/http/http_proxy_client_socket.h
+++ b/chromium/net/http/http_proxy_client_socket.h
@@ -69,9 +69,6 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
bool WasAlpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
- void GetConnectionAttempts(ConnectionAttempts* out) const override;
- void ClearConnectionAttempts() override {}
- void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
int64_t GetTotalReceivedBytes() const override;
void ApplySocketTag(const SocketTag& tag) override;
@@ -131,7 +128,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
bool CheckDone();
CompletionRepeatingCallback io_callback_;
- State next_state_;
+ State next_state_ = STATE_NONE;
// Stores the callback provided by the caller of async operations.
CompletionOnceCallback user_callback_;
@@ -147,7 +144,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
// Whether or not |socket_| has been previously used. Once auth credentials
// are sent, set to true.
- bool is_reused_;
+ bool is_reused_ = false;
// The hostname and port of the endpoint. This is not necessarily the one
// specified by the URL, due to Alternate-Protocol or fixed testing ports.
diff --git a/chromium/net/http/http_proxy_connect_job.cc b/chromium/net/http/http_proxy_connect_job.cc
index 5fadbafb011..9a95455672c 100644
--- a/chromium/net/http/http_proxy_connect_job.cc
+++ b/chromium/net/http/http_proxy_connect_job.cc
@@ -188,9 +188,6 @@ HttpProxyConnectJob::HttpProxyConnectJob(
NetLogSourceType::HTTP_PROXY_CONNECT_JOB,
NetLogEventType::HTTP_PROXY_CONNECT_JOB_CONNECT),
params_(std::move(params)),
- next_state_(STATE_NONE),
- has_restarted_(false),
- has_established_connection_(false),
http_auth_controller_(
params_->tunnel()
? base::MakeRefCounted<HttpAuthController>(
@@ -441,9 +438,9 @@ int HttpProxyConnectJob::DoBeginConnect() {
int HttpProxyConnectJob::DoTransportConnect() {
ProxyServer::Scheme scheme = GetProxyServerScheme();
if (scheme == ProxyServer::SCHEME_HTTP) {
- nested_connect_job_ = TransportConnectJob::CreateTransportConnectJob(
- params_->transport_params(), priority(), socket_tag(),
- common_connect_job_params(), this, &net_log());
+ nested_connect_job_ = std::make_unique<TransportConnectJob>(
+ priority(), socket_tag(), common_connect_job_params(),
+ params_->transport_params(), this, &net_log());
} else {
DCHECK_EQ(scheme, ProxyServer::SCHEME_HTTPS);
DCHECK(params_->ssl_params());
@@ -660,7 +657,8 @@ int HttpProxyConnectJob::DoQuicProxyCreateSession() {
quic_version, ssl_params->privacy_mode(), kH2QuicTunnelPriority,
socket_tag(), params_->network_isolation_key(),
ssl_params->GetDirectConnectionParams()->secure_dns_policy(),
- /*use_dns_aliases=*/false, ssl_params->ssl_config().GetCertVerifyFlags(),
+ /*use_dns_aliases=*/false, /*require_dns_https_alpn=*/false,
+ ssl_params->ssl_config().GetCertVerifyFlags(),
GURL("https://" + proxy_server.ToString()), net_log(),
&quic_net_error_details_,
/*failed_on_default_network_callback=*/CompletionOnceCallback(),
diff --git a/chromium/net/http/http_proxy_connect_job.h b/chromium/net/http/http_proxy_connect_job.h
index 3ef13066025..8587092cf1a 100644
--- a/chromium/net/http/http_proxy_connect_job.h
+++ b/chromium/net/http/http_proxy_connect_job.h
@@ -222,13 +222,13 @@ class NET_EXPORT_PRIVATE HttpProxyConnectJob : public ConnectJob,
scoped_refptr<SSLCertRequestInfo> ssl_cert_request_info_;
- State next_state_;
+ State next_state_ = STATE_NONE;
- bool has_restarted_;
+ bool has_restarted_ = false;
// Set to true once a connection has been successfully established. Remains
// true even if a new socket is being connected to retry with auth.
- bool has_established_connection_;
+ bool has_established_connection_ = false;
ResolveErrorInfo resolve_error_info_;
diff --git a/chromium/net/http/http_request_headers.cc b/chromium/net/http/http_request_headers.cc
index e7855a169d6..ea36ce6f63d 100644
--- a/chromium/net/http/http_request_headers.cc
+++ b/chromium/net/http/http_request_headers.cc
@@ -8,12 +8,12 @@
#include "base/logging.h"
#include "base/notreached.h"
+#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
-#include "net/base/escape.h"
#include "net/http/http_log_util.h"
#include "net/http/http_util.h"
#include "net/log/net_log_capture_mode.h"
@@ -64,9 +64,7 @@ HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair(
: key(key.data(), key.size()), value(value.data(), value.size()) {}
HttpRequestHeaders::Iterator::Iterator(const HttpRequestHeaders& headers)
- : started_(false),
- curr_(headers.headers_.begin()),
- end_(headers.headers_.end()) {}
+ : curr_(headers.headers_.begin()), end_(headers.headers_.end()) {}
HttpRequestHeaders::Iterator::~Iterator() = default;
diff --git a/chromium/net/http/http_request_headers.h b/chromium/net/http/http_request_headers.h
index dbc3124def7..c1a956e0a80 100644
--- a/chromium/net/http/http_request_headers.h
+++ b/chromium/net/http/http_request_headers.h
@@ -56,7 +56,7 @@ class NET_EXPORT HttpRequestHeaders {
const std::string& value() const { return curr_->value; }
private:
- bool started_;
+ bool started_ = false;
HttpRequestHeaders::HeaderVector::const_iterator curr_;
const HttpRequestHeaders::HeaderVector::const_iterator end_;
};
diff --git a/chromium/net/http/http_request_info.cc b/chromium/net/http/http_request_info.cc
index faf31912abf..adac030ea8d 100644
--- a/chromium/net/http/http_request_info.cc
+++ b/chromium/net/http/http_request_info.cc
@@ -8,14 +8,7 @@
namespace net {
-HttpRequestInfo::HttpRequestInfo()
- : is_subframe_document_resource(false),
- upload_data_stream(nullptr),
- load_flags(0),
- privacy_mode(PRIVACY_MODE_DISABLED),
- secure_dns_policy(SecureDnsPolicy::kAllow),
- reporting_upload_depth(0),
- idempotency(net::DEFAULT_IDEMPOTENCY) {}
+HttpRequestInfo::HttpRequestInfo() = default;
HttpRequestInfo::HttpRequestInfo(const HttpRequestInfo& other) = default;
diff --git a/chromium/net/http/http_request_info.h b/chromium/net/http/http_request_info.h
index 4292be327a5..ff52954b981 100644
--- a/chromium/net/http/http_request_info.h
+++ b/chromium/net/http/http_request_info.h
@@ -40,23 +40,23 @@ struct NET_EXPORT HttpRequestInfo {
NetworkIsolationKey network_isolation_key;
// True if it is a subframe's document resource.
- bool is_subframe_document_resource;
+ bool is_subframe_document_resource = false;
// Any extra request headers (including User-Agent).
HttpRequestHeaders extra_headers;
// Any upload data.
- raw_ptr<UploadDataStream> upload_data_stream;
+ raw_ptr<UploadDataStream> upload_data_stream = nullptr;
// Any load flags (see load_flags.h).
- int load_flags;
+ int load_flags = 0;
// If enabled, then request must be sent over connection that cannot be
// tracked by the server (e.g. without channel id).
- PrivacyMode privacy_mode;
+ PrivacyMode privacy_mode = PRIVACY_MODE_DISABLED;
// Secure DNS Tag for the request.
- SecureDnsPolicy secure_dns_policy;
+ SecureDnsPolicy secure_dns_policy = SecureDnsPolicy::kAllow;
// Tag applied to all sockets used to service request.
SocketTag socket_tag;
@@ -70,7 +70,7 @@ struct NET_EXPORT HttpRequestInfo {
//
// If the request is a Reporting upload, the depth is the max of the depth
// of the requests reported within it plus 1.
- int reporting_upload_depth;
+ int reporting_upload_depth = 0;
// This may the top frame origin associated with a request, or it may be the
// top frame site. Or it may be nullptr. Only used for histograms.
@@ -87,7 +87,15 @@ struct NET_EXPORT HttpRequestInfo {
// replay the request. If the request has any side effects, those effects can
// happen multiple times. It is only safe to enable the 0-RTT if it is known
// that the request is idempotent.
- net::Idempotency idempotency;
+ net::Idempotency idempotency = net::DEFAULT_IDEMPOTENCY;
+
+ // Index of the requested URL in Cache Transparency's pervasive payload list.
+ // Only used for logging purposes.
+ int pervasive_payloads_index_for_logging = -1;
+
+ // Checksum of the request body and selected headers, in upper-case
+ // hexadecimal. Only non-empty if the USE_SINGLE_KEYED_CACHE load flag is set.
+ std::string checksum;
};
} // namespace net
diff --git a/chromium/net/http/http_response_body_drainer.cc b/chromium/net/http/http_response_body_drainer.cc
index bca2f5fe3a1..9591c58c96f 100644
--- a/chromium/net/http/http_response_body_drainer.cc
+++ b/chromium/net/http/http_response_body_drainer.cc
@@ -20,10 +20,7 @@ const int HttpResponseBodyDrainer::kDrainBodyBufferSize;
const int HttpResponseBodyDrainer::kTimeoutInSeconds;
HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStream* stream)
- : stream_(stream),
- next_state_(STATE_NONE),
- total_read_(0),
- session_(nullptr) {}
+ : stream_(stream) {}
HttpResponseBodyDrainer::~HttpResponseBodyDrainer() = default;
diff --git a/chromium/net/http/http_response_body_drainer.h b/chromium/net/http/http_response_body_drainer.h
index 4ad3f5da318..5ba92fa0be1 100644
--- a/chromium/net/http/http_response_body_drainer.h
+++ b/chromium/net/http/http_response_body_drainer.h
@@ -55,10 +55,10 @@ class NET_EXPORT_PRIVATE HttpResponseBodyDrainer {
scoped_refptr<IOBuffer> read_buf_;
const std::unique_ptr<HttpStream> stream_;
- State next_state_;
- int total_read_;
+ State next_state_ = STATE_NONE;
+ int total_read_ = 0;
base::OneShotTimer timer_;
- raw_ptr<HttpNetworkSession> session_;
+ raw_ptr<HttpNetworkSession> session_ = nullptr;
};
} // namespace net
diff --git a/chromium/net/http/http_response_body_drainer_unittest.cc b/chromium/net/http/http_response_body_drainer_unittest.cc
index ed70a0d0f83..13cdd3c74eb 100644
--- a/chromium/net/http/http_response_body_drainer_unittest.cc
+++ b/chromium/net/http/http_response_body_drainer_unittest.cc
@@ -48,10 +48,7 @@ static_assert((HttpResponseBodyDrainer::kDrainBodyBufferSize %
class CloseResultWaiter {
public:
- CloseResultWaiter()
- : result_(false),
- have_result_(false),
- waiting_for_result_(false) {}
+ CloseResultWaiter() = default;
CloseResultWaiter(const CloseResultWaiter&) = delete;
CloseResultWaiter& operator=(const CloseResultWaiter&) = delete;
@@ -74,23 +71,15 @@ class CloseResultWaiter {
}
private:
- int result_;
- bool have_result_;
- bool waiting_for_result_;
+ int result_ = false;
+ bool have_result_ = false;
+ bool waiting_for_result_ = false;
};
class MockHttpStream : public HttpStream {
public:
- MockHttpStream(CloseResultWaiter* result_waiter)
- : result_waiter_(result_waiter),
- buf_len_(0),
- closed_(false),
- stall_reads_forever_(false),
- num_chunks_(0),
- is_sync_(false),
- is_last_chunk_zero_size_(false),
- is_complete_(false),
- can_reuse_connection_(true) {}
+ explicit MockHttpStream(CloseResultWaiter* result_waiter)
+ : result_waiter_(result_waiter) {}
MockHttpStream(const MockHttpStream&) = delete;
MockHttpStream& operator=(const MockHttpStream&) = delete;
@@ -125,7 +114,9 @@ class MockHttpStream : public HttpStream {
}
void GetSSLInfo(SSLInfo* ssl_info) override {}
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
- bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
+ int GetRemoteEndpoint(IPEndPoint* endpoint) override {
+ return ERR_UNEXPECTED;
+ }
// Mocked API
int ReadResponseBody(IOBuffer* buf,
@@ -183,14 +174,14 @@ class MockHttpStream : public HttpStream {
const raw_ptr<CloseResultWaiter> result_waiter_;
scoped_refptr<IOBuffer> user_buf_;
CompletionOnceCallback callback_;
- int buf_len_;
- bool closed_;
- bool stall_reads_forever_;
- int num_chunks_;
- bool is_sync_;
- bool is_last_chunk_zero_size_;
- bool is_complete_;
- bool can_reuse_connection_;
+ int buf_len_ = 0;
+ bool closed_ = false;
+ bool stall_reads_forever_ = false;
+ int num_chunks_ = 0;
+ bool is_sync_ = false;
+ bool is_last_chunk_zero_size_ = false;
+ bool is_complete_ = false;
+ bool can_reuse_connection_ = true;
base::WeakPtrFactory<MockHttpStream> weak_factory_{this};
};
diff --git a/chromium/net/http/http_response_headers.cc b/chromium/net/http/http_response_headers.cc
index 91536513f3d..727cebff27e 100644
--- a/chromium/net/http/http_response_headers.cc
+++ b/chromium/net/http/http_response_headers.cc
@@ -19,6 +19,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/pickle.h"
+#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -27,10 +28,10 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
-#include "net/base/escape.h"
#include "net/base/parse_number.h"
#include "net/http/http_byte_range.h"
#include "net/http/http_log_util.h"
+#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_values.h"
@@ -110,7 +111,7 @@ const char* const kNonUpdatedHeaderPrefixes[] = {
bool ShouldUpdateHeader(base::StringPiece name) {
for (size_t i = 0; i < std::size(kNonUpdatedHeaders); ++i) {
- if (base::LowerCaseEqualsASCII(name, kNonUpdatedHeaders[i]))
+ if (base::EqualsCaseInsensitiveASCII(name, kNonUpdatedHeaders[i]))
return false;
}
for (size_t i = 0; i < std::size(kNonUpdatedHeaderPrefixes); ++i) {
@@ -263,8 +264,8 @@ void HttpResponseHeaders::Persist(base::Pickle* pickle,
}
void HttpResponseHeaders::Update(const HttpResponseHeaders& new_headers) {
- DCHECK(new_headers.response_code() == 304 ||
- new_headers.response_code() == 206);
+ DCHECK(new_headers.response_code() == net::HTTP_NOT_MODIFIED ||
+ new_headers.response_code() == net::HTTP_PARTIAL_CONTENT);
// Copy up to the null byte. This just copies the status line.
std::string new_raw_headers(raw_headers_.c_str());
@@ -707,7 +708,7 @@ void HttpResponseHeaders::ParseStatusLine(
if (p == line_end) {
DVLOG(1) << "missing response status; assuming 200 OK";
raw_headers_.append(" 200 OK");
- response_code_ = 200;
+ response_code_ = net::HTTP_OK;
return;
}
@@ -722,7 +723,7 @@ void HttpResponseHeaders::ParseStatusLine(
if (p == code) {
DVLOG(1) << "missing response status number; assuming 200";
raw_headers_.append(" 200");
- response_code_ = 200;
+ response_code_ = net::HTTP_OK;
return;
}
raw_headers_.push_back(' ');
@@ -962,7 +963,7 @@ bool HttpResponseHeaders::IsRedirect(std::string* location) const {
// valid UTF-8, so encoding errors turn into replacement characters before
// escaping. Escaping here preserves the bytes as-is. See
// https://crbug.com/942073#c14.
- *location = EscapeNonASCII(location_strpiece);
+ *location = base::EscapeNonASCII(location_strpiece);
}
return true;
@@ -972,8 +973,11 @@ bool HttpResponseHeaders::IsRedirect(std::string* location) const {
bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) {
// Users probably want to see 300 (multiple choice) pages, so we don't count
// them as redirects that need to be followed.
- return (response_code == 301 || response_code == 302 ||
- response_code == 303 || response_code == 307 || response_code == 308);
+ return (response_code == net::HTTP_MOVED_PERMANENTLY ||
+ response_code == net::HTTP_FOUND ||
+ response_code == net::HTTP_SEE_OTHER ||
+ response_code == net::HTTP_TEMPORARY_REDIRECT ||
+ response_code == net::HTTP_PERMANENT_REDIRECT);
}
// From RFC 2616 section 13.2.4:
@@ -1101,8 +1105,9 @@ HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
// https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an
// experimental RFC that adds 308 permanent redirect as well, for which "any
// future references ... SHOULD use one of the returned URIs."
- if ((response_code_ == 200 || response_code_ == 203 ||
- response_code_ == 206) &&
+ if ((response_code_ == net::HTTP_OK ||
+ response_code_ == net::HTTP_NON_AUTHORITATIVE_INFORMATION ||
+ response_code_ == net::HTTP_PARTIAL_CONTENT) &&
!must_revalidate) {
// TODO(darin): Implement a smarter heuristic.
Time last_modified_value;
@@ -1116,8 +1121,10 @@ HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
}
// These responses are implicitly fresh (unless otherwise overruled):
- if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 ||
- response_code_ == 410) {
+ if (response_code_ == net::HTTP_MULTIPLE_CHOICES ||
+ response_code_ == net::HTTP_MOVED_PERMANENTLY ||
+ response_code_ == net::HTTP_PERMANENT_REDIRECT ||
+ response_code_ == net::HTTP_GONE) {
lifetimes.freshness = base::TimeDelta::Max();
lifetimes.staleness = base::TimeDelta(); // It should never be stale.
return lifetimes;
@@ -1293,7 +1300,7 @@ bool HttpResponseHeaders::IsKeepAlive() const {
std::string token;
while (EnumerateHeader(&iterator, header, &token)) {
for (const KeepAliveToken& keep_alive_token : kKeepAliveTokens) {
- if (base::LowerCaseEqualsASCII(token, keep_alive_token.token))
+ if (base::EqualsCaseInsensitiveASCII(token, keep_alive_token.token))
return keep_alive_token.keep_alive;
}
}
diff --git a/chromium/net/http/http_response_info.cc b/chromium/net/http/http_response_info.cc
index cc35dd83961..e96d6da97c1 100644
--- a/chromium/net/http/http_response_info.cc
+++ b/chromium/net/http/http_response_info.cc
@@ -117,6 +117,10 @@ enum {
// This bit is set if the response has a nonempty `dns_aliases` entry.
RESPONSE_INFO_HAS_DNS_ALIASES = 1 << 27,
+ // This bit is set for an entry in the single-keyed cache that has been marked
+ // unusable due to the checksum not matching.
+ RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE = 1 << 28,
+
// TODO(darin): Add other bits to indicate alternate request methods.
// For now, we don't support storing those.
};
@@ -183,18 +187,7 @@ HttpResponseInfo::ConnectionInfoCoarse HttpResponseInfo::ConnectionInfoToCoarse(
return CONNECTION_INFO_COARSE_OTHER;
}
-HttpResponseInfo::HttpResponseInfo()
- : was_cached(false),
- cache_entry_status(CacheEntryStatus::ENTRY_UNDEFINED),
- network_accessed(false),
- was_fetched_via_spdy(false),
- was_alpn_negotiated(false),
- was_fetched_via_proxy(false),
- did_use_http_auth(false),
- unused_since_prefetch(false),
- restricted_prefetch(false),
- async_revalidation_requested(false),
- connection_info(CONNECTION_INFO_UNKNOWN) {}
+HttpResponseInfo::HttpResponseInfo() = default;
HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) = default;
@@ -357,6 +350,9 @@ bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
restricted_prefetch = (flags & RESPONSE_INFO_RESTRICTED_PREFETCH) != 0;
+ single_keyed_cache_entry_unusable =
+ (flags & RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE) != 0;
+
ssl_info.pkp_bypassed = (flags & RESPONSE_INFO_PKP_BYPASSED) != 0;
// Read peer_signature_algorithm.
@@ -422,6 +418,8 @@ void HttpResponseInfo::Persist(base::Pickle* pickle,
flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH;
if (restricted_prefetch)
flags |= RESPONSE_INFO_RESTRICTED_PREFETCH;
+ if (single_keyed_cache_entry_unusable)
+ flags |= RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE;
if (ssl_info.pkp_bypassed)
flags |= RESPONSE_INFO_PKP_BYPASSED;
if (!stale_revalidate_timeout.is_null())
diff --git a/chromium/net/http/http_response_info.h b/chromium/net/http/http_response_info.h
index a6d80e494ed..e09a96c4b5c 100644
--- a/chromium/net/http/http_response_info.h
+++ b/chromium/net/http/http_response_info.h
@@ -147,45 +147,60 @@ class NET_EXPORT HttpResponseInfo {
// when reloading previously visited pages (without going over the network).
// Note also that under normal circumstances, was_cached is set to the correct
// value even if the request fails.
- bool was_cached;
+ bool was_cached = false;
// How this response was handled by the HTTP cache.
- CacheEntryStatus cache_entry_status;
+ CacheEntryStatus cache_entry_status = CacheEntryStatus::ENTRY_UNDEFINED;
// True if the request accessed the network in the process of retrieving
// data.
- bool network_accessed;
+ bool network_accessed = false;
// True if the request was fetched over a SPDY channel.
- bool was_fetched_via_spdy;
+ bool was_fetched_via_spdy = false;
// True if ALPN was negotiated for this request.
- bool was_alpn_negotiated;
+ bool was_alpn_negotiated = false;
- // True if the request was fetched via an explicit proxy. The proxy could
+ // True if the response was fetched via an explicit proxy. The proxy could
// be any type of proxy, HTTP or SOCKS. Note, we do not know if a
- // transparent proxy may have been involved. If true, |proxy_server| contains
- // the proxy server that was used.
- // TODO(tbansal): crbug.com/653354. Remove |was_fetched_via_proxy|.
- bool was_fetched_via_proxy;
+ // transparent proxy may have been involved.
+ //
+ // If true and this struct was not restored from pickled data, |proxy_server|
+ // contains the proxy server that was used.
+ //
+ // TODO(https://crbug.com/653354): Remove this in favor of |proxy_server|.
+ bool was_fetched_via_proxy = false;
+
+ // Information about the proxy used to fetch this response, if any.
+ //
+ // This field is not persisted by |Persist()| and not restored by
+ // |InitFromPickle()|.
+ //
+ // TODO(https://crbug.com/653354): Support this field in |Persist()| and
+ // |InitFromPickle()| then use it to replace |was_fetched_via_proxy|.
ProxyServer proxy_server;
// Whether the request use http proxy or server authentication.
- bool did_use_http_auth;
+ bool did_use_http_auth = false;
// True if the resource was originally fetched for a prefetch and has not been
// used since.
- bool unused_since_prefetch;
+ bool unused_since_prefetch = false;
// True if the response is a prefetch whose reuse is "restricted". This means
// it can only be reused from the cache by requests that are marked as able to
// use restricted prefetches.
- bool restricted_prefetch;
+ bool restricted_prefetch = false;
// True if this resource is stale and needs async revalidation.
// This value is not persisted by Persist(); it is only ever set when the
// response is retrieved from the cache.
- bool async_revalidation_requested;
+ bool async_revalidation_requested = false;
+
+ // True if this entry in the single-keyed cache is unusable due to a checksum
+ // mismatch.
+ bool single_keyed_cache_entry_unusable = false;
// stale-while-revalidate, if any, will be honored until time given by
// |stale_revalidate_timeout|. This value is latched the first time
@@ -205,7 +220,7 @@ class NET_EXPORT HttpResponseInfo {
std::string alpn_negotiated_protocol;
// The type of connection used for this response.
- ConnectionInfo connection_info;
+ ConnectionInfo connection_info = CONNECTION_INFO_UNKNOWN;
// The time at which the request was made that resulted in this response.
// For cached responses, this is the last time the cache entry was validated.
diff --git a/chromium/net/http/http_security_headers.cc b/chromium/net/http/http_security_headers.cc
index 39eb8191ebc..15defb9c4ff 100644
--- a/chromium/net/http/http_security_headers.cc
+++ b/chromium/net/http/http_security_headers.cc
@@ -102,10 +102,11 @@ bool ParseHSTSHeader(const std::string& value,
case DIRECTIVE_END:
if (base::IsAsciiWhitespace(token[0]))
continue;
- if (base::LowerCaseEqualsASCII(token, "max-age")) {
+ if (base::EqualsCaseInsensitiveASCII(token, "max-age")) {
state = AFTER_MAX_AGE_LABEL;
max_age_observed++;
- } else if (base::LowerCaseEqualsASCII(token, "includesubdomains")) {
+ } else if (base::EqualsCaseInsensitiveASCII(token,
+ "includesubdomains")) {
state = AFTER_INCLUDE_SUBDOMAINS;
include_subdomains_observed++;
include_subdomains_candidate = true;
@@ -198,7 +199,7 @@ bool ParseExpectCTHeader(const std::string& value,
while (name_value_pairs.GetNext()) {
base::StringPiece name = name_value_pairs.name_piece();
- if (base::LowerCaseEqualsASCII(name, "max-age")) {
+ if (base::EqualsCaseInsensitiveASCII(name, "max-age")) {
// "A given directive MUST NOT appear more than once in a given header
// field."
if (parsed_max_age)
@@ -208,7 +209,7 @@ bool ParseExpectCTHeader(const std::string& value,
return false;
}
parsed_max_age = true;
- } else if (base::LowerCaseEqualsASCII(name, "enforce")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "enforce")) {
// "A given directive MUST NOT appear more than once in a given header
// field."
if (enforce_candidate)
@@ -216,7 +217,7 @@ bool ParseExpectCTHeader(const std::string& value,
if (!name_value_pairs.value_piece().empty())
return false;
enforce_candidate = true;
- } else if (base::LowerCaseEqualsASCII(name, "report-uri")) {
+ } else if (base::EqualsCaseInsensitiveASCII(name, "report-uri")) {
// "A given directive MUST NOT appear more than once in a given header
// field."
if (has_report_uri)
diff --git a/chromium/net/http/http_server_properties.cc b/chromium/net/http/http_server_properties.cc
index 0ac003c574e..3adcc93fcbd 100644
--- a/chromium/net/http/http_server_properties.cc
+++ b/chromium/net/http/http_server_properties.cc
@@ -143,7 +143,6 @@ HttpServerProperties::HttpServerProperties(
use_network_isolation_key_(base::FeatureList::IsEnabled(
features::kPartitionHttpServerPropertiesByNetworkIsolationKey)),
is_initialized_(pref_delegate.get() == nullptr),
- queue_write_on_load_(false),
properties_manager_(
pref_delegate
? std::make_unique<HttpServerPropertiesManager>(
diff --git a/chromium/net/http/http_server_properties.h b/chromium/net/http/http_server_properties.h
index 2d782f38455..94c1573e620 100644
--- a/chromium/net/http/http_server_properties.h
+++ b/chromium/net/http/http_server_properties.h
@@ -610,7 +610,7 @@ class NET_EXPORT HttpServerProperties
// Queue a write when resources finish loading. Set to true when
// MaybeQueueWriteProperties() is invoked while still waiting on
// initialization to complete.
- bool queue_write_on_load_;
+ bool queue_write_on_load_ = false;
// Used to load/save properties from/to preferences. May be nullptr.
std::unique_ptr<HttpServerPropertiesManager> properties_manager_;
diff --git a/chromium/net/http/http_server_properties_manager.cc b/chromium/net/http/http_server_properties_manager.cc
index 3513f4fd685..7f7e696bea7 100644
--- a/chromium/net/http/http_server_properties_manager.cc
+++ b/chromium/net/http/http_server_properties_manager.cc
@@ -107,29 +107,26 @@ AlternativeServiceInfoVector GetAlternativeServiceToPersist(
void AddAlternativeServiceFieldsToDictionaryValue(
const AlternativeService& alternative_service,
- base::Value* dict) {
- DCHECK(dict->is_dict());
- dict->SetIntKey(kPortKey, alternative_service.port);
+ base::Value::Dict& dict) {
+ dict.Set(kPortKey, alternative_service.port);
if (!alternative_service.host.empty()) {
- dict->SetStringKey(kHostKey, alternative_service.host);
+ dict.Set(kHostKey, alternative_service.host);
}
- dict->SetStringKey(kProtocolKey,
- NextProtoToString(alternative_service.protocol));
+ dict.Set(kProtocolKey, NextProtoToString(alternative_service.protocol));
}
// Fails in the case of NetworkIsolationKeys that can't be persisted to disk,
// like unique origins.
bool TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
const BrokenAlternativeService& broken_alt_service,
- base::Value* dict) {
- DCHECK(dict->is_dict());
+ base::Value::Dict& dict) {
base::Value network_isolation_key_value;
if (!broken_alt_service.network_isolation_key.ToValue(
&network_isolation_key_value)) {
return false;
}
- dict->SetKey(kNetworkIsolationKey, std::move(network_isolation_key_value));
+ dict.Set(kNetworkIsolationKey, std::move(network_isolation_key_value));
AddAlternativeServiceFieldsToDictionaryValue(
broken_alt_service.alternative_service, dict);
return true;
@@ -153,20 +150,18 @@ std::string QuicServerIdToString(const quic::QuicServerId& server_id) {
(server_id.privacy_mode_enabled() ? "/private" : "");
}
-// Takes in a base::Value representing a dictionary, and whether
-// NetworkIsolationKeys are enabled for HttpServerProperties, and extracts the
-// NetworkIsolationKey stored with the |kNetworkIsolationKey| in the dictionary,
-// and writes it to |out_network_isolation_key|. Returns false if unable to load
-// a NetworkIsolationKey, or the NetworkIsolationKey is non-empty, but
+// Takes in a base::Value::Dict, and whether NetworkIsolationKeys are enabled
+// for HttpServerProperties, and extracts the NetworkIsolationKey stored with
+// the |kNetworkIsolationKey| in the dictionary, and writes it to
+// |out_network_isolation_key|. Returns false if unable to load a
+// NetworkIsolationKey, or the NetworkIsolationKey is non-empty, but
// |use_network_isolation_key| is false.
bool GetNetworkIsolationKeyFromDict(
- const base::Value& dict,
+ const base::Value::Dict& dict,
bool use_network_isolation_key,
NetworkIsolationKey* out_network_isolation_key) {
- DCHECK(dict.is_dict());
-
const base::Value* network_isolation_key_value =
- dict.FindKey(kNetworkIsolationKey);
+ dict.Find(kNetworkIsolationKey);
NetworkIsolationKey network_isolation_key;
if (!network_isolation_key_value ||
!NetworkIsolationKey::FromValue(*network_isolation_key_value,
@@ -230,16 +225,19 @@ void HttpServerPropertiesManager::ReadPrefs(
net_log_.EndEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION);
- const base::Value* http_server_properties_dict =
+ const base::Value* http_server_properties_value =
pref_delegate_->GetServerProperties();
// If there are no preferences set, do nothing.
- if (!http_server_properties_dict || !http_server_properties_dict->is_dict())
+ if (!http_server_properties_value || !http_server_properties_value->is_dict())
return;
+ const base::Value::Dict& http_server_properties_dict =
+ http_server_properties_value->GetDict();
+
net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_CACHE,
- [&] { return http_server_properties_dict->Clone(); });
+ [&] { return http_server_properties_value->Clone(); });
absl::optional<int> maybe_version_number =
- http_server_properties_dict->FindIntKey(kVersionKey);
+ http_server_properties_dict.FindInt(kVersionKey);
if (!maybe_version_number.has_value() ||
*maybe_version_number != kVersionNumber) {
DVLOG(1) << "Missing or unsupported. Clearing all properties. "
@@ -260,14 +258,14 @@ void HttpServerPropertiesManager::ReadPrefs(
// ...
// ], ...
// },
- const base::Value* servers_list =
- http_server_properties_dict->FindListKey(kServersKey);
+ const base::Value::List* servers_list =
+ http_server_properties_dict.FindList(kServersKey);
if (!servers_list) {
DVLOG(1) << "Malformed http_server_properties for servers list.";
return;
}
- ReadLastLocalAddressWhenQuicWorked(*http_server_properties_dict,
+ ReadLastLocalAddressWhenQuicWorked(http_server_properties_dict,
last_local_address_when_quic_worked);
*server_info_map = std::make_unique<HttpServerProperties::ServerInfoMap>();
@@ -281,24 +279,23 @@ void HttpServerPropertiesManager::ReadPrefs(
// Iterate servers list in reverse MRU order so that entries are inserted
// into |spdy_servers_map|, |alternative_service_map|, and
// |server_network_stats_map| from oldest to newest.
- for (auto it = servers_list->GetListDeprecated().end();
- it != servers_list->GetListDeprecated().begin();) {
+ for (auto it = servers_list->end(); it != servers_list->begin();) {
--it;
if (!it->is_dict()) {
DVLOG(1) << "Malformed http_server_properties for servers dictionary.";
continue;
}
- AddServerData(*it, server_info_map->get(), use_network_isolation_key);
+ AddServerData(it->GetDict(), server_info_map->get(),
+ use_network_isolation_key);
}
- AddToQuicServerInfoMap(*http_server_properties_dict,
- use_network_isolation_key,
+ AddToQuicServerInfoMap(http_server_properties_dict, use_network_isolation_key,
quic_server_info_map->get());
// Read list containing broken and recently-broken alternative services, if
// it exists.
- const base::Value* broken_alt_svc_list =
- http_server_properties_dict->FindListKey(kBrokenAlternativeServicesKey);
+ const base::Value::List* broken_alt_svc_list =
+ http_server_properties_dict.FindList(kBrokenAlternativeServicesKey);
if (broken_alt_svc_list) {
*broken_alternative_service_list =
std::make_unique<BrokenAlternativeServiceList>();
@@ -307,15 +304,15 @@ void HttpServerPropertiesManager::ReadPrefs(
kMaxRecentlyBrokenAlternativeServiceEntries);
// Iterate list in reverse-MRU order
- for (auto it = broken_alt_svc_list->GetListDeprecated().end();
- it != broken_alt_svc_list->GetListDeprecated().begin();) {
+ for (auto it = broken_alt_svc_list->end();
+ it != broken_alt_svc_list->begin();) {
--it;
if (!it->is_dict()) {
DVLOG(1) << "Malformed broken alterantive service entry.";
continue;
}
AddToBrokenAlternativeServices(
- *it, use_network_isolation_key,
+ it->GetDict(), use_network_isolation_key,
broken_alternative_service_list->get(),
recently_broken_alternative_services->get());
}
@@ -341,7 +338,7 @@ void HttpServerPropertiesManager::ReadPrefs(
}
void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
- const base::Value& broken_alt_svc_entry_dict,
+ const base::Value::Dict& broken_alt_svc_entry_dict,
bool use_network_isolation_key,
BrokenAlternativeServiceList* broken_alternative_service_list,
RecentlyBrokenAlternativeServices* recently_broken_alternative_services) {
@@ -364,9 +361,9 @@ void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
// Read broken-count and add an entry for |alt_service| into
// |recently_broken_alternative_services|.
- if (broken_alt_svc_entry_dict.FindKey(kBrokenCountKey)) {
+ if (broken_alt_svc_entry_dict.Find(kBrokenCountKey)) {
absl::optional<int> broken_count =
- broken_alt_svc_entry_dict.FindIntKey(kBrokenCountKey);
+ broken_alt_svc_entry_dict.FindInt(kBrokenCountKey);
if (!broken_count.has_value()) {
DVLOG(1) << "Recently broken alternative service has malformed "
<< "broken-count.";
@@ -385,9 +382,9 @@ void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
// Read broken-until and add an entry for |alt_service| in
// |broken_alternative_service_list|.
- if (broken_alt_svc_entry_dict.FindKey(kBrokenUntilKey)) {
+ if (broken_alt_svc_entry_dict.Find(kBrokenUntilKey)) {
const std::string* expiration_string =
- broken_alt_svc_entry_dict.FindStringKey(kBrokenUntilKey);
+ broken_alt_svc_entry_dict.FindString(kBrokenUntilKey);
int64_t expiration_int64;
if (!expiration_string ||
!base::StringToInt64(*expiration_string, &expiration_int64)) {
@@ -415,11 +412,11 @@ void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
}
void HttpServerPropertiesManager::AddServerData(
- const base::Value& server_dict,
+ const base::Value::Dict& server_dict,
HttpServerProperties::ServerInfoMap* server_info_map,
bool use_network_isolation_key) {
// Get server's scheme/host/pair.
- const std::string* server_str = server_dict.FindStringKey(kServerKey);
+ const std::string* server_str = server_dict.FindString(kServerKey);
NetworkIsolationKey network_isolation_key;
// Can't load entry if server name missing, or if the network isolation key is
// missing or invalid.
@@ -437,7 +434,7 @@ void HttpServerPropertiesManager::AddServerData(
HttpServerProperties::ServerInfo server_info;
- server_info.supports_spdy = server_dict.FindBoolKey(kSupportsSpdyKey);
+ server_info.supports_spdy = server_dict.FindBool(kSupportsSpdyKey);
if (ParseAlternativeServiceInfo(spdy_server, server_dict, &server_info))
ParseNetworkStats(spdy_server, server_dict, &server_info);
@@ -451,12 +448,12 @@ void HttpServerPropertiesManager::AddServerData(
}
bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
- const base::Value& dict,
+ const base::Value::Dict& dict,
bool host_optional,
const std::string& parsing_under,
AlternativeService* alternative_service) {
// Protocol is mandatory.
- const std::string* protocol_str = dict.FindStringKey(kProtocolKey);
+ const std::string* protocol_str = dict.FindString(kProtocolKey);
if (!protocol_str) {
DVLOG(1) << "Malformed alternative service protocol string under: "
<< parsing_under;
@@ -473,8 +470,8 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
// If host is optional, it defaults to "".
std::string host = "";
const std::string* hostp = nullptr;
- if (dict.FindKey(kHostKey)) {
- hostp = dict.FindStringKey(kHostKey);
+ if (dict.Find(kHostKey)) {
+ hostp = dict.FindString(kHostKey);
if (!hostp) {
DVLOG(1) << "Malformed alternative service host string under: "
<< parsing_under;
@@ -489,7 +486,7 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
alternative_service->host = host;
// Port is mandatory.
- absl::optional<int> maybe_port = dict.FindIntKey(kPortKey);
+ absl::optional<int> maybe_port = dict.FindInt(kPortKey);
if (!maybe_port.has_value() || !IsPortValid(maybe_port.value())) {
DVLOG(1) << "Malformed alternative service port under: " << parsing_under;
return false;
@@ -500,7 +497,7 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
}
bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
- const base::Value& dict,
+ const base::Value::Dict& dict,
const std::string& server_str,
AlternativeServiceInfo* alternative_service_info) {
AlternativeService alternative_service;
@@ -511,10 +508,10 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
alternative_service_info->set_alternative_service(alternative_service);
// Expiration is optional, defaults to one day.
- if (!dict.FindKey(kExpirationKey)) {
+ if (!dict.Find(kExpirationKey)) {
alternative_service_info->set_expiration(base::Time::Now() + base::Days(1));
} else {
- const std::string* expiration_string = dict.FindStringKey(kExpirationKey);
+ const std::string* expiration_string = dict.FindString(kExpirationKey);
if (expiration_string) {
int64_t expiration_int64 = 0;
if (!base::StringToInt64(*expiration_string, &expiration_int64)) {
@@ -532,15 +529,15 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
}
// Advertised versions list is optional.
- if (dict.FindKey(kAdvertisedAlpnsKey)) {
- const base::Value* versions_list = dict.FindListKey(kAdvertisedAlpnsKey);
+ if (dict.Find(kAdvertisedAlpnsKey)) {
+ const base::Value::List* versions_list = dict.FindList(kAdvertisedAlpnsKey);
if (!versions_list) {
DVLOG(1) << "Malformed alternative service advertised versions list for "
<< "server: " << server_str;
return false;
}
quic::ParsedQuicVersionVector advertised_versions;
- for (const auto& value : versions_list->GetListDeprecated()) {
+ for (const auto& value : *versions_list) {
const std::string* version_string = value.GetIfString();
if (!version_string) {
DVLOG(1) << "Malformed alternative service version for server: "
@@ -561,11 +558,11 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
const url::SchemeHostPort& server,
- const base::Value& server_pref_dict,
+ const base::Value::Dict& server_pref_dict,
HttpServerProperties::ServerInfo* server_info) {
DCHECK(!server_info->alternative_services.has_value());
- const base::Value* alternative_service_list =
- server_pref_dict.FindListKey(kAlternativeServiceKey);
+ const base::Value::List* alternative_service_list =
+ server_pref_dict.FindList(kAlternativeServiceKey);
if (!alternative_service_list) {
return true;
}
@@ -574,14 +571,13 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
}
AlternativeServiceInfoVector alternative_service_info_vector;
- for (const auto& alternative_service_list_item :
- alternative_service_list->GetListDeprecated()) {
+ for (const auto& alternative_service_list_item : *alternative_service_list) {
if (!alternative_service_list_item.is_dict())
return false;
AlternativeServiceInfo alternative_service_info;
- if (!ParseAlternativeServiceInfoDictOfServer(alternative_service_list_item,
- server.Serialize(),
- &alternative_service_info)) {
+ if (!ParseAlternativeServiceInfoDictOfServer(
+ alternative_service_list_item.GetDict(), server.Serialize(),
+ &alternative_service_info)) {
return false;
}
if (base::Time::Now() < alternative_service_info.expiration()) {
@@ -598,14 +594,14 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
}
void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
- const base::Value& http_server_properties_dict,
+ const base::Value::Dict& http_server_properties_dict,
IPAddress* last_local_address_when_quic_worked) {
- const base::Value* supports_quic_dict =
- http_server_properties_dict.FindDictKey(kSupportsQuicKey);
+ const base::Value::Dict* supports_quic_dict =
+ http_server_properties_dict.FindDict(kSupportsQuicKey);
if (!supports_quic_dict) {
return;
}
- const base::Value* used_quic = supports_quic_dict->FindKey(kUsedQuicKey);
+ const base::Value* used_quic = supports_quic_dict->Find(kUsedQuicKey);
if (!used_quic || !used_quic->is_bool()) {
DVLOG(1) << "Malformed SupportsQuic";
return;
@@ -613,7 +609,7 @@ void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
if (!used_quic->GetBool())
return;
- const std::string* address = supports_quic_dict->FindStringKey(kAddressKey);
+ const std::string* address = supports_quic_dict->FindString(kAddressKey);
if (!address ||
!last_local_address_when_quic_worked->AssignFromIPLiteral(*address)) {
DVLOG(1) << "Malformed SupportsQuic";
@@ -622,16 +618,15 @@ void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
void HttpServerPropertiesManager::ParseNetworkStats(
const url::SchemeHostPort& server,
- const base::Value& server_pref_dict,
+ const base::Value::Dict& server_pref_dict,
HttpServerProperties::ServerInfo* server_info) {
DCHECK(!server_info->server_network_stats.has_value());
- const base::Value* server_network_stats_dict =
- server_pref_dict.FindDictKey(kNetworkStatsKey);
+ const base::Value::Dict* server_network_stats_dict =
+ server_pref_dict.FindDict(kNetworkStatsKey);
if (!server_network_stats_dict) {
return;
}
- absl::optional<int> maybe_srtt =
- server_network_stats_dict->FindIntKey(kSrttKey);
+ absl::optional<int> maybe_srtt = server_network_stats_dict->FindInt(kSrttKey);
if (!maybe_srtt.has_value()) {
DVLOG(1) << "Malformed ServerNetworkStats for server: "
<< server.Serialize();
@@ -645,23 +640,24 @@ void HttpServerPropertiesManager::ParseNetworkStats(
}
void HttpServerPropertiesManager::AddToQuicServerInfoMap(
- const base::Value& http_server_properties_dict,
+ const base::Value::Dict& http_server_properties_dict,
bool use_network_isolation_key,
HttpServerProperties::QuicServerInfoMap* quic_server_info_map) {
- const base::Value* quic_server_info_list =
- http_server_properties_dict.FindListKey(kQuicServers);
+ const base::Value::List* quic_server_info_list =
+ http_server_properties_dict.FindList(kQuicServers);
if (!quic_server_info_list) {
DVLOG(1) << "Malformed http_server_properties for quic_servers.";
return;
}
- for (const auto& quic_server_info_value :
- quic_server_info_list->GetListDeprecated()) {
- if (!quic_server_info_value.is_dict())
+ for (const auto& quic_server_info_value : *quic_server_info_list) {
+ const base::Value::Dict* quic_server_info_dict =
+ quic_server_info_value.GetIfDict();
+ if (!quic_server_info_dict)
continue;
const std::string* quic_server_id_str =
- quic_server_info_value.FindStringKey(kQuicServerIdKey);
+ quic_server_info_dict->FindString(kQuicServerIdKey);
if (!quic_server_id_str || quic_server_id_str->empty())
continue;
@@ -674,7 +670,7 @@ void HttpServerPropertiesManager::AddToQuicServerInfoMap(
}
NetworkIsolationKey network_isolation_key;
- if (!GetNetworkIsolationKeyFromDict(quic_server_info_value,
+ if (!GetNetworkIsolationKeyFromDict(*quic_server_info_dict,
use_network_isolation_key,
&network_isolation_key)) {
DVLOG(1) << "Malformed http_server_properties quic server dict: "
@@ -683,7 +679,7 @@ void HttpServerPropertiesManager::AddToQuicServerInfoMap(
}
const std::string* quic_server_info =
- quic_server_info_value.FindStringKey(kServerInfoKey);
+ quic_server_info_dict->FindString(kServerInfoKey);
if (!quic_server_info) {
DVLOG(1) << "Malformed http_server_properties quic server info: "
<< *quic_server_id_str;
@@ -714,11 +710,13 @@ void HttpServerPropertiesManager::WriteToPrefs(
std::set<std::pair<std::string, NetworkIsolationKey>>
persisted_canonical_suffix_set;
const base::Time now = base::Time::Now();
- base::Value http_server_properties_dict(base::Value::Type::DICTIONARY);
+ base::Value http_server_properties_value(base::Value::Type::DICTIONARY);
+ base::Value::Dict& http_server_properties_dict =
+ http_server_properties_value.GetDict();
- // Convert |server_info_map| to a dictionary Value and add it to
+ // Convert |server_info_map| to a list Value and add it to
// |http_server_properties_dict|.
- base::Value servers_list(base::Value::Type::LIST);
+ base::Value::List servers_list;
for (const auto& [key, server_info] : base::Reversed(server_info_map)) {
// If can't convert the NetworkIsolationKey to a value, don't save to disk.
// Generally happens because the key is for a unique origin.
@@ -726,139 +724,137 @@ void HttpServerPropertiesManager::WriteToPrefs(
if (!key.network_isolation_key.ToValue(&network_isolation_key_value))
continue;
- base::Value server_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict server_dict;
bool supports_spdy = server_info.supports_spdy.value_or(false);
if (supports_spdy)
- server_dict.SetBoolKey(kSupportsSpdyKey, supports_spdy);
+ server_dict.Set(kSupportsSpdyKey, supports_spdy);
AlternativeServiceInfoVector alternative_services =
GetAlternativeServiceToPersist(server_info.alternative_services, key,
now, get_canonical_suffix,
&persisted_canonical_suffix_set);
if (!alternative_services.empty())
- SaveAlternativeServiceToServerPrefs(alternative_services, &server_dict);
+ SaveAlternativeServiceToServerPrefs(alternative_services, server_dict);
if (server_info.server_network_stats) {
SaveNetworkStatsToServerPrefs(*server_info.server_network_stats,
- &server_dict);
+ server_dict);
}
// Don't add empty entries. This can happen if, for example, all alternative
// services are empty, or |supports_spdy| is set to false, and all other
// fields are not set.
- if (server_dict.DictEmpty())
+ if (server_dict.empty())
continue;
- server_dict.SetStringKey(kServerKey, key.server.Serialize());
- server_dict.SetKey(kNetworkIsolationKey,
- std::move(network_isolation_key_value));
+ server_dict.Set(kServerKey, key.server.Serialize());
+ server_dict.Set(kNetworkIsolationKey,
+ std::move(network_isolation_key_value));
servers_list.Append(std::move(server_dict));
}
- http_server_properties_dict.SetKey(kServersKey, std::move(servers_list));
+ http_server_properties_dict.Set(kServersKey, std::move(servers_list));
- http_server_properties_dict.SetIntKey(kVersionKey, kVersionNumber);
+ http_server_properties_dict.Set(kVersionKey, kVersionNumber);
SaveLastLocalAddressWhenQuicWorkedToPrefs(last_local_address_when_quic_worked,
- &http_server_properties_dict);
+ http_server_properties_dict);
SaveQuicServerInfoMapToServerPrefs(quic_server_info_map,
- &http_server_properties_dict);
+ http_server_properties_dict);
SaveBrokenAlternativeServicesToPrefs(
broken_alternative_service_list, kMaxBrokenAlternativeServicesToPersist,
- recently_broken_alternative_services, &http_server_properties_dict);
+ recently_broken_alternative_services, http_server_properties_dict);
- pref_delegate_->SetServerProperties(http_server_properties_dict,
+ pref_delegate_->SetServerProperties(http_server_properties_value,
std::move(callback));
net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS,
- [&] { return http_server_properties_dict.Clone(); });
+ [&] { return http_server_properties_value.Clone(); });
}
void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
const AlternativeServiceInfoVector& alternative_service_info_vector,
- base::Value* server_pref_dict) {
+ base::Value::Dict& server_pref_dict) {
if (alternative_service_info_vector.empty()) {
return;
}
- base::Value alternative_service_list(base::Value::Type::LIST);
+ base::Value::List alternative_service_list;
for (const AlternativeServiceInfo& alternative_service_info :
alternative_service_info_vector) {
const AlternativeService& alternative_service =
alternative_service_info.alternative_service();
DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
- base::Value alternative_service_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict alternative_service_dict;
AddAlternativeServiceFieldsToDictionaryValue(alternative_service,
- &alternative_service_dict);
+ alternative_service_dict);
// JSON cannot store int64_t, so expiration is converted to a string.
- alternative_service_dict.SetStringKey(
+ alternative_service_dict.Set(
kExpirationKey,
base::NumberToString(
alternative_service_info.expiration().ToInternalValue()));
- base::Value advertised_versions_list(base::Value::Type::LIST);
+ base::Value::List advertised_versions_list;
for (const auto& version : alternative_service_info.advertised_versions()) {
advertised_versions_list.Append(quic::AlpnForVersion(version));
}
- alternative_service_dict.SetKey(kAdvertisedAlpnsKey,
- std::move(advertised_versions_list));
+ alternative_service_dict.Set(kAdvertisedAlpnsKey,
+ std::move(advertised_versions_list));
alternative_service_list.Append(std::move(alternative_service_dict));
}
- if (alternative_service_list.GetListDeprecated().size() == 0)
+ if (alternative_service_list.size() == 0)
return;
- server_pref_dict->SetKey(kAlternativeServiceKey,
- std::move(alternative_service_list));
+ server_pref_dict.Set(kAlternativeServiceKey,
+ std::move(alternative_service_list));
}
void HttpServerPropertiesManager::SaveLastLocalAddressWhenQuicWorkedToPrefs(
const IPAddress& last_local_address_when_quic_worked,
- base::Value* http_server_properties_dict) {
+ base::Value::Dict& http_server_properties_dict) {
if (!last_local_address_when_quic_worked.IsValid())
return;
- base::Value supports_quic_dict(base::Value::Type::DICTIONARY);
- supports_quic_dict.SetBoolKey(kUsedQuicKey, true);
- supports_quic_dict.SetStringKey(
- kAddressKey, last_local_address_when_quic_worked.ToString());
- http_server_properties_dict->SetKey(kSupportsQuicKey,
- std::move(supports_quic_dict));
+ base::Value::Dict supports_quic_dict;
+ supports_quic_dict.Set(kUsedQuicKey, true);
+ supports_quic_dict.Set(kAddressKey,
+ last_local_address_when_quic_worked.ToString());
+ http_server_properties_dict.Set(kSupportsQuicKey,
+ std::move(supports_quic_dict));
}
void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
const ServerNetworkStats& server_network_stats,
- base::Value* server_pref_dict) {
- base::Value server_network_stats_dict(base::Value::Type::DICTIONARY);
- // Becasue JSON doesn't support int64_t, persist int64_t as a string.
- server_network_stats_dict.SetIntKey(
+ base::Value::Dict& server_pref_dict) {
+ base::Value::Dict server_network_stats_dict;
+ // Because JSON doesn't support int64_t, persist int64_t as a string.
+ server_network_stats_dict.Set(
kSrttKey, static_cast<int>(server_network_stats.srtt.InMicroseconds()));
// TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
// bandwidth_estimate.
- server_pref_dict->SetKey(kNetworkStatsKey,
- std::move(server_network_stats_dict));
+ server_pref_dict.Set(kNetworkStatsKey, std::move(server_network_stats_dict));
}
void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
- base::Value* http_server_properties_dict) {
+ base::Value::Dict& http_server_properties_dict) {
if (quic_server_info_map.empty())
return;
- base::Value quic_servers_list(base::Value::Type::LIST);
+ base::Value::List quic_servers_list;
for (const auto& [key, server_info] : base::Reversed(quic_server_info_map)) {
base::Value network_isolation_key_value;
// Don't save entries with ephemeral NIKs.
if (!key.network_isolation_key.ToValue(&network_isolation_key_value))
continue;
- base::Value quic_server_pref_dict(base::Value::Type::DICTIONARY);
- quic_server_pref_dict.SetStringKey(kQuicServerIdKey,
- QuicServerIdToString(key.server_id));
- quic_server_pref_dict.SetKey(kNetworkIsolationKey,
- std::move(network_isolation_key_value));
- quic_server_pref_dict.SetStringKey(kServerInfoKey, server_info);
+ base::Value::Dict quic_server_pref_dict;
+ quic_server_pref_dict.Set(kQuicServerIdKey,
+ QuicServerIdToString(key.server_id));
+ quic_server_pref_dict.Set(kNetworkIsolationKey,
+ std::move(network_isolation_key_value));
+ quic_server_pref_dict.Set(kServerInfoKey, server_info);
quic_servers_list.Append(std::move(quic_server_pref_dict));
}
- http_server_properties_dict->SetKey(kQuicServers,
- std::move(quic_servers_list));
+ http_server_properties_dict.Set(kQuicServers, std::move(quic_servers_list));
}
void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
@@ -866,7 +862,7 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
size_t max_broken_alternative_services,
const RecentlyBrokenAlternativeServices&
recently_broken_alternative_services,
- base::Value* http_server_properties_dict) {
+ base::Value::Dict& http_server_properties_dict) {
if (broken_alternative_service_list.empty() &&
recently_broken_alternative_services.empty()) {
return;
@@ -874,7 +870,7 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
// JSON list will be in MRU order according to
// |recently_broken_alternative_services|.
- base::Value json_list(base::Value::Type::LIST);
+ base::Value::List json_list;
// Maps recently-broken alternative services to the index where it's stored
// in |json_list|.
@@ -883,14 +879,13 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
if (!recently_broken_alternative_services.empty()) {
for (const auto& [broken_alt_service, broken_count] :
base::Reversed(recently_broken_alternative_services)) {
- base::Value entry_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict entry_dict;
if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
- broken_alt_service, &entry_dict)) {
+ broken_alt_service, entry_dict)) {
continue;
}
- entry_dict.SetKey(kBrokenCountKey, base::Value(broken_count));
- json_list_index_map[broken_alt_service] =
- json_list.GetListDeprecated().size();
+ entry_dict.Set(kBrokenCountKey, broken_count);
+ json_list_index_map[broken_alt_service] = json_list.size();
json_list.Append(std::move(entry_dict));
}
}
@@ -914,20 +909,18 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
auto index_map_it = json_list_index_map.find(broken_alt_service);
if (index_map_it != json_list_index_map.end()) {
size_t json_list_index = index_map_it->second;
- base::Value& entry_dict =
- json_list.GetListDeprecated()[json_list_index];
+ base::Value& entry_dict = json_list[json_list_index];
DCHECK(entry_dict.is_dict());
- DCHECK(!entry_dict.FindKey(kBrokenUntilKey));
- entry_dict.SetKey(kBrokenUntilKey,
- base::Value(base::NumberToString(expiration_int64)));
+ DCHECK(!entry_dict.GetDict().Find(kBrokenUntilKey));
+ entry_dict.GetDict().Set(kBrokenUntilKey,
+ base::NumberToString(expiration_int64));
} else {
- base::Value entry_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict entry_dict;
if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
- broken_alt_service, &entry_dict)) {
+ broken_alt_service, entry_dict)) {
continue;
}
- entry_dict.SetKey(kBrokenUntilKey,
- base::Value(base::NumberToString(expiration_int64)));
+ entry_dict.Set(kBrokenUntilKey, base::NumberToString(expiration_int64));
json_list.Append(std::move(entry_dict));
}
}
@@ -935,11 +928,11 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
// This can happen if all the entries are for NetworkIsolationKeys for opaque
// origins, which isn't exactly common, but can theoretically happen.
- if (json_list.GetListDeprecated().empty())
+ if (json_list.empty())
return;
- http_server_properties_dict->SetKey(kBrokenAlternativeServicesKey,
- std::move(json_list));
+ http_server_properties_dict.Set(kBrokenAlternativeServicesKey,
+ std::move(json_list));
}
void HttpServerPropertiesManager::OnHttpServerPropertiesLoaded() {
diff --git a/chromium/net/http/http_server_properties_manager.h b/chromium/net/http/http_server_properties_manager.h
index add11943a41..9be5265ae9d 100644
--- a/chromium/net/http/http_server_properties_manager.h
+++ b/chromium/net/http/http_server_properties_manager.h
@@ -132,7 +132,7 @@ class NET_EXPORT_PRIVATE HttpServerPropertiesManager {
FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest,
AdvertisedVersionsRoundTrip);
- void AddServerData(const base::Value& server_dict,
+ void AddServerData(const base::Value::Dict& server_dict,
HttpServerProperties::ServerInfoMap* server_info_map,
bool use_network_isolation_key);
@@ -146,13 +146,13 @@ class NET_EXPORT_PRIVATE HttpServerPropertiesManager {
// |alternative_service| is the output of parsing |dict|.
// Return value is true if parsing is successful.
static bool ParseAlternativeServiceDict(
- const base::Value& dict,
+ const base::Value::Dict& dict,
bool host_optional,
const std::string& parsing_under,
AlternativeService* alternative_service);
static bool ParseAlternativeServiceInfoDictOfServer(
- const base::Value& dict,
+ const base::Value::Dict& dict,
const std::string& server_str,
AlternativeServiceInfo* alternative_service_info);
@@ -161,43 +161,43 @@ class NET_EXPORT_PRIVATE HttpServerPropertiesManager {
// not considered corruption).
static bool ParseAlternativeServiceInfo(
const url::SchemeHostPort& server,
- const base::Value& server_dict,
+ const base::Value::Dict& server_dict,
HttpServerProperties::ServerInfo* server_info);
void ReadLastLocalAddressWhenQuicWorked(
- const base::Value& server_dict,
+ const base::Value::Dict& server_dict,
IPAddress* last_local_address_when_quic_worked);
void ParseNetworkStats(const url::SchemeHostPort& server,
- const base::Value& server_dict,
+ const base::Value::Dict& server_dict,
HttpServerProperties::ServerInfo* server_info);
void AddToQuicServerInfoMap(
- const base::Value& server_dict,
+ const base::Value::Dict& server_dict,
bool use_network_isolation_key,
HttpServerProperties::QuicServerInfoMap* quic_server_info_map);
void AddToBrokenAlternativeServices(
- const base::Value& broken_alt_svc_entry_dict,
+ const base::Value::Dict& broken_alt_svc_entry_dict,
bool use_network_isolation_key,
BrokenAlternativeServiceList* broken_alternative_service_list,
RecentlyBrokenAlternativeServices* recently_broken_alternative_services);
void SaveAlternativeServiceToServerPrefs(
const AlternativeServiceInfoVector& alternative_service_info_vector,
- base::Value* server_pref_dict);
+ base::Value::Dict& server_pref_dict);
void SaveLastLocalAddressWhenQuicWorkedToPrefs(
const IPAddress& last_local_address_when_quic_worked,
- base::Value* http_server_properties_dict);
+ base::Value::Dict& http_server_properties_dict);
void SaveNetworkStatsToServerPrefs(
const ServerNetworkStats& server_network_stats,
- base::Value* server_pref_dict);
+ base::Value::Dict& server_pref_dict);
void SaveQuicServerInfoMapToServerPrefs(
const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
- base::Value* http_server_properties_dict);
+ base::Value::Dict& http_server_properties_dict);
void SaveBrokenAlternativeServicesToPrefs(
const BrokenAlternativeServiceList& broken_alternative_service_list,
size_t max_broken_alternative_services,
const RecentlyBrokenAlternativeServices&
recently_broken_alternative_services,
- base::Value* http_server_properties_dict);
+ base::Value::Dict& http_server_properties_dict);
void OnHttpServerPropertiesLoaded();
diff --git a/chromium/net/http/http_server_properties_manager_unittest.cc b/chromium/net/http/http_server_properties_manager_unittest.cc
index 598d9c934f7..df6ed2e114e 100644
--- a/chromium/net/http/http_server_properties_manager_unittest.cc
+++ b/chromium/net/http/http_server_properties_manager_unittest.cc
@@ -279,9 +279,9 @@ class HttpServerPropertiesManagerTest : public testing::Test,
// Returns a dictionary with only the version field populated.
static base::Value DictWithVersion() {
- base::Value http_server_properties_dict(base::Value::Type::DICTIONARY);
- http_server_properties_dict.SetIntKey("version", 5);
- return http_server_properties_dict;
+ base::Value::Dict http_server_properties_dict;
+ http_server_properties_dict.Set("version", 5);
+ return base::Value(std::move(http_server_properties_dict));
}
raw_ptr<MockPrefDelegate>
@@ -292,43 +292,42 @@ class HttpServerPropertiesManagerTest : public testing::Test,
};
TEST_F(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
- base::Value server_pref_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict server_pref_dict;
// Set supports_spdy for www.google.com:65536.
- server_pref_dict.SetBoolKey("supports_spdy", true);
+ server_pref_dict.Set("supports_spdy", true);
// Set up alternative_service for www.google.com:65536.
- base::Value alternative_service_dict(base::Value::Type::DICTIONARY);
- alternative_service_dict.SetStringKey("protocol_str", "h2");
- alternative_service_dict.SetIntKey("port", 80);
- base::Value alternative_service_list(base::Value::Type::LIST);
+ base::Value::Dict alternative_service_dict;
+ alternative_service_dict.Set("protocol_str", "h2");
+ alternative_service_dict.Set("port", 80);
+ base::Value::List alternative_service_list;
alternative_service_list.Append(std::move(alternative_service_dict));
- server_pref_dict.SetKey("alternative_service",
- std::move(alternative_service_list));
+ server_pref_dict.Set("alternative_service",
+ std::move(alternative_service_list));
// Set up ServerNetworkStats for www.google.com:65536.
- base::Value stats(base::Value::Type::DICTIONARY);
- stats.SetIntKey("srtt", 10);
- server_pref_dict.SetKey("network_stats", std::move(stats));
+ base::Value::Dict stats;
+ stats.Set("srtt", 10);
+ server_pref_dict.Set("network_stats", std::move(stats));
// Set the server preference for www.google.com:65536.
- base::Value servers_dict(base::Value::Type::DICTIONARY);
- servers_dict.SetKey("www.google.com:65536", std::move(server_pref_dict));
- base::Value servers_list(base::Value::Type::LIST);
+ base::Value::Dict servers_dict;
+ servers_dict.Set("www.google.com:65536", std::move(server_pref_dict));
+ base::Value::List servers_list;
servers_list.Append(std::move(servers_dict));
base::Value http_server_properties_dict = DictWithVersion();
- http_server_properties_dict.SetKey("servers", std::move(servers_list));
+ http_server_properties_dict.GetDict().Set("servers", std::move(servers_list));
// Set quic_server_info for www.google.com:65536.
- base::Value quic_servers_dict(base::Value::Type::DICTIONARY);
- base::Value quic_server_pref_dict1(base::Value::Type::DICTIONARY);
- quic_server_pref_dict1.SetKey("server_info",
- base::Value("quic_server_info1"));
- quic_servers_dict.SetKey("http://mail.google.com:65536",
- std::move(quic_server_pref_dict1));
+ base::Value::Dict quic_servers_dict;
+ base::Value::Dict quic_server_pref_dict1;
+ quic_server_pref_dict1.Set("server_info", "quic_server_info1");
+ quic_servers_dict.Set("http://mail.google.com:65536",
+ std::move(quic_server_pref_dict1));
- http_server_properties_dict.SetKey("quic_servers",
- std::move(quic_servers_dict));
+ http_server_properties_dict.GetDict().Set("quic_servers",
+ std::move(quic_servers_dict));
// Set up the pref.
InitializePrefs(http_server_properties_dict);
@@ -349,27 +348,27 @@ TEST_F(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
}
TEST_F(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) {
- base::Value server_pref_dict(base::Value::Type::DICTIONARY);
+ base::Value::Dict server_pref_dict;
// Set supports_spdy for www.google.com:80.
- server_pref_dict.SetBoolKey("supports_spdy", true);
+ server_pref_dict.Set("supports_spdy", true);
// Set up alternative_service for www.google.com:80.
- base::Value alternative_service_dict(base::Value::Type::DICTIONARY);
- alternative_service_dict.SetStringKey("protocol_str", "h2");
- alternative_service_dict.SetIntKey("port", 65536);
- base::Value alternative_service_list(base::Value::Type::LIST);
+ base::Value::Dict alternative_service_dict;
+ alternative_service_dict.Set("protocol_str", "h2");
+ alternative_service_dict.Set("port", 65536);
+ base::Value::List alternative_service_list;
alternative_service_list.Append(std::move(alternative_service_dict));
- server_pref_dict.SetKey("alternative_service",
- std::move(alternative_service_list));
+ server_pref_dict.Set("alternative_service",
+ std::move(alternative_service_list));
// Set the server preference for www.google.com:80.
- base::Value servers_dict(base::Value::Type::DICTIONARY);
- servers_dict.SetKey("www.google.com:80", std::move(server_pref_dict));
- base::Value servers_list(base::Value::Type::LIST);
+ base::Value::Dict servers_dict;
+ servers_dict.Set("www.google.com:80", std::move(server_pref_dict));
+ base::Value::List servers_list;
servers_list.Append(std::move(servers_dict));
base::Value http_server_properties_dict = DictWithVersion();
- http_server_properties_dict.SetKey("servers", std::move(servers_list));
+ http_server_properties_dict.GetDict().Set("servers", std::move(servers_list));
// Set up the pref.
InitializePrefs(http_server_properties_dict);
@@ -1028,38 +1027,37 @@ TEST_F(HttpServerPropertiesManagerTest, Clear) {
// https://crbug.com/444956: Add 200 alternative_service servers followed by
// supports_quic and verify we have read supports_quic from prefs.
TEST_F(HttpServerPropertiesManagerTest, BadLastLocalAddressWhenQuicWorked) {
- base::Value servers_list(base::Value::Type::LIST);
+ base::Value::List servers_list;
for (int i = 1; i <= 200; ++i) {
// Set up alternative_service for www.google.com:i.
- base::Value server_dict(base::Value::Type::DICTIONARY);
- base::Value alternative_service_dict(base::Value::Type::DICTIONARY);
- alternative_service_dict.SetStringKey("protocol_str", "quic");
- alternative_service_dict.SetIntKey("port", i);
- base::Value alternative_service_list(base::Value::Type::LIST);
+ base::Value::Dict server_dict;
+ base::Value::Dict alternative_service_dict;
+ alternative_service_dict.Set("protocol_str", "quic");
+ alternative_service_dict.Set("port", i);
+ base::Value::List alternative_service_list;
alternative_service_list.Append(std::move(alternative_service_dict));
- server_dict.SetKey("alternative_service",
- std::move(alternative_service_list));
- server_dict.SetStringKey("server",
- StringPrintf("https://www.google.com:%d", i));
- server_dict.SetKey("isolation", base::Value(base::Value::Type::LIST));
+ server_dict.Set("alternative_service", std::move(alternative_service_list));
+ server_dict.Set("server", StringPrintf("https://www.google.com:%d", i));
+ server_dict.Set("isolation", base::Value(base::Value::Type::LIST));
servers_list.Append(std::move(server_dict));
}
// Set the server preference for http://mail.google.com server.
- base::Value server_dict2(base::Value::Type::DICTIONARY);
- server_dict2.SetStringKey("server", "https://mail.google.com");
- server_dict2.SetKey("isolation", base::Value(base::Value::Type::LIST));
+ base::Value::Dict server_dict2;
+ server_dict2.Set("server", "https://mail.google.com");
+ server_dict2.Set("isolation", base::Value(base::Value::Type::LIST));
servers_list.Append(std::move(server_dict2));
base::Value http_server_properties_dict = DictWithVersion();
- http_server_properties_dict.SetKey("servers", std::move(servers_list));
+ http_server_properties_dict.GetDict().Set("servers", std::move(servers_list));
// Set up SupportsQuic for 127.0.0.1
- base::Value supports_quic(base::Value::Type::DICTIONARY);
- supports_quic.SetBoolKey("used_quic", true);
- supports_quic.SetStringKey("address", "127.0.0.1");
- http_server_properties_dict.SetKey("supports_quic", std::move(supports_quic));
+ base::Value::Dict supports_quic;
+ supports_quic.Set("used_quic", true);
+ supports_quic.Set("address", "127.0.0.1");
+ http_server_properties_dict.GetDict().Set("supports_quic",
+ std::move(supports_quic));
// Set up the pref.
InitializePrefs(http_server_properties_dict);
@@ -1174,17 +1172,16 @@ TEST_F(HttpServerPropertiesManagerTest, UpdatePrefsWithCache) {
ASSERT_TRUE(server_dict.is_dict());
// Extract and remove the "broken_until" string for "www.google.com:1234".
- base::Value* broken_alt_svc_list =
- server_dict.FindListKey("broken_alternative_services");
+ base::Value::List* broken_alt_svc_list =
+ server_dict.GetDict().FindList("broken_alternative_services");
ASSERT_TRUE(broken_alt_svc_list);
- ASSERT_EQ(2u, broken_alt_svc_list->GetListDeprecated().size());
- base::Value& broken_alt_svcs_list_entry =
- broken_alt_svc_list->GetListDeprecated()[0];
+ ASSERT_EQ(2u, broken_alt_svc_list->size());
+ base::Value& broken_alt_svcs_list_entry = (*broken_alt_svc_list)[0];
const std::string* broken_until_str =
- broken_alt_svcs_list_entry.FindStringKey("broken_until");
+ broken_alt_svcs_list_entry.GetDict().FindString("broken_until");
ASSERT_TRUE(broken_until_str);
const std::string expiration_string = *broken_until_str;
- broken_alt_svcs_list_entry.RemoveKey("broken_until");
+ broken_alt_svcs_list_entry.GetDict().Remove("broken_until");
// Expiration time of "www.google.com:1234" should be 5 minutes minus the
// update-prefs-delay from when the prefs were written.
@@ -1248,7 +1245,7 @@ TEST_F(HttpServerPropertiesManagerTest, ParseAlternativeServiceInfo) {
const url::SchemeHostPort server("https", "example.com", 443);
HttpServerProperties::ServerInfo server_info;
EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo(
- server, *server_dict, &server_info));
+ server, server_dict->GetDict(), &server_info));
ASSERT_TRUE(server_info.alternative_services.has_value());
AlternativeServiceInfoVector alternative_service_info_vector =
@@ -1302,7 +1299,7 @@ TEST_F(HttpServerPropertiesManagerTest, DoNotLoadAltSvcForInsecureOrigins) {
const url::SchemeHostPort server("http", "example.com", 80);
HttpServerProperties::ServerInfo server_info;
EXPECT_FALSE(HttpServerPropertiesManager::ParseAlternativeServiceInfo(
- server, *server_dict, &server_info));
+ server, server_dict->GetDict(), &server_info));
EXPECT_TRUE(server_info.empty());
}
@@ -1352,38 +1349,40 @@ TEST_F(HttpServerPropertiesManagerTest, DoNotPersistExpiredAlternativeService) {
const base::Value* pref_dict = pref_delegate_->GetServerProperties();
- const base::Value* servers_list = pref_dict->FindListKey("servers");
+ const base::Value::List* servers_list =
+ pref_dict->GetDict().FindList("servers");
ASSERT_TRUE(servers_list);
- auto it = servers_list->GetListDeprecated().begin();
+ auto it = servers_list->begin();
const base::Value& server_pref_dict = *it;
ASSERT_TRUE(server_pref_dict.is_dict());
- const std::string* server_str = server_pref_dict.FindStringKey("server");
+ const std::string* server_str =
+ server_pref_dict.GetDict().FindString("server");
ASSERT_TRUE(server_str);
EXPECT_EQ("https://www.example.com", *server_str);
const base::Value* network_isolation_key_value =
- server_pref_dict.FindKey("isolation");
+ server_pref_dict.GetDict().Find("isolation");
ASSERT_TRUE(network_isolation_key_value);
ASSERT_EQ(base::Value::Type::LIST, network_isolation_key_value->type());
- EXPECT_TRUE(network_isolation_key_value->GetListDeprecated().empty());
+ EXPECT_TRUE(network_isolation_key_value->GetList().empty());
- const base::Value* altsvc_list =
- server_pref_dict.FindListKey("alternative_service");
+ const base::Value::List* altsvc_list =
+ server_pref_dict.GetDict().FindList("alternative_service");
ASSERT_TRUE(altsvc_list);
- ASSERT_EQ(2u, altsvc_list->GetListDeprecated().size());
+ ASSERT_EQ(2u, altsvc_list->size());
- const base::Value& altsvc_entry = altsvc_list->GetListDeprecated()[0];
+ const base::Value& altsvc_entry = (*altsvc_list)[0];
ASSERT_TRUE(altsvc_entry.is_dict());
- const std::string* hostname = altsvc_entry.FindStringKey("host");
+ const std::string* hostname = altsvc_entry.GetDict().FindString("host");
ASSERT_TRUE(hostname);
EXPECT_EQ("broken.example.com", *hostname);
- const base::Value& altsvc_entry2 = altsvc_list->GetListDeprecated()[1];
+ const base::Value& altsvc_entry2 = (*altsvc_list)[1];
ASSERT_TRUE(altsvc_entry.is_dict());
- hostname = altsvc_entry2.FindStringKey("host");
+ hostname = altsvc_entry2.GetDict().FindString("host");
ASSERT_TRUE(hostname);
EXPECT_EQ("valid.example.com", *hostname);
}
@@ -1392,27 +1391,27 @@ TEST_F(HttpServerPropertiesManagerTest, DoNotPersistExpiredAlternativeService) {
TEST_F(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) {
InitializePrefs();
- base::Value alternative_service_list(base::Value::Type::LIST);
- base::Value expired_dict(base::Value::Type::DICTIONARY);
- expired_dict.SetStringKey("protocol_str", "h2");
- expired_dict.SetStringKey("host", "expired.example.com");
- expired_dict.SetIntKey("port", 443);
+ base::Value::List alternative_service_list;
+ base::Value::Dict expired_dict;
+ expired_dict.Set("protocol_str", "h2");
+ expired_dict.Set("host", "expired.example.com");
+ expired_dict.Set("port", 443);
base::Time time_one_day_ago = base::Time::Now() - base::Days(1);
- expired_dict.SetStringKey(
- "expiration", base::NumberToString(time_one_day_ago.ToInternalValue()));
+ expired_dict.Set("expiration",
+ base::NumberToString(time_one_day_ago.ToInternalValue()));
alternative_service_list.Append(std::move(expired_dict));
- base::Value valid_dict(base::Value::Type::DICTIONARY);
- valid_dict.SetStringKey("protocol_str", "h2");
- valid_dict.SetStringKey("host", "valid.example.com");
- valid_dict.SetIntKey("port", 443);
- valid_dict.SetStringKey(
- "expiration", base::NumberToString(one_day_from_now_.ToInternalValue()));
+ base::Value::Dict valid_dict;
+ valid_dict.Set("protocol_str", "h2");
+ valid_dict.Set("host", "valid.example.com");
+ valid_dict.Set("port", 443);
+ valid_dict.Set("expiration",
+ base::NumberToString(one_day_from_now_.ToInternalValue()));
alternative_service_list.Append(std::move(valid_dict));
- base::Value server_pref_dict(base::Value::Type::DICTIONARY);
- server_pref_dict.SetKey("alternative_service",
- std::move(alternative_service_list));
+ base::Value::Dict server_pref_dict;
+ server_pref_dict.Set("alternative_service",
+ std::move(alternative_service_list));
const url::SchemeHostPort server("https", "example.com", 443);
HttpServerProperties::ServerInfo server_info;
@@ -1520,7 +1519,7 @@ TEST_F(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) {
"\"isolation\":[],"
"\"server\":\"https://www.google.com:80\"},"
"{\"alternative_service\":[{"
- "\"advertised_alpns\":[\"h3\",\"h3-Q050\"],"
+ "\"advertised_alpns\":[\"h3\"],"
"\"expiration\":\"9223372036854775807\","
"\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
@@ -1554,7 +1553,7 @@ TEST_F(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) {
const url::SchemeHostPort server("https", "example.com", 443);
HttpServerProperties::ServerInfo server_info;
EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo(
- server, *server_dict, &server_info));
+ server, server_dict->GetDict(), &server_info));
ASSERT_TRUE(server_info.alternative_services.has_value());
AlternativeServiceInfoVector alternative_service_info_vector =
@@ -1633,7 +1632,7 @@ TEST_F(HttpServerPropertiesManagerTest,
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{"
- "\"advertised_alpns\":[\"h3\",\"h3-Q050\"],"
+ "\"advertised_alpns\":[\"h3\"],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
@@ -3030,14 +3029,14 @@ TEST_F(HttpServerPropertiesManagerTest, AdvertisedVersionsRoundTrip) {
base::JSONReader::ReadDeprecated(preferences_json);
ASSERT_TRUE(preferences_dict);
ASSERT_TRUE(preferences_dict->is_dict());
- const base::Value* servers_list = preferences_dict->FindListKey("servers");
+ const base::Value::List* servers_list =
+ preferences_dict->GetDict().FindList("servers");
ASSERT_TRUE(servers_list);
- ASSERT_TRUE(servers_list->is_list());
- ASSERT_EQ(servers_list->GetListDeprecated().size(), 1u);
- const base::Value& server_dict = servers_list->GetListDeprecated()[0];
+ ASSERT_EQ(servers_list->size(), 1u);
+ const base::Value& server_dict = (*servers_list)[0];
HttpServerProperties::ServerInfo server_info;
EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo(
- server, server_dict, &server_info));
+ server, server_dict.GetDict(), &server_info));
ASSERT_TRUE(server_info.alternative_services.has_value());
AlternativeServiceInfoVector alternative_service_info_vector_out =
server_info.alternative_services.value();
diff --git a/chromium/net/http/http_stream.h b/chromium/net/http/http_stream.h
index 04d1507f8ce..80712a613ff 100644
--- a/chromium/net/http/http_stream.h
+++ b/chromium/net/http/http_stream.h
@@ -171,9 +171,9 @@ class NET_EXPORT_PRIVATE HttpStream {
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) = 0;
// Gets the remote endpoint of the socket that the HTTP stream is using, if
- // any. Returns true and fills in |endpoint| if it is available; returns false
- // and does not modify |endpoint| if it is unavailable.
- virtual bool GetRemoteEndpoint(IPEndPoint* endpoint) = 0;
+ // any. Returns OK and fills in |endpoint| if it is available; returns an
+ // error and does not modify |endpoint| otherwise.
+ virtual int GetRemoteEndpoint(IPEndPoint* endpoint) = 0;
// In the case of an HTTP error or redirect, flush the response body (usually
// a simple error or "this page has moved") so that we can re-use the
diff --git a/chromium/net/http/http_stream_factory.cc b/chromium/net/http/http_stream_factory.cc
index 7812973922f..4b3a3463c5a 100644
--- a/chromium/net/http/http_stream_factory.cc
+++ b/chromium/net/http/http_stream_factory.cc
@@ -152,7 +152,11 @@ std::unique_ptr<HttpStreamRequest> HttpStreamFactory::RequestStreamInternal(
auto job_controller = std::make_unique<JobController>(
this, delegate, session_, job_factory_.get(), request_info,
/* is_preconnect = */ false, is_websocket, enable_ip_based_pooling,
- enable_alternative_services, server_ssl_config, proxy_ssl_config);
+ enable_alternative_services,
+ session_->context()
+ .quic_context->params()
+ ->delay_main_job_with_available_spdy_session,
+ server_ssl_config, proxy_ssl_config);
JobController* job_controller_raw_ptr = job_controller.get();
job_controller_set_.insert(std::move(job_controller));
return job_controller_raw_ptr->Start(delegate,
@@ -169,7 +173,11 @@ void HttpStreamFactory::PreconnectStreams(int num_streams,
/*is_preconnect=*/true,
/*is_websocket=*/false,
/*enable_ip_based_pooling=*/true,
- /*enable_alternative_services=*/true, /*server_ssl_config=*/SSLConfig(),
+ /*enable_alternative_services=*/true,
+ session_->context()
+ .quic_context->params()
+ ->delay_main_job_with_available_spdy_session,
+ /*server_ssl_config=*/SSLConfig(),
/*proxy_ssl_config=*/SSLConfig());
JobController* job_controller_raw_ptr = job_controller.get();
job_controller_set_.insert(std::move(job_controller));
diff --git a/chromium/net/http/http_stream_factory_job.cc b/chromium/net/http/http_stream_factory_job.cc
index b8583f068a9..f0a2edc34f1 100644
--- a/chromium/net/http/http_stream_factory_job.cc
+++ b/chromium/net/http/http_stream_factory_job.cc
@@ -124,7 +124,6 @@ HttpStreamFactory::Job::Job(Delegate* delegate,
base::BindRepeating(&Job::OnIOComplete, base::Unretained(this))),
connection_(new ClientSocketHandle),
session_(session),
- next_state_(STATE_NONE),
destination_(std::move(destination)),
origin_url_(origin_url),
is_websocket_(is_websocket),
@@ -147,15 +146,7 @@ HttpStreamFactory::Job::Job(Delegate* delegate,
(ShouldForceQuic(session, destination_, proxy_info, using_ssl_))),
quic_version_(quic_version),
expect_spdy_(alternative_protocol == kProtoHTTP2 && !using_quic_),
- using_spdy_(false),
- should_reconsider_proxy_(false),
quic_request_(session_->quic_stream_factory()),
- expect_on_quic_host_resolution_(false),
- using_existing_quic_session_(false),
- establishing_tunnel_(false),
- was_alpn_negotiated_(false),
- negotiated_protocol_(kProtoUnknown),
- num_streams_(0),
pushed_stream_id_(kNoPushedStreamFound),
spdy_session_key_(
using_quic_ ? SpdySessionKey()
@@ -164,12 +155,12 @@ HttpStreamFactory::Job::Job(Delegate* delegate,
request_info_.privacy_mode,
request_info_.socket_tag,
request_info_.network_isolation_key,
- request_info_.secure_dns_policy)),
- stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM),
- init_connection_already_resumed_(false) {
+ request_info_.secure_dns_policy)) {
// Websocket `destination` schemes should be converted to HTTP(S).
- DCHECK(base::LowerCaseEqualsASCII(destination_.scheme(), url::kHttpScheme) ||
- base::LowerCaseEqualsASCII(destination_.scheme(), url::kHttpsScheme));
+ DCHECK(base::EqualsCaseInsensitiveASCII(destination_.scheme(),
+ url::kHttpScheme) ||
+ base::EqualsCaseInsensitiveASCII(destination_.scheme(),
+ url::kHttpsScheme));
// This class is specific to a single `ProxyServer`, so `proxy_info_` must be
// non-empty. Entries beyond the first are ignored. It should simply take a
@@ -308,6 +299,12 @@ void HttpStreamFactory::Job::SetPriority(RequestPriority priority) {
// TODO(akalin): Maybe Propagate this to the preconnect state.
}
+bool HttpStreamFactory::Job::HasAvailableSpdySession() const {
+ return !using_quic_ && CanUseExistingSpdySession() &&
+ session_->spdy_session_pool()->HasAvailableSession(spdy_session_key_,
+ is_websocket_);
+}
+
bool HttpStreamFactory::Job::was_alpn_negotiated() const {
return was_alpn_negotiated_;
}
@@ -356,7 +353,8 @@ bool HttpStreamFactory::Job::ShouldForceQuic(
base::Contains(quic_params->origins_to_force_quic_on,
HostPortPair::FromSchemeHostPort(destination))) &&
proxy_info.is_direct() &&
- base::LowerCaseEqualsASCII(destination.scheme(), url::kHttpsScheme);
+ base::EqualsCaseInsensitiveASCII(destination.scheme(),
+ url::kHttpsScheme);
}
// static
@@ -409,7 +407,7 @@ void HttpStreamFactory::Job::OnStreamReadyCallback() {
DCHECK_NE(job_type_, PRECONNECT);
DCHECK(!is_websocket_ || try_websocket_over_http2_);
- MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ MaybeCopyConnectionAttemptsFromHandle();
delegate_->OnStreamReady(this, server_ssl_config_);
// |this| may be deleted after this call.
@@ -420,7 +418,7 @@ void HttpStreamFactory::Job::OnWebSocketHandshakeStreamReadyCallback() {
DCHECK_NE(job_type_, PRECONNECT);
DCHECK(is_websocket_);
- MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ MaybeCopyConnectionAttemptsFromHandle();
delegate_->OnWebSocketHandshakeStreamReady(
this, server_ssl_config_, proxy_info_, std::move(websocket_stream_));
@@ -430,7 +428,7 @@ void HttpStreamFactory::Job::OnWebSocketHandshakeStreamReadyCallback() {
void HttpStreamFactory::Job::OnBidirectionalStreamImplReadyCallback() {
DCHECK(bidirectional_stream_impl_);
- MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ MaybeCopyConnectionAttemptsFromHandle();
delegate_->OnBidirectionalStreamImplReady(this, server_ssl_config_,
proxy_info_);
@@ -440,7 +438,7 @@ void HttpStreamFactory::Job::OnBidirectionalStreamImplReadyCallback() {
void HttpStreamFactory::Job::OnStreamFailedCallback(int result) {
DCHECK_NE(job_type_, PRECONNECT);
- MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ MaybeCopyConnectionAttemptsFromHandle();
delegate_->OnStreamFailed(this, result, server_ssl_config_);
// |this| may be deleted after this call.
@@ -452,7 +450,7 @@ void HttpStreamFactory::Job::OnCertificateErrorCallback(
DCHECK_NE(job_type_, PRECONNECT);
DCHECK(!spdy_session_request_);
- MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ MaybeCopyConnectionAttemptsFromHandle();
delegate_->OnCertificateError(this, result, server_ssl_config_, ssl_info);
// |this| may be deleted after this call.
@@ -819,11 +817,18 @@ int HttpStreamFactory::Job::DoInitConnectionImpl() {
DCHECK(!is_websocket_);
DCHECK(request_info_.socket_tag == SocketTag());
+ // The lifeime of the preconnect tasks is not controlled by |connection_|.
+ // It may outlives |this|. So we can't use |io_callback_| which holds
+ // base::Unretained(this).
+ auto callback =
+ base::BindOnce(&Job::OnIOComplete, ptr_factory_.GetWeakPtr());
+
return PreconnectSocketsForHttpRequest(
destination_, request_info_.load_flags, priority_, session_,
proxy_info_, server_ssl_config_, proxy_ssl_config_,
request_info_.privacy_mode, request_info_.network_isolation_key,
- request_info_.secure_dns_policy, net_log_, num_streams_);
+ request_info_.secure_dns_policy, net_log_, num_streams_,
+ std::move(callback));
}
ClientSocketPool::ProxyAuthCallback proxy_auth_callback =
@@ -880,7 +885,8 @@ int HttpStreamFactory::Job::DoInitConnectionImplQuic() {
std::move(destination), quic_version_, request_info_.privacy_mode,
priority_, request_info_.socket_tag, request_info_.network_isolation_key,
request_info_.secure_dns_policy, proxy_info_.is_direct(),
- ssl_config->GetCertVerifyFlags(), url, net_log_, &net_error_details_,
+ /*require_dns_https_alpn=*/false, ssl_config->GetCertVerifyFlags(), url,
+ net_log_, &net_error_details_,
base::BindOnce(&Job::OnFailedOnDefaultNetwork, ptr_factory_.GetWeakPtr()),
io_callback_);
if (rv == OK) {
@@ -1239,21 +1245,12 @@ int HttpStreamFactory::Job::ReconsiderProxyAfterError(int error) {
return error;
}
-// If the connection succeeds, failed connection attempts leading up to the
-// success will be returned via the successfully connected socket. If the
-// connection fails, failed connection attempts will be returned via the
-// ClientSocketHandle. Check whether a socket was returned and copy the
-// connection attempts from the proper place.
-void HttpStreamFactory::Job::MaybeCopyConnectionAttemptsFromSocketOrHandle() {
+void HttpStreamFactory::Job::MaybeCopyConnectionAttemptsFromHandle() {
if (!connection_)
return;
- ConnectionAttempts socket_attempts = connection_->connection_attempts();
- if (connection_->socket()) {
- connection_->socket()->GetConnectionAttempts(&socket_attempts);
- }
-
- delegate_->AddConnectionAttemptsToRequest(this, socket_attempts);
+ delegate_->AddConnectionAttemptsToRequest(this,
+ connection_->connection_attempts());
}
HttpStreamFactory::JobFactory::JobFactory() = default;
diff --git a/chromium/net/http/http_stream_factory_job.h b/chromium/net/http/http_stream_factory_job.h
index 6ce0c30b74c..1a176b71a8f 100644
--- a/chromium/net/http/http_stream_factory_job.h
+++ b/chromium/net/http/http_stream_factory_job.h
@@ -191,6 +191,10 @@ class HttpStreamFactory::Job
void SetPriority(RequestPriority priority);
+ // Returns true if the current request can be immediately sent on a existing
+ // spdy session.
+ bool HasAvailableSpdySession() const;
+
const GURL& origin_url() const { return origin_url_; }
RequestPriority priority() const { return priority_; }
bool was_alpn_negotiated() const;
@@ -334,7 +338,7 @@ class HttpStreamFactory::Job
// code is simply returned.
int ReconsiderProxyAfterError(int error);
- void MaybeCopyConnectionAttemptsFromSocketOrHandle();
+ void MaybeCopyConnectionAttemptsFromHandle();
// Returns true if the request should be throttled to allow for only one
// connection attempt to be made to an H2 server at a time.
@@ -351,7 +355,7 @@ class HttpStreamFactory::Job
std::unique_ptr<ClientSocketHandle> connection_;
const raw_ptr<HttpNetworkSession> session_;
- State next_state_;
+ State next_state_ = STATE_NONE;
// The server we are trying to reach, could be that of the origin or of the
// alternative service (after applying host mapping rules).
@@ -384,7 +388,7 @@ class HttpStreamFactory::Job
// describe some proxy cases.
const bool using_ssl_;
- // True if Job actually uses HTTP/2. Note this describes both using QUIC
+ // True if Job actually uses QUIC. Note this describes both using QUIC
// with an HTTPS origin, and proxying a cleartext HTTP request over an QUIC
// proxy. This differs from `using_ssl_`, which only describes the origin.
const bool using_quic_;
@@ -401,37 +405,37 @@ class HttpStreamFactory::Job
// True if Job actually uses HTTP/2. Note this describes both using HTTP/2
// with an HTTPS origin, and proxying a cleartext HTTP request over an HTTP/2
// proxy. This differs from `using_ssl_`, which only describes the origin.
- bool using_spdy_;
+ bool using_spdy_ = false;
// True if this job might succeed with a different proxy config.
- bool should_reconsider_proxy_;
+ bool should_reconsider_proxy_ = false;
QuicStreamRequest quic_request_;
// Only valid for a QUIC job. Set when a QUIC connection is started. If true,
// then OnQuicHostResolution() is expected to be called in the future.
- bool expect_on_quic_host_resolution_;
+ bool expect_on_quic_host_resolution_ = false;
// True if this job used an existing QUIC session.
- bool using_existing_quic_session_;
+ bool using_existing_quic_session_ = false;
// True when the tunnel is in the process of being established - we can't
// read from the socket until the tunnel is done.
- bool establishing_tunnel_;
+ bool establishing_tunnel_ = false;
std::unique_ptr<HttpStream> stream_;
std::unique_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_;
// True if we negotiated ALPN.
- bool was_alpn_negotiated_;
+ bool was_alpn_negotiated_ = false;
// Protocol negotiated with the server.
- NextProto negotiated_protocol_;
+ NextProto negotiated_protocol_ = kProtoUnknown;
// 0 if we're not preconnecting. Otherwise, the number of streams to
// preconnect.
- int num_streams_;
+ int num_streams_ = 0;
// Initialized when we have an existing SpdySession.
base::WeakPtr<SpdySession> existing_spdy_session_;
@@ -447,10 +451,11 @@ class HttpStreamFactory::Job
const SpdySessionKey spdy_session_key_;
// Type of stream that is requested.
- HttpStreamRequest::StreamType stream_type_;
+ HttpStreamRequest::StreamType stream_type_ =
+ HttpStreamRequest::BIDIRECTIONAL_STREAM;
// Whether Job has continued to DoInitConnection().
- bool init_connection_already_resumed_;
+ bool init_connection_already_resumed_ = false;
base::OnceClosure restart_with_auth_callback_;
diff --git a/chromium/net/http/http_stream_factory_job_controller.cc b/chromium/net/http/http_stream_factory_job_controller.cc
index 98d2dfdc8f5..19dd80b8150 100644
--- a/chromium/net/http/http_stream_factory_job_controller.cc
+++ b/chromium/net/http/http_stream_factory_job_controller.cc
@@ -130,31 +130,22 @@ HttpStreamFactory::JobController::JobController(
bool is_websocket,
bool enable_ip_based_pooling,
bool enable_alternative_services,
+ bool delay_main_job_with_available_spdy_session,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config)
: factory_(factory),
session_(session),
job_factory_(job_factory),
- request_(nullptr),
delegate_(delegate),
is_preconnect_(is_preconnect),
is_websocket_(is_websocket),
enable_ip_based_pooling_(enable_ip_based_pooling),
enable_alternative_services_(enable_alternative_services),
- main_job_net_error_(OK),
- alternative_job_net_error_(OK),
- alternative_job_failed_on_default_network_(false),
- job_bound_(false),
- main_job_is_blocked_(false),
- main_job_is_resumed_(false),
- bound_job_(nullptr),
- next_state_(STATE_RESOLVE_PROXY),
- proxy_resolve_request_(nullptr),
+ delay_main_job_with_available_spdy_session_(
+ delay_main_job_with_available_spdy_session),
request_info_(request_info),
server_ssl_config_(server_ssl_config),
proxy_ssl_config_(proxy_ssl_config),
- num_streams_(0),
- priority_(IDLE),
net_log_(NetLogWithSource::Make(
session->net_log(),
NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)) {
@@ -599,8 +590,23 @@ const NetLogWithSource* HttpStreamFactory::JobController::GetNetLog() const {
void HttpStreamFactory::JobController::MaybeSetWaitTimeForMainJob(
const base::TimeDelta& delay) {
if (main_job_is_blocked_) {
- main_job_wait_time_ =
- std::min(delay, base::Seconds(kMaxDelayTimeForMainJobSecs));
+ const bool has_available_spdy_session =
+ main_job_->HasAvailableSpdySession();
+ if (!delay_main_job_with_available_spdy_session_ &&
+ has_available_spdy_session) {
+ main_job_wait_time_ = base::TimeDelta();
+ } else {
+ main_job_wait_time_ =
+ std::min(delay, base::Seconds(kMaxDelayTimeForMainJobSecs));
+ }
+ if (has_available_spdy_session) {
+ UMA_HISTOGRAM_TIMES("Net.HttpJob.MainJobWaitTimeWithAvailableSpdySession",
+ main_job_wait_time_);
+ } else {
+ UMA_HISTOGRAM_TIMES(
+ "Net.HttpJob.MainJobWaitTimeWithoutAvailableSpdySession",
+ main_job_wait_time_);
+ }
}
}
@@ -1107,7 +1113,7 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal(
QuicSessionKey session_key(
HostPortPair::FromURL(mapped_origin), request_info.privacy_mode,
request_info.socket_tag, request_info.network_isolation_key,
- request_info.secure_dns_policy);
+ request_info.secure_dns_policy, /*require_dns_https_alpn=*/false);
GURL destination = CreateAltSvcUrl(
original_url, alternative_service_info.host_port_pair());
diff --git a/chromium/net/http/http_stream_factory_job_controller.h b/chromium/net/http/http_stream_factory_job_controller.h
index 5b5cb2ad651..e6149e3f076 100644
--- a/chromium/net/http/http_stream_factory_job_controller.h
+++ b/chromium/net/http/http_stream_factory_job_controller.h
@@ -12,6 +12,7 @@
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_errors.h"
#include "net/base/privacy_mode.h"
#include "net/http/http_stream_factory_job.h"
#include "net/http/http_stream_request.h"
@@ -42,6 +43,7 @@ class HttpStreamFactory::JobController
bool is_websocket,
bool enable_ip_based_pooling,
bool enable_alternative_services,
+ bool delay_main_job_with_available_spdy_session,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config);
@@ -278,7 +280,7 @@ class HttpStreamFactory::JobController
// reference and is safe as |request_| will notify |this| JobController
// when it's destructed by calling OnRequestComplete(), which nulls
// |request_|.
- raw_ptr<HttpStreamRequest> request_;
+ raw_ptr<HttpStreamRequest> request_ = nullptr;
const raw_ptr<HttpStreamRequest::Delegate> delegate_;
@@ -306,40 +308,44 @@ class HttpStreamFactory::JobController
// Error status used for alternative service brokenness reporting.
// Net error code of the main job. Set to OK by default.
- int main_job_net_error_;
+ int main_job_net_error_ = OK;
// Net error code of the alternative job. Set to OK by default.
- int alternative_job_net_error_;
+ int alternative_job_net_error_ = OK;
// Set to true if the alternative job failed on the default network.
- bool alternative_job_failed_on_default_network_;
+ bool alternative_job_failed_on_default_network_ = false;
// True if a Job has ever been bound to the |request_|.
- bool job_bound_;
+ bool job_bound_ = false;
// True if the main job has to wait for the alternative job: i.e., the main
// job must not create a connection until it is resumed.
- bool main_job_is_blocked_;
+ bool main_job_is_blocked_ = false;
// Handle for cancelling any posted delayed ResumeMainJob() task.
base::CancelableOnceClosure resume_main_job_callback_;
// True if the main job was blocked and has been resumed in ResumeMainJob().
- bool main_job_is_resumed_;
+ bool main_job_is_resumed_ = false;
+
+ // If true, delay main job even the request can be sent immediately on an
+ // available SPDY session.
+ bool delay_main_job_with_available_spdy_session_;
// Waiting time for the main job before it is resumed.
base::TimeDelta main_job_wait_time_;
// At the point where a Job is irrevocably tied to |request_|, we set this.
// It will be nulled when the |request_| is finished.
- raw_ptr<Job> bound_job_;
+ raw_ptr<Job> bound_job_ = nullptr;
- State next_state_;
+ State next_state_ = STATE_RESOLVE_PROXY;
std::unique_ptr<ProxyResolutionRequest> proxy_resolve_request_;
const HttpRequestInfo request_info_;
ProxyInfo proxy_info_;
const SSLConfig server_ssl_config_;
const SSLConfig proxy_ssl_config_;
- int num_streams_;
+ int num_streams_ = 0;
HttpStreamRequest::StreamType stream_type_;
- RequestPriority priority_;
+ RequestPriority priority_ = IDLE;
const NetLogWithSource net_log_;
base::WeakPtrFactory<JobController> ptr_factory_{this};
diff --git a/chromium/net/http/http_stream_factory_job_controller_unittest.cc b/chromium/net/http/http_stream_factory_job_controller_unittest.cc
index cd013d32fa1..c401c7b4167 100644
--- a/chromium/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/chromium/net/http/http_stream_factory_job_controller_unittest.cc
@@ -55,6 +55,8 @@
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session_key.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
#include "net/test/test_with_task_environment.h"
#include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -114,14 +116,6 @@ class MockPrefDelegate : public HttpServerProperties::PrefDelegate {
class HttpStreamFactoryJobPeer {
public:
- static void Start(HttpStreamFactory::Job* job,
- HttpStreamRequest::StreamType stream_type) {
- // Start() is mocked for MockHttpStreamFactoryJob.
- // This is the alternative method to invoke real Start() method on Job.
- job->stream_type_ = stream_type;
- job->StartInternal();
- }
-
// Returns |num_streams_| of |job|. It should be 0 for non-preconnect Jobs.
static int GetNumStreams(const HttpStreamFactory::Job* job) {
return job->num_streams_;
@@ -215,6 +209,11 @@ class HttpStreamFactoryJobControllerTest : public TestWithTaskEnvironment {
enable_ip_based_pooling_ = false;
}
+ void SetNotDelayMainJobWithAvailableSpdySession() {
+ ASSERT_FALSE(test_proxy_delegate_);
+ delay_main_job_with_available_spdy_session_ = false;
+ }
+
void DisableAlternativeServices() {
ASSERT_FALSE(test_proxy_delegate_);
enable_alternative_services_ = false;
@@ -252,7 +251,8 @@ class HttpStreamFactoryJobControllerTest : public TestWithTaskEnvironment {
job_controller_ = new HttpStreamFactory::JobController(
factory_, &request_delegate_, session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller_);
}
@@ -354,6 +354,7 @@ class HttpStreamFactoryJobControllerTest : public TestWithTaskEnvironment {
bool is_preconnect_ = false;
bool enable_ip_based_pooling_ = true;
bool enable_alternative_services_ = true;
+ bool delay_main_job_with_available_spdy_session_ = true;
private:
std::unique_ptr<TestProxyDelegate> test_proxy_delegate_;
@@ -483,7 +484,8 @@ class JobControllerReconsiderProxyAfterErrorTest
new HttpStreamFactory::JobController(
factory_, &request_delegate_, session_.get(), &default_job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
return job_controller->Start(
@@ -1862,11 +1864,12 @@ void HttpStreamFactoryJobControllerTest::
// Run message loop to make the main job succeed.
base::RunLoop().RunUntilIdle();
+ request_.reset();
+
// If alt job was retried on the alternate network, the alternative service
// should be marked broken until the default network changes.
VerifyBrokenAlternateProtocolMapping(request_info,
alt_job_retried_on_non_default_network);
- request_.reset();
EXPECT_TRUE(HttpStreamFactoryPeer::IsJobControllerDeleted(factory_));
if (alt_job_retried_on_non_default_network) {
// Verify the brokenness is cleared when the default network changes.
@@ -1889,7 +1892,7 @@ TEST_F(HttpStreamFactoryJobControllerTest,
// changes.
TEST_F(HttpStreamFactoryJobControllerTest,
MainJobSucceedsAfterAltJobSucceededOnAlternateNetwork) {
- TestAltJobSucceedsAfterMainJobSucceeded(true);
+ TestMainJobSucceedsAfterAltJobSucceeded(true);
}
void HttpStreamFactoryJobControllerTest::TestMainJobFailsAfterAltJobSucceeded(
@@ -2685,7 +2688,8 @@ TEST_F(HttpStreamFactoryJobControllerTest,
new HttpStreamFactory::JobController(
factory_, &request_delegate, session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
job_controller->Preconnect(/*num_streams=*/5);
@@ -2702,6 +2706,58 @@ TEST_F(HttpStreamFactoryJobControllerTest,
}
}
+TEST_F(HttpStreamFactoryJobControllerTest,
+ DonotDelayMainJobIfHasAvailableSpdySession) {
+ SetNotDelayMainJobWithAvailableSpdySession();
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ Initialize(request_info);
+ // Put a SpdySession in the pool.
+ HostPortPair host_port_pair("www.google.com", 443);
+ SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
+ PRIVACY_MODE_DISABLED,
+ SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+ NetworkIsolationKey(), SecureDnsPolicy::kAllow);
+ std::ignore = CreateFakeSpdySession(session_->spdy_session_pool(), key);
+
+ // Handshake will fail asynchronously after mock data is unpaused.
+ MockQuicData quic_data(version_);
+ quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause
+ quic_data.AddRead(ASYNC, ERR_FAILED);
+ quic_data.AddWrite(ASYNC, ERR_FAILED);
+ quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get());
+
+ // Enable delayed TCP and set time delay for waiting job.
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory();
+ quic_stream_factory->set_is_quic_known_to_work_on_current_network(true);
+ ServerNetworkStats stats1;
+ stats1.srtt = base::Milliseconds(100);
+ session_->http_server_properties()->SetServerNetworkStats(
+ url::SchemeHostPort(GURL("https://www.google.com")),
+ NetworkIsolationKey(), stats1);
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(kProtoQUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+
+ // This prevents handshake from immediately succeeding.
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::COLD_START);
+
+ request_ =
+ job_controller_->Start(&request_delegate_, nullptr, net_log_with_source_,
+ HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY);
+
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+ // The main job shouldn't have any delay since the request can be sent on
+ // available SPDY session.
+ EXPECT_FALSE(job_controller_->ShouldWait(
+ const_cast<net::HttpStreamFactory::Job*>(job_controller_->main_job())));
+}
+
// Check the case that while a preconnect is waiting in the H2 request queue,
// and a SPDY session appears, the job completes successfully.
TEST_F(HttpStreamFactoryJobControllerTest, SpdySessionInterruptsPreconnect) {
@@ -2737,7 +2793,8 @@ TEST_F(HttpStreamFactoryJobControllerTest, SpdySessionInterruptsPreconnect) {
new HttpStreamFactory::JobController(
factory_, &preconnect_request_delegate, session_.get(), &job_factory_,
request_info, true /* is_preconnect */, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
job_controller->Preconnect(1);
@@ -2768,6 +2825,152 @@ TEST_F(HttpStreamFactoryJobControllerTest, SpdySessionInterruptsPreconnect) {
EXPECT_TRUE(spdy_session);
}
+// This test verifies that a preconnect job doesn't block subsequent requests
+// which can use an existing IP based pooled SpdySession.
+// This test uses "wildcard.pem" to support IpBasedPooling for *.example.org,
+// and starts 3 requests:
+// [1] Normal non-preconnect request to www.example.org.
+// [2] Preconnect request to other.example.org. The connection is paused until
+// OnConnectComplete() is called in the end of the test.
+// [3] Normal non-preconnect request to other.example.org. This request must
+// succeed even while the preconnect request [2] is paused.
+TEST_F(HttpStreamFactoryJobControllerTest,
+ PreconnectJobDoesntBlockIpBasedPooling) {
+ // Make sure that both "www.example.org" and "other.example.org" are pointing
+ // to the same IP address.
+ std::vector<HostResolverEndpointResult> endpoints;
+ HostResolverEndpointResult endpoint_result;
+ endpoint_result.ip_endpoints = {IPEndPoint(IPAddress::IPv4Localhost(), 0)};
+ endpoints.push_back(endpoint_result);
+ session_deps_.host_resolver->rules()->AddRule("www.example.org", endpoints);
+ session_deps_.host_resolver->rules()->AddRule("other.example.org", endpoints);
+ // Make |host_resolver| asynchronous to simulate the issue of
+ // crbug.com/1320608.
+ session_deps_.host_resolver->set_synchronous_mode(false);
+
+ // This is used for the non-preconnect requests [1] and [3].
+ MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
+ SequencedSocketData first_socket(reads, writes);
+ first_socket.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps_.socket_factory->AddSocketDataProvider(&first_socket);
+
+ // This is used for the non-preconnect requests.
+ SSLSocketDataProvider ssl_data1(ASYNC, OK);
+ ssl_data1.next_proto = kProtoHTTP2;
+ // "wildcard.pem" supports "*.example.org".
+ ssl_data1.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
+
+ // This is used for the preconnect request.
+ SequencedSocketData second_socket;
+ // The connection is paused. And it will be completed with
+ // ERR_CONNECTION_FAILED.
+ second_socket.set_connect_data(MockConnect(ASYNC, ERR_IO_PENDING));
+ session_deps_.socket_factory->AddSocketDataProvider(&second_socket);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org");
+ Initialize(request_info);
+
+ // Start a non-preconnect request [1].
+ {
+ std::unique_ptr<HttpStreamRequest> stream_request = job_controller_->Start(
+ &request_delegate_,
+ /*websocket_handshake_stream_create_helper=*/nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY);
+ base::RunLoop run_loop;
+ EXPECT_CALL(request_delegate_, OnStreamReadyImpl(_, _, _))
+ .WillOnce([&run_loop]() { run_loop.Quit(); });
+ run_loop.Run();
+ }
+
+ // Sanity check - make sure the SpdySession was created.
+ {
+ base::WeakPtr<SpdySession> spdy_session =
+ session_->spdy_session_pool()->FindAvailableSession(
+ SpdySessionKey(HostPortPair::FromURL(request_info.url),
+ ProxyServer::Direct(), request_info.privacy_mode,
+ SpdySessionKey::IsProxySession::kFalse,
+ request_info.socket_tag,
+ request_info.network_isolation_key,
+ request_info.secure_dns_policy),
+ /*enable_ip_based_pooling=*/false, /*is_websocket=*/false,
+ NetLogWithSource());
+ EXPECT_TRUE(spdy_session);
+ }
+
+ HttpRequestInfo other_request_info;
+ other_request_info.method = "GET";
+ other_request_info.url = GURL("https://other.example.org");
+
+ // Create and start a preconnect request [2].
+ MockHttpStreamRequestDelegate preconnect_request_delegate;
+ HttpStreamFactory::JobController* preconnect_job_controller =
+ new HttpStreamFactory::JobController(
+ factory_, &preconnect_request_delegate, session_.get(), &job_factory_,
+ other_request_info, /*is_preconnect=*/true,
+ /*is_websocket=*/false, /*enable_ip_based_pooling=*/true,
+ enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
+ SSLConfig());
+ HttpStreamFactoryPeer::AddJobController(factory_, preconnect_job_controller);
+ preconnect_job_controller->Preconnect(1);
+ base::RunLoop().RunUntilIdle();
+
+ // The SpdySession is available for IP based pooling when the host resolution
+ // has finished.
+ {
+ const SpdySessionKey spdy_session_key = SpdySessionKey(
+ HostPortPair::FromURL(other_request_info.url), ProxyServer::Direct(),
+ other_request_info.privacy_mode, SpdySessionKey::IsProxySession::kFalse,
+ other_request_info.socket_tag, other_request_info.network_isolation_key,
+ other_request_info.secure_dns_policy);
+ EXPECT_FALSE(session_->spdy_session_pool()->FindAvailableSession(
+ spdy_session_key, /*enable_ip_based_pooling=*/false,
+ /*is_websocket=*/false, NetLogWithSource()));
+ EXPECT_TRUE(session_->spdy_session_pool()->FindAvailableSession(
+ spdy_session_key, /*enable_ip_based_pooling=*/true,
+ /*is_websocket=*/false, NetLogWithSource()));
+ }
+
+ // Create and start a second non-preconnect request [3].
+ {
+ MockHttpStreamRequestDelegate request_delegate;
+ HttpStreamFactory::JobController* job_controller =
+ new HttpStreamFactory::JobController(
+ factory_, &request_delegate, session_.get(), &job_factory_,
+ other_request_info, /*is_preconnect=*/false,
+ /*is_websocket=*/false, /*enable_ip_based_pooling=*/true,
+ enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
+ SSLConfig());
+ HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
+ std::unique_ptr<HttpStreamRequest> second_stream_request =
+ job_controller->Start(
+ &request_delegate,
+ /*websocket_handshake_stream_create_helper=*/nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(request_delegate, OnStreamReadyImpl(_, _, _))
+ .WillOnce([&run_loop]() { run_loop.Quit(); });
+ run_loop.Run();
+ second_stream_request.reset();
+ }
+
+ second_socket.socket()->OnConnectComplete(
+ MockConnect(SYNCHRONOUS, ERR_CONNECTION_FAILED));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(HttpStreamFactoryPeer::IsJobControllerDeleted(factory_));
+ EXPECT_TRUE(first_socket.AllReadDataConsumed());
+ EXPECT_TRUE(first_socket.AllWriteDataConsumed());
+}
+
class JobControllerLimitMultipleH2Requests
: public HttpStreamFactoryJobControllerTest {
protected:
@@ -2805,7 +3008,8 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultipleRequests) {
new HttpStreamFactory::JobController(
factory_, request_delegates[i].get(), session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
auto request = job_controller->Start(
@@ -2892,7 +3096,9 @@ TEST_F(JobControllerLimitMultipleH2Requests,
factory_, request_delegates[i].get(), session_.get(),
&job_factory_, request_info, is_preconnect_,
false /* is_websocket */, enable_ip_based_pooling_,
- enable_alternative_services_, SSLConfig(), SSLConfig());
+ enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
+ SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
auto request = job_controller->Start(
request_delegates[i].get(), nullptr, net_log_with_source_,
@@ -2967,7 +3173,8 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultipleRequestsFirstRequestHang) {
new HttpStreamFactory::JobController(
factory_, request_delegates[i].get(), session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
auto request = job_controller->Start(
@@ -3040,7 +3247,8 @@ TEST_F(JobControllerLimitMultipleH2Requests,
new HttpStreamFactory::JobController(
factory_, request_delegates[i].get(), session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
auto request = job_controller->Start(
@@ -3095,7 +3303,8 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultiplePreconnects) {
new HttpStreamFactory::JobController(
factory_, request_delegates[i].get(), session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
job_controller->Preconnect(1);
@@ -3143,7 +3352,8 @@ TEST_F(JobControllerLimitMultipleH2Requests, H1NegotiatedForFirstRequest) {
new HttpStreamFactory::JobController(
factory_, request_delegates[i].get(), session_.get(), &job_factory_,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
auto request = job_controller->Start(
@@ -3205,7 +3415,8 @@ TEST_F(JobControllerLimitMultipleH2Requests, QuicJobNotThrottled) {
new HttpStreamFactory::JobController(
factory_, &request_delegate_, session_.get(), &default_job_factory,
request_info, is_preconnect_, false /* is_websocket */,
- enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+ enable_ip_based_pooling_, enable_alternative_services_,
+ delay_main_job_with_available_spdy_session_, SSLConfig(),
SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
request_ =
@@ -3303,7 +3514,9 @@ class HttpStreamFactoryJobControllerPreconnectTest
request_info_, /* is_preconnect = */ true,
/* is_websocket = */ false,
/* enable_ip_based_pooling = */ true,
- /* enable_alternative_services = */ true, SSLConfig(), SSLConfig());
+ /* enable_alternative_services = */ true,
+ /* delay_main_job_with_available_spdy_session = */ true, SSLConfig(),
+ SSLConfig());
HttpStreamFactoryPeer::AddJobController(factory_, job_controller_);
}
diff --git a/chromium/net/http/http_stream_factory_test_util.cc b/chromium/net/http/http_stream_factory_test_util.cc
index 3da68eec0e6..5b7a376b708 100644
--- a/chromium/net/http/http_stream_factory_test_util.cc
+++ b/chromium/net/http/http_stream_factory_test_util.cc
@@ -52,10 +52,7 @@ MockHttpStreamFactoryJob::MockHttpStreamFactoryJob(
MockHttpStreamFactoryJob::~MockHttpStreamFactoryJob() = default;
-TestJobFactory::TestJobFactory()
- : main_job_(nullptr),
- alternative_job_(nullptr),
- override_main_job_url_(false) {}
+TestJobFactory::TestJobFactory() = default;
TestJobFactory::~TestJobFactory() = default;
diff --git a/chromium/net/http/http_stream_factory_test_util.h b/chromium/net/http/http_stream_factory_test_util.h
index 163129859bb..ac89b431dba 100644
--- a/chromium/net/http/http_stream_factory_test_util.h
+++ b/chromium/net/http/http_stream_factory_test_util.h
@@ -174,9 +174,9 @@ class TestJobFactory : public HttpStreamFactory::JobFactory {
}
private:
- raw_ptr<MockHttpStreamFactoryJob> main_job_;
- raw_ptr<MockHttpStreamFactoryJob> alternative_job_;
- bool override_main_job_url_;
+ raw_ptr<MockHttpStreamFactoryJob> main_job_ = nullptr;
+ raw_ptr<MockHttpStreamFactoryJob> alternative_job_ = nullptr;
+ bool override_main_job_url_ = false;
GURL main_job_alternative_url_;
};
diff --git a/chromium/net/http/http_stream_factory_unittest.cc b/chromium/net/http/http_stream_factory_unittest.cc
index 7145365d4ac..e11997a6ae8 100644
--- a/chromium/net/http/http_stream_factory_unittest.cc
+++ b/chromium/net/http/http_stream_factory_unittest.cc
@@ -25,6 +25,7 @@
#include "build/build_config.h"
#include "net/base/completion_once_callback.h"
#include "net/base/features.h"
+#include "net/base/net_errors.h"
#include "net/base/network_isolation_key.h"
#include "net/base/port_util.h"
#include "net/base/privacy_mode.h"
@@ -163,7 +164,9 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
}
void GetSSLInfo(SSLInfo* ssl_info) override {}
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
- bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
+ int GetRemoteEndpoint(IPEndPoint* endpoint) override {
+ return ERR_UNEXPECTED;
+ }
void Drain(HttpNetworkSession* session) override {}
void PopulateNetErrorDetails(NetErrorDetails* details) override { return; }
void SetPriority(RequestPriority priority) override {}
@@ -189,11 +192,8 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
class MockHttpStreamFactoryForPreconnect : public HttpStreamFactory {
public:
explicit MockHttpStreamFactoryForPreconnect(HttpNetworkSession* session)
- : HttpStreamFactory(session),
- preconnect_done_(false),
- waiting_for_preconnect_(false) {}
-
- ~MockHttpStreamFactoryForPreconnect() override {}
+ : HttpStreamFactory(session) {}
+ ~MockHttpStreamFactoryForPreconnect() override = default;
void WaitForPreconnects() {
while (!preconnect_done_) {
@@ -211,14 +211,14 @@ class MockHttpStreamFactoryForPreconnect : public HttpStreamFactory {
loop_.QuitWhenIdle();
}
- bool preconnect_done_;
- bool waiting_for_preconnect_;
+ bool preconnect_done_ = false;
+ bool waiting_for_preconnect_ = false;
base::RunLoop loop_;
};
class StreamRequestWaiter : public HttpStreamRequest::Delegate {
public:
- StreamRequestWaiter() : error_status_(OK) {}
+ StreamRequestWaiter() = default;
StreamRequestWaiter(const StreamRequestWaiter&) = delete;
StreamRequestWaiter& operator=(const StreamRequestWaiter&) = delete;
@@ -319,7 +319,7 @@ class StreamRequestWaiter : public HttpStreamRequest::Delegate {
std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_;
SSLConfig used_ssl_config_;
ProxyInfo used_proxy_info_;
- int error_status_;
+ int error_status_ = OK;
};
class WebSocketBasicHandshakeStream : public MockWebSocketHandshakeStream {
@@ -423,8 +423,7 @@ class CapturePreconnectsTransportSocketPool : public TransportClientSocketPool {
base::TimeDelta(),
ProxyServer::Direct(),
false /* is_for_websockets */,
- common_connect_job_params),
- last_num_streams_(-1) {}
+ common_connect_job_params) {}
int last_num_streams() const { return last_num_streams_; }
const ClientSocketPool::GroupId& last_group_id() const {
@@ -457,14 +456,16 @@ class CapturePreconnectsTransportSocketPool : public TransportClientSocketPool {
return ERR_UNEXPECTED;
}
- void RequestSockets(
+ int RequestSockets(
const ClientSocketPool::GroupId& group_id,
scoped_refptr<ClientSocketPool::SocketParams> socket_params,
const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
int num_sockets,
+ CompletionOnceCallback callback,
const NetLogWithSource& net_log) override {
last_num_streams_ = num_sockets;
last_group_id_ = group_id;
+ return OK;
}
void CancelRequest(const ClientSocketPool::GroupId& group_id,
@@ -496,7 +497,7 @@ class CapturePreconnectsTransportSocketPool : public TransportClientSocketPool {
}
private:
- int last_num_streams_;
+ int last_num_streams_ = -1;
ClientSocketPool::GroupId last_group_id_;
};
@@ -946,8 +947,7 @@ class TestBidirectionalDelegate : public BidirectionalStreamImpl::Delegate {
// Simplify ownership issues and the interaction with the MockSocketFactory.
class MockQuicData {
public:
- explicit MockQuicData(quic::ParsedQuicVersion version)
- : packet_number_(0), printer_(version) {}
+ explicit MockQuicData(quic::ParsedQuicVersion version) : printer_(version) {}
~MockQuicData() = default;
@@ -977,7 +977,7 @@ class MockQuicData {
std::vector<std::unique_ptr<quic::QuicEncryptedPacket>> packets_;
std::vector<MockWrite> writes_;
std::vector<MockRead> reads_;
- size_t packet_number_;
+ size_t packet_number_ = 0;
QuicPacketPrinter printer_;
std::unique_ptr<SequencedSocketData> socket_data_;
};
@@ -1065,10 +1065,10 @@ int GetHandedOutSocketCount(ClientSocketPool* pool) {
// Return count of distinct QUIC sessions.
int GetQuicSessionCount(HttpNetworkSession* session) {
base::Value dict(session->QuicInfoToValue());
- base::Value* session_list = dict.FindListKey("sessions");
+ base::Value::List* session_list = dict.GetDict().FindList("sessions");
if (!session_list)
return -1;
- return session_list->GetListDeprecated().size();
+ return session_list->size();
}
TEST_F(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
@@ -2086,7 +2086,7 @@ class HttpStreamFactoryBidirectionalQuicTest
MockHostResolver* host_resolver() { return &host_resolver_; }
private:
- QuicFlagSaver saver_;
+ quic::test::QuicFlagSaver saver_;
const quic::ParsedQuicVersion version_;
const bool client_headers_include_h2_stream_dependency_;
MockQuicContext quic_context_;
diff --git a/chromium/net/http/http_stream_parser.cc b/chromium/net/http/http_stream_parser.cc
index 0637a502b9a..7a0e8f0e4ca 100644
--- a/chromium/net/http/http_stream_parser.cc
+++ b/chromium/net/http/http_stream_parser.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
+#include "base/numerics/clamped_math.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "net/base/io_buffer.h"
@@ -24,6 +25,7 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/log/net_log_event_type.h"
#include "net/socket/ssl_client_socket.h"
@@ -113,12 +115,7 @@ bool ShouldTryReadingOnUploadError(int error_code) {
class HttpStreamParser::SeekableIOBuffer : public IOBuffer {
public:
explicit SeekableIOBuffer(int capacity)
- : IOBuffer(capacity),
- real_data_(data_),
- capacity_(capacity),
- size_(0),
- used_(0) {
- }
+ : IOBuffer(capacity), real_data_(data_), capacity_(capacity) {}
// DidConsume() changes the |data_| pointer so that |data_| always points
// to the first unconsumed byte.
@@ -171,8 +168,8 @@ class HttpStreamParser::SeekableIOBuffer : public IOBuffer {
raw_ptr<char> real_data_;
const int capacity_;
- int size_;
- int used_;
+ int size_ = 0;
+ int used_ = 0;
};
// 2 CRLFs + max of 8 hex chars.
@@ -183,26 +180,12 @@ HttpStreamParser::HttpStreamParser(StreamSocket* stream_socket,
const HttpRequestInfo* request,
GrowableIOBuffer* read_buffer,
const NetLogWithSource& net_log)
- : io_state_(STATE_NONE),
- request_(request),
- request_headers_(nullptr),
- request_headers_length_(0),
+ : request_(request),
read_buf_(read_buffer),
- read_buf_unused_offset_(0),
response_header_start_offset_(std::string::npos),
- received_bytes_(0),
- sent_bytes_(0),
- response_(nullptr),
- response_body_length_(-1),
- response_is_keep_alive_(false),
- response_body_read_(0),
- user_read_buf_(nullptr),
- user_read_buf_len_(0),
stream_socket_(stream_socket),
connection_is_reused_(connection_is_reused),
- net_log_(net_log),
- sent_last_chunk_(false),
- upload_error_(OK) {
+ net_log_(net_log) {
io_callback_ = base::BindRepeating(&HttpStreamParser::OnIOComplete,
weak_ptr_factory_.GetWeakPtr());
}
@@ -912,7 +895,7 @@ int HttpStreamParser::HandleReadHeaderResult(int result) {
response_body_length_ = -1;
// Record the timing of the 103 Early Hints response for the experiment
// (https://crbug.com/1093693).
- if (response_->headers->response_code() == 103 &&
+ if (response_->headers->response_code() == net::HTTP_EARLY_HINTS &&
first_early_hints_time_.is_null()) {
first_early_hints_time_ = current_response_start_time_;
}
@@ -1018,7 +1001,7 @@ int HttpStreamParser::ParseResponseHeaders(int end_offset) {
// See
// https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/qS63pYso4P0
if (read_buf_->offset() < 3 || scheme != "http" ||
- !base::LowerCaseEqualsASCII(
+ !base::EqualsCaseInsensitiveASCII(
base::StringPiece(read_buf_->StartOfBuffer(), 3), "icy")) {
return ERR_INVALID_HTTP_RESPONSE;
}
@@ -1087,9 +1070,9 @@ void HttpStreamParser::CalculateResponseBodySize() {
response_body_length_ = 0;
} else {
switch (response_->headers->response_code()) {
- case 204: // No Content
- case 205: // Reset Content
- case 304: // Not Modified
+ case net::HTTP_NO_CONTENT: // No Content
+ case net::HTTP_RESET_CONTENT: // Reset Content
+ case net::HTTP_NOT_MODIFIED: // Not Modified
response_body_length_ = 0;
break;
}
diff --git a/chromium/net/http/http_stream_parser.h b/chromium/net/http/http_stream_parser.h
index 16b5c49983b..73a4bc560ea 100644
--- a/chromium/net/http/http_stream_parser.h
+++ b/chromium/net/http/http_stream_parser.h
@@ -211,7 +211,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
bool SendRequestBuffersEmpty();
// Next state of the request, when the current one completes.
- State io_state_;
+ State io_state_ = STATE_NONE;
// Null when read state machine is invoked.
raw_ptr<const HttpRequestInfo> request_;
@@ -221,7 +221,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// Size of just the request headers. May be less than the length of
// |request_headers_| if the body was merged with the headers.
- int request_headers_length_;
+ int request_headers_length_ = 0;
// Temporary buffer for reading.
scoped_refptr<GrowableIOBuffer> read_buf_;
@@ -229,7 +229,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// Offset of the first unused byte in |read_buf_|. May be nonzero due to
// body data in the same packet as header data but is zero when reading
// headers.
- int read_buf_unused_offset_;
+ int read_buf_unused_offset_ = 0;
// The amount beyond |read_buf_unused_offset_| where the status line starts;
// std::string::npos if not found yet.
@@ -237,16 +237,16 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// The amount of received data. If connection is reused then intermediate
// value may be bigger than final.
- int64_t received_bytes_;
+ int64_t received_bytes_ = 0;
// The amount of sent data.
- int64_t sent_bytes_;
+ int64_t sent_bytes_ = 0;
// The parsed response headers. Owned by the caller of SendRequest. This
// cannot be safely accessed after reading the final set of headers, as the
// caller of SendRequest may have been destroyed - this happens in the case an
// HttpResponseBodyDrainer is used.
- raw_ptr<HttpResponseInfo> response_;
+ raw_ptr<HttpResponseInfo> response_ = nullptr;
// Time at which the first bytes of the first header response including
// informational responses (1xx) are about to be parsed. This corresponds to
@@ -271,10 +271,10 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// Indicates the content length. If this value is less than zero
// (and chunked_decoder_ is null), then we must read until the server
// closes the connection.
- int64_t response_body_length_;
+ int64_t response_body_length_ = -1;
// True if reading a keep-alive response. False if not, or if don't yet know.
- bool response_is_keep_alive_;
+ bool response_is_keep_alive_ = false;
// True if we've seen a response that has an HTTP status line. This is
// persistent across multiple response parsing. If we see a status line
@@ -282,14 +282,14 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
bool has_seen_status_line_ = false;
// Keep track of the number of response body bytes read so far.
- int64_t response_body_read_;
+ int64_t response_body_read_ = 0;
// Helper if the data is chunked.
std::unique_ptr<HttpChunkedDecoder> chunked_decoder_;
// Where the caller wants the body data.
scoped_refptr<IOBuffer> user_read_buf_;
- int user_read_buf_len_;
+ int user_read_buf_len_ = 0;
// The callback to notify a user that the handshake has been confirmed.
CompletionOnceCallback confirm_handshake_callback_;
@@ -317,10 +317,10 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// Buffer used to send the request body. This points the same buffer as
// |request_body_read_buf_| unless the data is chunked.
scoped_refptr<SeekableIOBuffer> request_body_send_buf_;
- bool sent_last_chunk_;
+ bool sent_last_chunk_ = false;
// Error received when uploading the body, if any.
- int upload_error_;
+ int upload_error_ = OK;
MutableNetworkTrafficAnnotationTag traffic_annotation_;
diff --git a/chromium/net/http/http_stream_parser_unittest.cc b/chromium/net/http/http_stream_parser_unittest.cc
index 62373540a51..d870cd1c398 100644
--- a/chromium/net/http/http_stream_parser_unittest.cc
+++ b/chromium/net/http/http_stream_parser_unittest.cc
@@ -1227,10 +1227,9 @@ class SimpleGetRunner {
public:
SimpleGetRunner()
: url_("http://localhost"),
- read_buffer_(base::MakeRefCounted<GrowableIOBuffer>()),
- sequence_number_(0) {
- writes_.push_back(MockWrite(
- SYNCHRONOUS, sequence_number_++, "GET / HTTP/1.1\r\n\r\n"));
+ read_buffer_(base::MakeRefCounted<GrowableIOBuffer>()) {
+ writes_.emplace_back(
+ MockWrite(SYNCHRONOUS, sequence_number_++, "GET / HTTP/1.1\r\n\r\n"));
}
void set_url(const GURL& url) { url_ = url; }
@@ -1313,7 +1312,7 @@ class SimpleGetRunner {
std::unique_ptr<StreamSocket> stream_socket_;
std::unique_ptr<SequencedSocketData> data_;
std::unique_ptr<HttpStreamParser> parser_;
- int sequence_number_;
+ int sequence_number_ = 0;
};
// Test that HTTP/0.9 works as expected, only on ports where it should be
diff --git a/chromium/net/http/http_stream_request.cc b/chromium/net/http/http_stream_request.cc
index 980bc740455..c2446311e23 100644
--- a/chromium/net/http/http_stream_request.cc
+++ b/chromium/net/http/http_stream_request.cc
@@ -29,10 +29,6 @@ HttpStreamRequest::HttpStreamRequest(
websocket_handshake_stream_create_helper_(
websocket_handshake_stream_create_helper),
net_log_(net_log),
- completed_(false),
- was_alpn_negotiated_(false),
- negotiated_protocol_(kProtoUnknown),
- using_spdy_(false),
stream_type_(stream_type) {
net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_REQUEST);
}
diff --git a/chromium/net/http/http_stream_request.h b/chromium/net/http/http_stream_request.h
index a96da693891..8b8eb41dfdf 100644
--- a/chromium/net/http/http_stream_request.h
+++ b/chromium/net/http/http_stream_request.h
@@ -226,11 +226,11 @@ class NET_EXPORT_PRIVATE HttpStreamRequest {
websocket_handshake_stream_create_helper_;
const NetLogWithSource net_log_;
- bool completed_;
- bool was_alpn_negotiated_;
+ bool completed_ = false;
+ bool was_alpn_negotiated_ = false;
// Protocol negotiated with the server.
- NextProto negotiated_protocol_;
- bool using_spdy_;
+ NextProto negotiated_protocol_ = kProtoUnknown;
+ bool using_spdy_ = false;
ConnectionAttempts connection_attempts_;
const StreamType stream_type_;
};
diff --git a/chromium/net/http/http_stream_request_unittest.cc b/chromium/net/http/http_stream_request_unittest.cc
index ce2667feefa..bd31793c593 100644
--- a/chromium/net/http/http_stream_request_unittest.cc
+++ b/chromium/net/http/http_stream_request_unittest.cc
@@ -44,7 +44,9 @@ TEST(HttpStreamRequestTest, SetPriority) {
/* is_preconnect = */ false,
/* is_websocket = */ false,
/* enable_ip_based_pooling = */ true,
- /* enable_alternative_services = */ true, SSLConfig(), SSLConfig());
+ /* enable_alternative_services = */ true,
+ /* delay_main_job_with_available_spdy_session = */ true, SSLConfig(),
+ SSLConfig());
HttpStreamFactory::JobController* job_controller_raw_ptr =
job_controller.get();
factory->job_controller_set_.insert(std::move(job_controller));
diff --git a/chromium/net/http/http_transaction_test_util.cc b/chromium/net/http/http_transaction_test_util.cc
index 6c750250382..254263aba71 100644
--- a/chromium/net/http/http_transaction_test_util.cc
+++ b/chromium/net/http/http_transaction_test_util.cc
@@ -32,7 +32,6 @@
#include "net/http/http_transaction.h"
#include "net/log/net_log.h"
#include "net/log/net_log_source.h"
-#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_private_key.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -215,8 +214,7 @@ int TestTransactionConsumer::quit_counter_ = 0;
TestTransactionConsumer::TestTransactionConsumer(
RequestPriority priority,
- HttpTransactionFactory* factory)
- : state_(State::kIdle), error_(OK) {
+ HttpTransactionFactory* factory) {
// Disregard the error code.
factory->CreateTransaction(priority, &trans_);
++quit_counter_;
@@ -286,18 +284,7 @@ void TestTransactionConsumer::OnIOComplete(int result) {
MockNetworkTransaction::MockNetworkTransaction(RequestPriority priority,
MockNetworkLayer* factory)
- : request_(nullptr),
- data_cursor_(0),
- content_length_(0),
- priority_(priority),
- read_handler_(nullptr),
- websocket_handshake_stream_create_helper_(nullptr),
- transaction_factory_(factory->AsWeakPtr()),
- received_bytes_(0),
- sent_bytes_(0),
- socket_log_id_(NetLogSource::kInvalidId),
- done_reading_called_(false),
- reading_(false) {}
+ : priority_(priority), transaction_factory_(factory->AsWeakPtr()) {}
MockNetworkTransaction::~MockNetworkTransaction() {
// Use request_ as in ~HttpNetworkTransaction to make sure its valid and not
@@ -512,6 +499,8 @@ int MockNetworkTransaction::StartInternal(const HttpRequestInfo* request,
response_.was_cached = false;
response_.network_accessed = true;
response_.remote_endpoint = t->transport_info.endpoint;
+ response_.was_fetched_via_proxy =
+ t->transport_info.type == TransportType::kProxied;
response_.response_time = transaction_factory_->Now();
if (!t->response_time.is_null())
@@ -576,7 +565,7 @@ int MockNetworkTransaction::ResumeNetworkStart() {
}
ConnectionAttempts MockNetworkTransaction::GetConnectionAttempts() const {
- NOTIMPLEMENTED();
+ // TODO(ricea): Replace this with a proper implementation if needed.
return {};
}
@@ -597,13 +586,7 @@ void MockNetworkTransaction::RunCallback(CompletionOnceCallback callback,
std::move(callback).Run(result);
}
-MockNetworkLayer::MockNetworkLayer()
- : transaction_count_(0),
- done_reading_called_(false),
- stop_caching_called_(false),
- last_create_transaction_priority_(DEFAULT_PRIORITY),
- clock_(nullptr) {
-}
+MockNetworkLayer::MockNetworkLayer() = default;
MockNetworkLayer::~MockNetworkLayer() = default;
diff --git a/chromium/net/http/http_transaction_test_util.h b/chromium/net/http/http_transaction_test_util.h
index 18e015452d9..71541b55510 100644
--- a/chromium/net/http/http_transaction_test_util.h
+++ b/chromium/net/http/http_transaction_test_util.h
@@ -33,6 +33,7 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/log/net_log_source.h"
#include "net/socket/connection_attempts.h"
namespace net {
@@ -170,11 +171,11 @@ class TestTransactionConsumer {
void OnIOComplete(int result);
- State state_;
+ State state_ = State::kIdle;
std::unique_ptr<HttpTransaction> trans_;
std::string content_;
scoped_refptr<IOBuffer> read_buf_;
- int error_;
+ int error_ = OK;
static int quit_counter_;
};
@@ -276,29 +277,29 @@ class MockNetworkTransaction
void CallbackLater(CompletionOnceCallback callback, int result);
void RunCallback(CompletionOnceCallback callback, int result);
- raw_ptr<const HttpRequestInfo> request_;
+ raw_ptr<const HttpRequestInfo> request_ = nullptr;
HttpResponseInfo response_;
std::string data_;
- int64_t data_cursor_;
- int64_t content_length_;
+ int64_t data_cursor_ = 0;
+ int64_t content_length_ = 0;
int test_mode_;
RequestPriority priority_;
- MockTransactionReadHandler read_handler_;
- raw_ptr<CreateHelper> websocket_handshake_stream_create_helper_;
+ MockTransactionReadHandler read_handler_ = nullptr;
+ raw_ptr<CreateHelper> websocket_handshake_stream_create_helper_ = nullptr;
BeforeNetworkStartCallback before_network_start_callback_;
ConnectedCallback connected_callback_;
base::WeakPtr<MockNetworkLayer> transaction_factory_;
- int64_t received_bytes_;
- int64_t sent_bytes_;
+ int64_t received_bytes_ = 0;
+ int64_t sent_bytes_ = 0;
// NetLog ID of the fake / non-existent underlying socket used by the
// connection. Requires Start() be passed a NetLogWithSource with a real
// NetLog to
// be initialized.
- unsigned int socket_log_id_;
+ unsigned int socket_log_id_ = NetLogSource::kInvalidId;
- bool done_reading_called_;
- bool reading_;
+ bool done_reading_called_ = false;
+ bool reading_ = false;
CompletionOnceCallback resume_start_callback_; // used for pause and restart.
@@ -356,14 +357,14 @@ class MockNetworkLayer : public HttpTransactionFactory,
base::Time Now();
private:
- int transaction_count_;
- bool done_reading_called_;
- bool stop_caching_called_;
- RequestPriority last_create_transaction_priority_;
+ int transaction_count_ = 0;
+ bool done_reading_called_ = false;
+ bool stop_caching_called_ = false;
+ RequestPriority last_create_transaction_priority_ = DEFAULT_PRIORITY;
// By default clock_ is NULL but it can be set to a custom clock by test
// frameworks using SetClock.
- raw_ptr<base::Clock> clock_;
+ raw_ptr<base::Clock> clock_ = nullptr;
base::WeakPtr<MockNetworkTransaction> last_transaction_;
};
diff --git a/chromium/net/http/http_util.cc b/chromium/net/http/http_util.cc
index 0978147da37..96a6e2943e8 100644
--- a/chromium/net/http/http_util.cc
+++ b/chromium/net/http/http_util.cc
@@ -114,14 +114,14 @@ void HttpUtil::ParseContentType(const std::string& content_type_str,
// Trim LWS from param value, ParseMimeType() leaves WS for quoted-string.
// TODO(mmenke): Check that name has only valid characters.
if (!type_has_charset &&
- base::LowerCaseEqualsASCII(param.first, "charset")) {
+ base::EqualsCaseInsensitiveASCII(param.first, "charset")) {
type_has_charset = true;
charset_value = std::string(HttpUtil::TrimLWS(param.second));
continue;
}
if (boundary && !type_has_boundary &&
- base::LowerCaseEqualsASCII(param.first, "boundary")) {
+ base::EqualsCaseInsensitiveASCII(param.first, "boundary")) {
type_has_boundary = true;
*boundary = std::string(HttpUtil::TrimLWS(param.second));
continue;
@@ -131,7 +131,7 @@ void HttpUtil::ParseContentType(const std::string& content_type_str,
// If `mime_type_value` is the same as `mime_type`, then just update
// `charset`. However, if `charset` is empty and `mime_type` hasn't changed,
// then don't wipe-out an existing `charset`.
- bool eq = base::LowerCaseEqualsASCII(mime_type->data(), mime_type_value);
+ bool eq = base::EqualsCaseInsensitiveASCII(mime_type_value, *mime_type);
if (!eq) {
*mime_type = base::ToLowerASCII(mime_type_value);
}
@@ -154,7 +154,7 @@ bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier,
// "bytes" unit identifier is not found.
bytes_unit = TrimLWS(bytes_unit);
- if (!base::LowerCaseEqualsASCII(bytes_unit, "bytes")) {
+ if (!base::EqualsCaseInsensitiveASCII(bytes_unit, "bytes")) {
return false;
}
@@ -227,7 +227,7 @@ bool HttpUtil::ParseContentRangeHeaderFor206(
return false;
// Invalid header if it doesn't contain "bytes-unit".
- if (!base::LowerCaseEqualsASCII(
+ if (!base::EqualsCaseInsensitiveASCII(
TrimLWS(content_range_spec.substr(0, space_position)), "bytes")) {
return false;
}
@@ -332,7 +332,7 @@ bool HttpUtil::IsSafeHeader(base::StringPiece name) {
return false;
for (const char* field : kForbiddenHeaderFields) {
- if (base::LowerCaseEqualsASCII(name, field))
+ if (base::EqualsCaseInsensitiveASCII(name, field))
return false;
}
return true;
@@ -375,7 +375,7 @@ bool HttpUtil::IsNonCoalescingHeader(base::StringPiece name) {
};
for (const char* header : kNonCoalescingHeaders) {
- if (base::LowerCaseEqualsASCII(name, header)) {
+ if (base::EqualsCaseInsensitiveASCII(name, header)) {
return true;
}
}
@@ -518,8 +518,8 @@ size_t HttpUtil::LocateStartOfStatusLine(const char* buf, size_t buf_len) {
if (buf_len >= http_len) {
size_t i_max = std::min(buf_len - http_len, slop);
for (size_t i = 0; i <= i_max; ++i) {
- if (base::LowerCaseEqualsASCII(base::StringPiece(buf + i, http_len),
- "http"))
+ if (base::EqualsCaseInsensitiveASCII(base::StringPiece(buf + i, http_len),
+ "http"))
return i;
}
}
@@ -751,7 +751,7 @@ bool HttpUtil::HasStrongValidators(HttpVersion version,
std::string::const_iterator i = etag_header.begin();
std::string::const_iterator j = etag_header.begin() + slash;
TrimLWS(&i, &j);
- if (!base::LowerCaseEqualsASCII(base::MakeStringPiece(i, j), "w"))
+ if (!base::EqualsCaseInsensitiveASCII(base::MakeStringPiece(i, j), "w"))
return true;
}
@@ -870,7 +870,7 @@ bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) {
<< "the header name must be in all lower case";
while (GetNext()) {
- if (base::LowerCaseEqualsASCII(
+ if (base::EqualsCaseInsensitiveASCII(
base::MakeStringPiece(name_begin_, name_end_), name)) {
return true;
}
@@ -917,12 +917,10 @@ HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
Values optional_values,
Quotes strict_quotes)
: props_(begin, end, delimiter),
- valid_(true),
name_begin_(end),
name_end_(end),
value_begin_(end),
value_end_(end),
- value_is_quoted_(false),
values_optional_(optional_values == Values::NOT_REQUIRED),
strict_quotes_(strict_quotes == Quotes::STRICT_QUOTES) {}
@@ -1049,7 +1047,7 @@ bool HttpUtil::ParseAcceptEncoding(const std::string& accept_encoding,
return false;
base::StringPiece param_name = params.substr(0, equals_pos);
param_name = TrimLWS(param_name);
- if (!base::LowerCaseEqualsASCII(param_name, "q"))
+ if (!base::EqualsCaseInsensitiveASCII(param_name, "q"))
return false;
base::StringPiece qvalue = params.substr(equals_pos + 1);
qvalue = TrimLWS(qvalue);
diff --git a/chromium/net/http/http_util.h b/chromium/net/http/http_util.h
index 65f64279020..7733270cf20 100644
--- a/chromium/net/http/http_util.h
+++ b/chromium/net/http/http_util.h
@@ -450,7 +450,7 @@ class NET_EXPORT HttpUtil {
private:
HttpUtil::ValuesIterator props_;
- bool valid_;
+ bool valid_ = true;
std::string::const_iterator name_begin_;
std::string::const_iterator name_end_;
@@ -463,7 +463,7 @@ class NET_EXPORT HttpUtil {
// into the original's unquoted_value_ member.
std::string unquoted_value_;
- bool value_is_quoted_;
+ bool value_is_quoted_ = false;
// True if values are required for each name/value pair; false if a
// name is permitted to appear without a corresponding value.
diff --git a/chromium/net/http/http_util_unittest.cc b/chromium/net/http/http_util_unittest.cc
index 5072a7cbfee..b2eb2332b54 100644
--- a/chromium/net/http/http_util_unittest.cc
+++ b/chromium/net/http/http_util_unittest.cc
@@ -987,6 +987,8 @@ TEST(HttpUtilTest, ParseContentType) {
{ "*/*", "", "", false, "" },
{ "*/*; charset=utf-8", "*/*", "utf-8", true, "" },
{ "*/* ", "*/*", "", false, "" },
+ // Regression test for https://crbug.com/1326529
+ { "teXT/html", "text/html", "", false, ""},
// TODO(abarth): Add more interesting test cases.
};
// clang-format on
@@ -1008,6 +1010,42 @@ TEST(HttpUtilTest, ParseContentType) {
}
}
+TEST(HttpUtilTest, ParseContentResetCharset) {
+ std::string mime_type;
+ std::string charset;
+ bool had_charset = false;
+ std::string boundary;
+
+ // Set mime (capitalization should be ignored), but not charset.
+ HttpUtil::ParseContentType("Text/Html", &mime_type, &charset, &had_charset,
+ &boundary);
+ EXPECT_EQ("text/html", mime_type);
+ EXPECT_EQ("", charset);
+ EXPECT_FALSE(had_charset);
+
+ // The same mime, add charset.
+ HttpUtil::ParseContentType("tExt/hTml;charset=utf-8", &mime_type, &charset,
+ &had_charset, &boundary);
+ EXPECT_EQ("text/html", mime_type);
+ EXPECT_EQ("utf-8", charset);
+ EXPECT_TRUE(had_charset);
+
+ // The same mime (different capitalization), but no charset - should not clear
+ // charset.
+ HttpUtil::ParseContentType("teXt/htMl", &mime_type, &charset, &had_charset,
+ &boundary);
+ EXPECT_EQ("text/html", mime_type);
+ EXPECT_EQ("utf-8", charset);
+ EXPECT_TRUE(had_charset);
+
+ // A different mime will clear charset.
+ HttpUtil::ParseContentType("texT/plaiN", &mime_type, &charset, &had_charset,
+ &boundary);
+ EXPECT_EQ("text/plain", mime_type);
+ EXPECT_EQ("", charset);
+ EXPECT_TRUE(had_charset);
+}
+
TEST(HttpUtilTest, ParseContentRangeHeader) {
const struct {
const char* const content_range_header_spec;
diff --git a/chromium/net/http/http_vary_data.cc b/chromium/net/http/http_vary_data.cc
index 221978e1db5..9b444b9b16c 100644
--- a/chromium/net/http/http_vary_data.cc
+++ b/chromium/net/http/http_vary_data.cc
@@ -15,8 +15,7 @@
namespace net {
-HttpVaryData::HttpVaryData() : is_valid_(false) {
-}
+HttpVaryData::HttpVaryData() = default;
bool HttpVaryData::Init(const HttpRequestInfo& request_info,
const HttpResponseHeaders& response_headers) {
diff --git a/chromium/net/http/http_vary_data.h b/chromium/net/http/http_vary_data.h
index 0f4ceb1d005..c2512465554 100644
--- a/chromium/net/http/http_vary_data.h
+++ b/chromium/net/http/http_vary_data.h
@@ -79,7 +79,7 @@ class NET_EXPORT_PRIVATE HttpVaryData {
base::MD5Digest request_digest_;
// True when request_digest_ contains meaningful data.
- bool is_valid_;
+ bool is_valid_ = false;
};
} // namespace net
diff --git a/chromium/net/http/mock_http_cache.cc b/chromium/net/http/mock_http_cache.cc
index 7a4eea72f62..790d31af772 100644
--- a/chromium/net/http/mock_http_cache.cc
+++ b/chromium/net/http/mock_http_cache.cc
@@ -55,18 +55,7 @@ struct MockDiskEntry::CallbackInfo {
};
MockDiskEntry::MockDiskEntry(const std::string& key)
- : key_(key),
- in_memory_data_(0),
- max_file_size_(std::numeric_limits<int>::max()),
- doomed_(false),
- sparse_(false),
- fail_requests_(0),
- fail_sparse_requests_(false),
- busy_(false),
- delayed_(false),
- cancel_(false),
- defer_op_(DEFER_NONE),
- resume_return_code_(0) {
+ : key_(key), max_file_size_(std::numeric_limits<int>::max()) {
test_mode_ = GetTestModeForEntry(key);
}
@@ -393,19 +382,7 @@ bool MockDiskEntry::ignore_callbacks_ = false;
//-----------------------------------------------------------------------------
MockDiskCache::MockDiskCache()
- : Backend(DISK_CACHE),
- open_count_(0),
- create_count_(0),
- doomed_count_(0),
- max_file_size_(std::numeric_limits<int>::max()),
- fail_requests_(false),
- soft_failures_(0),
- soft_failures_one_instance_(0),
- double_create_check_(true),
- fail_sparse_requests_(false),
- support_in_memory_entry_data_(true),
- force_fail_callback_later_(false),
- defer_op_(MockDiskEntry::DEFER_NONE) {}
+ : Backend(DISK_CACHE), max_file_size_(std::numeric_limits<int>::max()) {}
MockDiskCache::~MockDiskCache() {
ReleaseAll();
@@ -682,21 +659,13 @@ int MockBackendFactory::CreateBackend(
//-----------------------------------------------------------------------------
-MockHttpCache::MockHttpCache() : MockHttpCache(false) {}
+MockHttpCache::MockHttpCache()
+ : MockHttpCache(std::make_unique<MockBackendFactory>()) {}
MockHttpCache::MockHttpCache(
std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory)
- : MockHttpCache(std::move(disk_cache_factory), false) {}
-
-MockHttpCache::MockHttpCache(bool is_main_cache)
- : MockHttpCache(std::make_unique<MockBackendFactory>(), is_main_cache) {}
-
-MockHttpCache::MockHttpCache(
- std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory,
- bool is_main_cache)
: http_cache_(std::make_unique<MockNetworkLayer>(),
- std::move(disk_cache_factory),
- is_main_cache) {}
+ std::move(disk_cache_factory)) {}
disk_cache::Backend* MockHttpCache::backend() {
TestCompletionCallback cb;
@@ -852,8 +821,7 @@ int MockBackendNoCbFactory::CreateBackend(
//-----------------------------------------------------------------------------
-MockBlockingBackendFactory::MockBlockingBackendFactory()
- : backend_(nullptr), block_(true), fail_(false) {}
+MockBlockingBackendFactory::MockBlockingBackendFactory() = default;
MockBlockingBackendFactory::~MockBlockingBackendFactory() = default;
diff --git a/chromium/net/http/mock_http_cache.h b/chromium/net/http/mock_http_cache.h
index f60f7c4656c..9068a3d8456 100644
--- a/chromium/net/http/mock_http_cache.h
+++ b/chromium/net/http/mock_http_cache.h
@@ -137,21 +137,21 @@ class MockDiskEntry : public disk_cache::Entry,
std::string key_;
std::vector<char> data_[kNumCacheEntryDataIndices];
- uint8_t in_memory_data_;
+ uint8_t in_memory_data_ = 0;
int test_mode_;
int max_file_size_;
- bool doomed_;
- bool sparse_;
- int fail_requests_;
- bool fail_sparse_requests_;
- bool busy_;
- bool delayed_;
- bool cancel_;
+ bool doomed_ = false;
+ bool sparse_ = false;
+ int fail_requests_ = 0;
+ bool fail_sparse_requests_ = false;
+ bool busy_ = false;
+ bool delayed_ = false;
+ bool cancel_ = false;
// Used for pause and restart.
- DeferOp defer_op_;
+ DeferOp defer_op_ = DEFER_NONE;
CompletionOnceCallback resume_callback_;
- int resume_return_code_;
+ int resume_return_code_ = 0;
static bool ignore_callbacks_;
};
@@ -261,20 +261,20 @@ class MockDiskCache : public disk_cache::Backend {
EntryMap entries_;
std::vector<std::string> external_cache_hits_;
- int open_count_;
- int create_count_;
- int doomed_count_;
+ int open_count_ = 0;
+ int create_count_ = 0;
+ int doomed_count_ = 0;
int max_file_size_;
- bool fail_requests_;
- int soft_failures_;
- int soft_failures_one_instance_;
- bool double_create_check_;
- bool fail_sparse_requests_;
- bool support_in_memory_entry_data_;
- bool force_fail_callback_later_;
+ bool fail_requests_ = false;
+ int soft_failures_ = 0;
+ int soft_failures_one_instance_ = 0;
+ bool double_create_check_ = true;
+ bool fail_sparse_requests_ = false;
+ bool support_in_memory_entry_data_ = true;
+ bool force_fail_callback_later_ = false;
// Used for pause and restart.
- MockDiskEntry::DeferOp defer_op_;
+ MockDiskEntry::DeferOp defer_op_ = MockDiskEntry::DEFER_NONE;
base::OnceClosure resume_callback_;
};
@@ -290,11 +290,6 @@ class MockHttpCache {
MockHttpCache();
explicit MockHttpCache(
std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory);
- // |is_main_cache| if set, will set a quic server info factory.
- explicit MockHttpCache(bool is_main_cache);
-
- MockHttpCache(std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory,
- bool is_main_cache);
HttpCache* http_cache() { return &http_cache_; }
@@ -390,10 +385,10 @@ class MockBlockingBackendFactory : public HttpCache::BackendFactory {
private:
int Result() { return fail_ ? ERR_FAILED : OK; }
- raw_ptr<std::unique_ptr<disk_cache::Backend>> backend_;
+ raw_ptr<std::unique_ptr<disk_cache::Backend>> backend_ = nullptr;
CompletionOnceCallback callback_;
- bool block_;
- bool fail_;
+ bool block_ = true;
+ bool fail_ = false;
};
} // namespace net
diff --git a/chromium/net/http/partial_data.cc b/chromium/net/http/partial_data.cc
index 3f76d090e79..7c60c5114b6 100644
--- a/chromium/net/http/partial_data.cc
+++ b/chromium/net/http/partial_data.cc
@@ -17,6 +17,7 @@
#include "net/base/net_errors.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
namespace net {
@@ -30,18 +31,7 @@ const int kDataStream = 1;
} // namespace
-PartialData::PartialData()
- : current_range_start_(0),
- current_range_end_(0),
- cached_start_(0),
- cached_min_len_(0),
- resource_size_(0),
- range_requested_(false),
- range_present_(false),
- final_range_(false),
- sparse_entry_(true),
- truncated_(false),
- initial_validation_(false) {}
+PartialData::PartialData() = default;
PartialData::~PartialData() = default;
@@ -226,7 +216,7 @@ bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
return true;
}
- sparse_entry_ = (headers->response_code() == 206);
+ sparse_entry_ = (headers->response_code() == net::HTTP_PARTIAL_CONTENT);
if (writing_in_progress || sparse_entry_) {
// |writing_in_progress| means another Transaction is still fetching the
@@ -292,7 +282,7 @@ bool PartialData::IsRequestedRangeOK() {
}
bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
- if (headers->response_code() == 304) {
+ if (headers->response_code() == net::HTTP_NOT_MODIFIED) {
if (!byte_range_.IsValid() || truncated_)
return true;
diff --git a/chromium/net/http/partial_data.h b/chromium/net/http/partial_data.h
index 16510de5ebc..4f6fe440574 100644
--- a/chromium/net/http/partial_data.h
+++ b/chromium/net/http/partial_data.h
@@ -136,8 +136,8 @@ class PartialData {
void GetAvailableRangeCompleted(const disk_cache::RangeResult& result);
// The portion we're trying to get, either from cache or network.
- int64_t current_range_start_;
- int64_t current_range_end_;
+ int64_t current_range_start_ = 0;
+ int64_t current_range_end_ = 0;
// Next portion available in the cache --- this may be what's currently being
// read, or the next thing that will be read if the current network portion
@@ -146,20 +146,20 @@ class PartialData {
// |cached_start_| represents the beginning of the range, while
// |cached_min_len_| the data not yet read (possibly overestimated). It may
// also have an error code latched into it.
- int64_t cached_start_;
- int cached_min_len_;
+ int64_t cached_start_ = 0;
+ int cached_min_len_ = 0;
// The size of the whole file.
- int64_t resource_size_;
+ int64_t resource_size_ = 0;
HttpByteRange byte_range_; // The range requested by the user.
// The clean set of extra headers (no ranges).
HttpRequestHeaders extra_headers_;
- bool range_requested_; // ###
- bool range_present_; // True if next range entry is already stored.
- bool final_range_;
- bool sparse_entry_;
- bool truncated_; // We have an incomplete 200 stored.
- bool initial_validation_; // Only used for truncated entries.
+ bool range_requested_ = false; // ###
+ bool range_present_ = false; // True if next range entry is already stored.
+ bool final_range_ = false;
+ bool sparse_entry_ = true;
+ bool truncated_ = false; // We have an incomplete 200 stored.
+ bool initial_validation_ = false; // Only used for truncated entries.
CompletionOnceCallback callback_;
base::WeakPtrFactory<PartialData> weak_factory_{this};
};
diff --git a/chromium/net/http/structured_headers.cc b/chromium/net/http/structured_headers.cc
deleted file mode 100644
index 58953d7ee4a..00000000000
--- a/chromium/net/http/structured_headers.cc
+++ /dev/null
@@ -1,984 +0,0 @@
-// Copyright 2019 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 "net/http/structured_headers.h"
-
-#include <cmath>
-#include <string>
-#include <utility>
-
-#include "base/base64.h"
-#include "base/containers/flat_set.h"
-#include "base/containers/span.h"
-#include "base/logging.h"
-#include "base/notreached.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-
-namespace net {
-namespace structured_headers {
-
-namespace {
-
-#define DIGIT "0123456789"
-#define LCALPHA "abcdefghijklmnopqrstuvwxyz"
-#define UCALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define TCHAR DIGIT LCALPHA UCALPHA "!#$%&'*+-.^_`|~"
-// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-3.9
-constexpr char kTokenChars09[] = DIGIT UCALPHA LCALPHA "_-.:%*/";
-// https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3.4
-constexpr char kTokenChars[] = TCHAR ":/";
-// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-3.1
-constexpr char kKeyChars09[] = DIGIT LCALPHA "_-";
-// https://www.rfc-editor.org/rfc/rfc8941.html#section-3.1.2
-constexpr char kKeyChars[] = DIGIT LCALPHA "_-.*";
-constexpr char kSP[] = " ";
-constexpr char kOWS[] = " \t";
-#undef DIGIT
-#undef LCALPHA
-#undef UCALPHA
-
-// https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3.1
-constexpr int64_t kMaxInteger = 999'999'999'999'999L;
-constexpr int64_t kMinInteger = -999'999'999'999'999L;
-
-// Smallest value which is too large for an sh-decimal. This is the smallest
-// double which will round up to 1e12 when serialized, which exceeds the range
-// for sh-decimal. Any float less than this should round down. This behaviour is
-// verified by unit tests.
-constexpr double kTooLargeDecimal = 1e12 - 0.0005;
-
-// Parser for (a subset of) Structured Headers for HTTP defined in [SH09] and
-// [RFC8941]. [SH09] compatibility is retained for use by Web Packaging, and can
-// be removed once that spec is updated, and users have migrated to new headers.
-// [SH09] https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09
-// [RFC8941] https://www.rfc-editor.org/rfc/rfc8941.html
-class StructuredHeaderParser {
- public:
- enum DraftVersion {
- kDraft09,
- kFinal,
- };
- explicit StructuredHeaderParser(base::StringPiece str, DraftVersion version)
- : input_(str), version_(version) {
- // [SH09] 4.2 Step 1.
- // Discard any leading OWS from input_string.
- // [RFC8941] 4.2 Step 2.
- // Discard any leading SP characters from input_string.
- SkipWhitespaces();
- }
- StructuredHeaderParser(const StructuredHeaderParser&) = delete;
- StructuredHeaderParser& operator=(const StructuredHeaderParser&) = delete;
-
- // Callers should call this after ReadSomething(), to check if parser has
- // consumed all the input successfully.
- bool FinishParsing() {
- // [SH09] 4.2 Step 7.
- // Discard any leading OWS from input_string.
- // [RFC8941] 4.2 Step 6.
- // Discard any leading SP characters from input_string.
- SkipWhitespaces();
- // [SH09] 4.2 Step 8. [RFC8941] 4.2 Step 7.
- // If input_string is not empty, fail parsing.
- return input_.empty();
- }
-
- // Parses a List of Lists ([SH09] 4.2.4).
- absl::optional<ListOfLists> ReadListOfLists() {
- DCHECK_EQ(version_, kDraft09);
- ListOfLists result;
- while (true) {
- std::vector<Item> inner_list;
- while (true) {
- absl::optional<Item> item(ReadBareItem());
- if (!item)
- return absl::nullopt;
- inner_list.push_back(std::move(*item));
- SkipWhitespaces();
- if (!ConsumeChar(';'))
- break;
- SkipWhitespaces();
- }
- result.push_back(std::move(inner_list));
- SkipWhitespaces();
- if (!ConsumeChar(','))
- break;
- SkipWhitespaces();
- }
- return result;
- }
-
- // Parses a List ([RFC8941] 4.2.1).
- absl::optional<List> ReadList() {
- DCHECK_EQ(version_, kFinal);
- List members;
- while (!input_.empty()) {
- absl::optional<ParameterizedMember> member(ReadItemOrInnerList());
- if (!member)
- return absl::nullopt;
- members.push_back(std::move(*member));
- SkipOWS();
- if (input_.empty())
- break;
- if (!ConsumeChar(','))
- return absl::nullopt;
- SkipOWS();
- if (input_.empty())
- return absl::nullopt;
- }
- return members;
- }
-
- // Parses an Item ([RFC8941] 4.2.3).
- absl::optional<ParameterizedItem> ReadItem() {
- absl::optional<Item> item = ReadBareItem();
- if (!item)
- return absl::nullopt;
- absl::optional<Parameters> parameters = ReadParameters();
- if (!parameters)
- return absl::nullopt;
- return ParameterizedItem(std::move(*item), std::move(*parameters));
- }
-
- // Parses a bare Item ([RFC8941] 4.2.3.1, though this is also the algorithm
- // for parsing an Item from [SH09] 4.2.7).
- absl::optional<Item> ReadBareItem() {
- if (input_.empty()) {
- DVLOG(1) << "ReadBareItem: unexpected EOF";
- return absl::nullopt;
- }
- switch (input_.front()) {
- case '"':
- return ReadString();
- case '*':
- if (version_ == kDraft09)
- return ReadByteSequence();
- return ReadToken();
- case ':':
- if (version_ == kFinal)
- return ReadByteSequence();
- return absl::nullopt;
- case '?':
- return ReadBoolean();
- default:
- if (input_.front() == '-' || base::IsAsciiDigit(input_.front()))
- return ReadNumber();
- if (base::IsAsciiAlpha(input_.front()))
- return ReadToken();
- return absl::nullopt;
- }
- }
-
- // Parses a Dictionary ([RFC8941] 4.2.2).
- absl::optional<Dictionary> ReadDictionary() {
- DCHECK_EQ(version_, kFinal);
- Dictionary members;
- while (!input_.empty()) {
- absl::optional<std::string> key(ReadKey());
- if (!key)
- return absl::nullopt;
- absl::optional<ParameterizedMember> member;
- if (ConsumeChar('=')) {
- member = ReadItemOrInnerList();
- if (!member)
- return absl::nullopt;
- } else {
- absl::optional<Parameters> parameters;
- parameters = ReadParameters();
- if (!parameters)
- return absl::nullopt;
- member = ParameterizedMember{Item(true), std::move(*parameters)};
- }
- members[*key] = std::move(*member);
- SkipOWS();
- if (input_.empty())
- break;
- if (!ConsumeChar(','))
- return absl::nullopt;
- SkipOWS();
- if (input_.empty())
- return absl::nullopt;
- }
- return members;
- }
-
- // Parses a Parameterised List ([SH09] 4.2.5).
- absl::optional<ParameterisedList> ReadParameterisedList() {
- DCHECK_EQ(version_, kDraft09);
- ParameterisedList items;
- while (true) {
- absl::optional<ParameterisedIdentifier> item =
- ReadParameterisedIdentifier();
- if (!item)
- return absl::nullopt;
- items.push_back(std::move(*item));
- SkipWhitespaces();
- if (!ConsumeChar(','))
- return items;
- SkipWhitespaces();
- }
- }
-
- private:
- // Parses a Parameterised Identifier ([SH09] 4.2.6).
- absl::optional<ParameterisedIdentifier> ReadParameterisedIdentifier() {
- DCHECK_EQ(version_, kDraft09);
- absl::optional<Item> primary_identifier = ReadToken();
- if (!primary_identifier)
- return absl::nullopt;
-
- ParameterisedIdentifier::Parameters parameters;
-
- SkipWhitespaces();
- while (ConsumeChar(';')) {
- SkipWhitespaces();
-
- absl::optional<std::string> name = ReadKey();
- if (!name)
- return absl::nullopt;
-
- Item value;
- if (ConsumeChar('=')) {
- auto item = ReadBareItem();
- if (!item)
- return absl::nullopt;
- value = std::move(*item);
- }
- if (!parameters.emplace(*name, value).second) {
- DVLOG(1) << "ReadParameterisedIdentifier: duplicated parameter: "
- << *name;
- return absl::nullopt;
- }
- SkipWhitespaces();
- }
- return ParameterisedIdentifier(std::move(*primary_identifier),
- std::move(parameters));
- }
-
- // Parses an Item or Inner List ([RFC8941] 4.2.1.1).
- absl::optional<ParameterizedMember> ReadItemOrInnerList() {
- DCHECK_EQ(version_, kFinal);
- std::vector<Item> member;
- bool member_is_inner_list = (!input_.empty() && input_.front() == '(');
- if (member_is_inner_list) {
- return ReadInnerList();
- } else {
- auto item = ReadItem();
- if (!item)
- return absl::nullopt;
- return ParameterizedMember(std::move(item->item),
- std::move(item->params));
- }
- }
-
- // Parses Parameters ([RFC8941] 4.2.3.2)
- absl::optional<Parameters> ReadParameters() {
- Parameters parameters;
- base::flat_set<std::string> keys;
-
- while (ConsumeChar(';')) {
- SkipWhitespaces();
-
- absl::optional<std::string> name = ReadKey();
- if (!name)
- return absl::nullopt;
- bool is_duplicate_key = !keys.insert(*name).second;
-
- Item value{true};
- if (ConsumeChar('=')) {
- auto item = ReadBareItem();
- if (!item)
- return absl::nullopt;
- value = std::move(*item);
- }
- if (is_duplicate_key) {
- for (auto& param : parameters) {
- if (param.first == name) {
- param.second = std::move(value);
- break;
- }
- }
- } else {
- parameters.emplace_back(std::move(*name), std::move(value));
- }
- }
- return parameters;
- }
-
- // Parses an Inner List ([RFC8941] 4.2.1.2).
- absl::optional<ParameterizedMember> ReadInnerList() {
- DCHECK_EQ(version_, kFinal);
- if (!ConsumeChar('('))
- return absl::nullopt;
- std::vector<ParameterizedItem> inner_list;
- while (true) {
- SkipWhitespaces();
- if (ConsumeChar(')')) {
- absl::optional<Parameters> parameters;
- parameters = ReadParameters();
- if (!parameters)
- return absl::nullopt;
- return ParameterizedMember(std::move(inner_list), true,
- std::move(*parameters));
- }
- auto item = ReadItem();
- if (!item)
- return absl::nullopt;
- inner_list.push_back(std::move(*item));
- if (input_.empty() || (input_.front() != ' ' && input_.front() != ')'))
- return absl::nullopt;
- }
- NOTREACHED();
- return absl::nullopt;
- }
-
- // Parses a Key ([SH09] 4.2.2, [RFC8941] 4.2.3.3).
- absl::optional<std::string> ReadKey() {
- if (version_ == kDraft09) {
- if (input_.empty() || !base::IsAsciiLower(input_.front())) {
- LogParseError("ReadKey", "lcalpha");
- return absl::nullopt;
- }
- } else {
- if (input_.empty() ||
- (!base::IsAsciiLower(input_.front()) && input_.front() != '*')) {
- LogParseError("ReadKey", "lcalpha | *");
- return absl::nullopt;
- }
- }
- const char* allowed_chars =
- (version_ == kDraft09 ? kKeyChars09 : kKeyChars);
- size_t len = input_.find_first_not_of(allowed_chars);
- if (len == base::StringPiece::npos)
- len = input_.size();
- std::string key(input_.substr(0, len));
- input_.remove_prefix(len);
- return key;
- }
-
- // Parses a Token ([SH09] 4.2.10, [RFC8941] 4.2.6).
- absl::optional<Item> ReadToken() {
- if (input_.empty() ||
- !(base::IsAsciiAlpha(input_.front()) || input_.front() == '*')) {
- LogParseError("ReadToken", "ALPHA");
- return absl::nullopt;
- }
- size_t len = input_.find_first_not_of(version_ == kDraft09 ? kTokenChars09
- : kTokenChars);
- if (len == base::StringPiece::npos)
- len = input_.size();
- std::string token(input_.substr(0, len));
- input_.remove_prefix(len);
- return Item(std::move(token), Item::kTokenType);
- }
-
- // Parses a Number ([SH09] 4.2.8, [RFC8941] 4.2.4).
- absl::optional<Item> ReadNumber() {
- bool is_negative = ConsumeChar('-');
- bool is_decimal = false;
- size_t decimal_position = 0;
- size_t i = 0;
- for (; i < input_.size(); ++i) {
- if (i > 0 && input_[i] == '.' && !is_decimal) {
- is_decimal = true;
- decimal_position = i;
- continue;
- }
- if (!base::IsAsciiDigit(input_[i]))
- break;
- }
- if (i == 0) {
- LogParseError("ReadNumber", "DIGIT");
- return absl::nullopt;
- }
- if (!is_decimal) {
- // [RFC8941] restricts the range of integers further.
- if (version_ == kFinal && i > 15) {
- LogParseError("ReadNumber", "integer too long");
- return absl::nullopt;
- }
- } else {
- if (version_ != kFinal && i > 16) {
- LogParseError("ReadNumber", "float too long");
- return absl::nullopt;
- }
- if (version_ == kFinal && decimal_position > 12) {
- LogParseError("ReadNumber", "decimal too long");
- return absl::nullopt;
- }
- if (i - decimal_position > (version_ == kFinal ? 4 : 7)) {
- LogParseError("ReadNumber", "too many digits after decimal");
- return absl::nullopt;
- }
- if (i == decimal_position) {
- LogParseError("ReadNumber", "no digits after decimal");
- return absl::nullopt;
- }
- }
- std::string output_number_string(input_.substr(0, i));
- input_.remove_prefix(i);
-
- if (is_decimal) {
- // Convert to a 64-bit double, and return if the conversion is
- // successful.
- double f;
- if (!base::StringToDouble(output_number_string, &f))
- return absl::nullopt;
- return Item(is_negative ? -f : f);
- } else {
- // Convert to a 64-bit signed integer, and return if the conversion is
- // successful.
- int64_t n;
- if (!base::StringToInt64(output_number_string, &n))
- return absl::nullopt;
- DCHECK(version_ != kFinal || (n <= kMaxInteger && n >= kMinInteger));
- return Item(is_negative ? -n : n);
- }
- }
-
- // Parses a String ([SH09] 4.2.9, [RFC8941] 4.2.5).
- absl::optional<Item> ReadString() {
- std::string s;
- if (!ConsumeChar('"')) {
- LogParseError("ReadString", "'\"'");
- return absl::nullopt;
- }
- while (!ConsumeChar('"')) {
- size_t i = 0;
- for (; i < input_.size(); ++i) {
- if (!base::IsAsciiPrintable(input_[i])) {
- DVLOG(1) << "ReadString: non printable-ASCII character";
- return absl::nullopt;
- }
- if (input_[i] == '"' || input_[i] == '\\')
- break;
- }
- if (i == input_.size()) {
- DVLOG(1) << "ReadString: missing closing '\"'";
- return absl::nullopt;
- }
- s.append(std::string(input_.substr(0, i)));
- input_.remove_prefix(i);
- if (ConsumeChar('\\')) {
- if (input_.empty()) {
- DVLOG(1) << "ReadString: backslash at string end";
- return absl::nullopt;
- }
- if (input_[0] != '"' && input_[0] != '\\') {
- DVLOG(1) << "ReadString: invalid escape";
- return absl::nullopt;
- }
- s.push_back(input_.front());
- input_.remove_prefix(1);
- }
- }
- return s;
- }
-
- // Parses a Byte Sequence ([SH09] 4.2.11, [RFC8941] 4.2.7).
- absl::optional<Item> ReadByteSequence() {
- char delimiter = (version_ == kDraft09 ? '*' : ':');
- if (!ConsumeChar(delimiter)) {
- LogParseError("ReadByteSequence", "delimiter");
- return absl::nullopt;
- }
- size_t len = input_.find(delimiter);
- if (len == base::StringPiece::npos) {
- DVLOG(1) << "ReadByteSequence: missing closing delimiter";
- return absl::nullopt;
- }
- std::string base64(input_.substr(0, len));
- // Append the necessary padding characters.
- base64.resize((base64.size() + 3) / 4 * 4, '=');
-
- std::string binary;
- if (!base::Base64Decode(base64, &binary)) {
- DVLOG(1) << "ReadByteSequence: failed to decode base64: " << base64;
- return absl::nullopt;
- }
- input_.remove_prefix(len);
- ConsumeChar(delimiter);
- return Item(std::move(binary), Item::kByteSequenceType);
- }
-
- // Parses a Boolean ([RFC8941] 4.2.8).
- // Note that this only parses ?0 and ?1 forms from SH version 10+, not the
- // previous ?F and ?T, which were not needed by any consumers of SH version 9.
- absl::optional<Item> ReadBoolean() {
- if (!ConsumeChar('?')) {
- LogParseError("ReadBoolean", "'?'");
- return absl::nullopt;
- }
- if (ConsumeChar('1')) {
- return Item(true);
- }
- if (ConsumeChar('0')) {
- return Item(false);
- }
- return absl::nullopt;
- }
-
- // There are several points in the specs where the handling of whitespace
- // differs between Draft 9 and the final RFC. In those cases, Draft 9 allows
- // any OWS character, while the RFC allows only a U+0020 SPACE.
- void SkipWhitespaces() {
- if (version_ == kDraft09) {
- input_ =
- base::TrimString(input_, base::StringPiece(kOWS), base::TRIM_LEADING);
- } else {
- input_ =
- base::TrimString(input_, base::StringPiece(kSP), base::TRIM_LEADING);
- }
- }
-
- void SkipOWS() {
- input_ =
- base::TrimString(input_, base::StringPiece(kOWS), base::TRIM_LEADING);
- }
-
- bool ConsumeChar(char expected) {
- if (!input_.empty() && input_.front() == expected) {
- input_.remove_prefix(1);
- return true;
- }
- return false;
- }
-
- void LogParseError(const char* func, const char* expected) {
- DVLOG(1) << func << ": " << expected << " expected, got "
- << (input_.empty() ? "EOS"
- : "'" + std::string(input_.substr(0, 1)) + "'");
- }
-
- base::StringPiece input_;
- DraftVersion version_;
-};
-
-// Serializer for (a subset of) Structured Field Values for HTTP defined in
-// [RFC8941]. Note that this serializer does not attempt to support [SH09].
-class StructuredHeaderSerializer {
- public:
- StructuredHeaderSerializer() = default;
- ~StructuredHeaderSerializer() = default;
- StructuredHeaderSerializer(const StructuredHeaderSerializer&) = delete;
- StructuredHeaderSerializer& operator=(const StructuredHeaderSerializer&) =
- delete;
-
- std::string Output() { return output_.str(); }
-
- // Serializes a List ([RFC8941] 4.1.1).
- bool WriteList(const List& value) {
- bool first = true;
- for (const auto& member : value) {
- if (!first)
- output_ << ", ";
- if (!WriteParameterizedMember(member))
- return false;
- first = false;
- }
- return true;
- }
-
- // Serializes an Item ([RFC8941] 4.1.3).
- bool WriteItem(const ParameterizedItem& value) {
- if (!WriteBareItem(value.item))
- return false;
- return WriteParameters(value.params);
- }
-
- // Serializes an Item ([RFC8941] 4.1.3).
- bool WriteBareItem(const Item& value) {
- if (value.is_string()) {
- // Serializes a String ([RFC8941] 4.1.6).
- output_ << "\"";
- for (const char& c : value.GetString()) {
- if (!base::IsAsciiPrintable(c))
- return false;
- if (c == '\\' || c == '\"')
- output_ << "\\";
- output_ << c;
- }
- output_ << "\"";
- return true;
- }
- if (value.is_token()) {
- // Serializes a Token ([RFC8941] 4.1.7).
- if (!value.GetString().size() ||
- !(base::IsAsciiAlpha(value.GetString().front()) ||
- value.GetString().front() == '*'))
- return false;
- if (value.GetString().find_first_not_of(kTokenChars) != std::string::npos)
- return false;
- output_ << value.GetString();
- return true;
- }
- if (value.is_byte_sequence()) {
- // Serializes a Byte Sequence ([RFC8941] 4.1.8).
- output_ << ":";
- output_ << base::Base64Encode(
- base::as_bytes(base::make_span(value.GetString())));
- output_ << ":";
- return true;
- }
- if (value.is_integer()) {
- // Serializes an Integer ([RFC8941] 4.1.4).
- if (value.GetInteger() > kMaxInteger || value.GetInteger() < kMinInteger)
- return false;
- output_ << value.GetInteger();
- return true;
- }
- if (value.is_decimal()) {
- // Serializes a Decimal ([RFC8941] 4.1.5).
- double decimal_value = value.GetDecimal();
- if (!std::isfinite(decimal_value) ||
- fabs(decimal_value) >= kTooLargeDecimal)
- return false;
-
- // Handle sign separately to simplify the rest of the formatting.
- if (decimal_value < 0)
- output_ << "-";
- // Unconditionally take absolute value to ensure that -0 is serialized as
- // "0.0", with no negative sign, as required by spec. (4.1.5, step 2).
- decimal_value = fabs(decimal_value);
- double remainder = fmod(decimal_value, 0.002);
- if (remainder == 0.0005) {
- // Value ended in exactly 0.0005, 0.0025, 0.0045, etc. Round down.
- decimal_value -= 0.0005;
- } else if (remainder == 0.0015) {
- // Value ended in exactly 0.0015, 0.0035, 0,0055, etc. Round up.
- decimal_value += 0.0005;
- } else {
- // Standard rounding will work in all other cases.
- decimal_value = round(decimal_value * 1000.0) / 1000.0;
- }
-
- // Use standard library functions to write the decimal, and then truncate
- // if necessary to conform to spec.
-
- // Maximum is 12 integer digits, one decimal point, three fractional
- // digits, and a null terminator.
- char buffer[17];
- base::snprintf(buffer, std::size(buffer), "%#.3f", decimal_value);
-
- // Strip any trailing 0s after the decimal point, but leave at least one
- // digit after it in all cases. (So 1.230 becomes 1.23, but 1.000 becomes
- // 1.0.)
- base::StringPiece formatted_number(buffer);
- auto truncate_index = formatted_number.find_last_not_of('0');
- if (formatted_number[truncate_index] == '.')
- truncate_index++;
- output_ << formatted_number.substr(0, truncate_index + 1);
- return true;
- }
- if (value.is_boolean()) {
- // Serializes a Boolean ([RFC8941] 4.1.9).
- output_ << (value.GetBoolean() ? "?1" : "?0");
- return true;
- }
- return false;
- }
-
- // Serializes a Dictionary ([RFC8941] 4.1.2).
- bool WriteDictionary(const Dictionary& value) {
- bool first = true;
- for (const auto& dict : value) {
- const auto& dict_member = dict.second;
- if (!first)
- output_ << ", ";
- if (!WriteKey(dict.first))
- return false;
- first = false;
- if (!dict_member.member_is_inner_list &&
- dict_member.member.front().item.is_boolean() &&
- dict_member.member.front().item.GetBoolean()) {
- if (!WriteParameters(dict_member.params))
- return false;
- } else {
- output_ << "=";
- if (!WriteParameterizedMember(dict_member))
- return false;
- }
- }
- return true;
- }
-
- private:
- bool WriteParameterizedMember(const ParameterizedMember& value) {
- // Serializes a parameterized member ([RFC8941] 4.1.1).
- if (value.member_is_inner_list) {
- if (!WriteInnerList(value.member))
- return false;
- } else {
- DCHECK_EQ(value.member.size(), 1UL);
- if (!WriteItem(value.member[0]))
- return false;
- }
- return WriteParameters(value.params);
- }
-
- bool WriteInnerList(const std::vector<ParameterizedItem>& value) {
- // Serializes an inner list ([RFC8941] 4.1.1.1).
- output_ << "(";
- bool first = true;
- for (const ParameterizedItem& member : value) {
- if (!first)
- output_ << " ";
- if (!WriteItem(member))
- return false;
- first = false;
- }
- output_ << ")";
- return true;
- }
-
- bool WriteParameters(const Parameters& value) {
- // Serializes a parameter list ([RFC8941] 4.1.1.2).
- for (const auto& param_name_and_value : value) {
- const std::string& param_name = param_name_and_value.first;
- const Item& param_value = param_name_and_value.second;
- output_ << ";";
- if (!WriteKey(param_name))
- return false;
- if (!param_value.is_null()) {
- if (param_value.is_boolean() && param_value.GetBoolean())
- continue;
- output_ << "=";
- if (!WriteBareItem(param_value))
- return false;
- }
- }
- return true;
- }
-
- bool WriteKey(const std::string& value) {
- // Serializes a Key ([RFC8941] 4.1.1.3).
- if (!value.size())
- return false;
- if (value.find_first_not_of(kKeyChars) != std::string::npos)
- return false;
- if (!base::IsAsciiLower(value[0]) && value[0] != '*')
- return false;
- output_ << value;
- return true;
- }
-
- std::ostringstream output_;
-};
-
-} // namespace
-
-Item::Item() {}
-Item::Item(const std::string& value, Item::ItemType type)
- : type_(type), string_value_(value) {}
-Item::Item(std::string&& value, Item::ItemType type)
- : type_(type), string_value_(std::move(value)) {
- DCHECK(type_ == kStringType || type_ == kTokenType ||
- type_ == kByteSequenceType);
-}
-Item::Item(const char* value, Item::ItemType type)
- : Item(std::string(value), type) {}
-Item::Item(int64_t value) : type_(kIntegerType), integer_value_(value) {}
-Item::Item(double value) : type_(kDecimalType), decimal_value_(value) {}
-Item::Item(bool value) : type_(kBooleanType), boolean_value_(value) {}
-
-bool operator==(const Item& lhs, const Item& rhs) {
- if (lhs.type_ != rhs.type_)
- return false;
- switch (lhs.type_) {
- case Item::kNullType:
- return true;
- case Item::kStringType:
- case Item::kTokenType:
- case Item::kByteSequenceType:
- return lhs.string_value_ == rhs.string_value_;
- case Item::kIntegerType:
- return lhs.integer_value_ == rhs.integer_value_;
- case Item::kDecimalType:
- return lhs.decimal_value_ == rhs.decimal_value_;
- case Item::kBooleanType:
- return lhs.boolean_value_ == rhs.boolean_value_;
- }
- NOTREACHED();
- return false;
-}
-
-ParameterizedItem::ParameterizedItem(const ParameterizedItem&) = default;
-ParameterizedItem& ParameterizedItem::operator=(const ParameterizedItem&) =
- default;
-ParameterizedItem::ParameterizedItem(Item id, const Parameters& ps)
- : item(std::move(id)), params(ps) {}
-ParameterizedItem::~ParameterizedItem() = default;
-
-ParameterizedMember::ParameterizedMember() = default;
-ParameterizedMember::ParameterizedMember(const ParameterizedMember&) = default;
-ParameterizedMember& ParameterizedMember::operator=(
- const ParameterizedMember&) = default;
-ParameterizedMember::ParameterizedMember(std::vector<ParameterizedItem> id,
- bool member_is_inner_list,
- const Parameters& ps)
- : member(std::move(id)),
- member_is_inner_list(member_is_inner_list),
- params(ps) {}
-ParameterizedMember::ParameterizedMember(std::vector<ParameterizedItem> id,
- const Parameters& ps)
- : member(std::move(id)), member_is_inner_list(true), params(ps) {}
-ParameterizedMember::ParameterizedMember(Item id, const Parameters& ps)
- : member({{std::move(id), {}}}), member_is_inner_list(false), params(ps) {}
-ParameterizedMember::~ParameterizedMember() = default;
-
-ParameterisedIdentifier::ParameterisedIdentifier(
- const ParameterisedIdentifier&) = default;
-ParameterisedIdentifier& ParameterisedIdentifier::operator=(
- const ParameterisedIdentifier&) = default;
-ParameterisedIdentifier::ParameterisedIdentifier(Item id, const Parameters& ps)
- : identifier(std::move(id)), params(ps) {}
-ParameterisedIdentifier::~ParameterisedIdentifier() = default;
-
-Dictionary::Dictionary() = default;
-Dictionary::Dictionary(const Dictionary&) = default;
-Dictionary::Dictionary(std::vector<DictionaryMember> members)
- : members_(std::move(members)) {}
-Dictionary::~Dictionary() = default;
-std::vector<DictionaryMember>::iterator Dictionary::begin() {
- return members_.begin();
-}
-std::vector<DictionaryMember>::const_iterator Dictionary::begin() const {
- return members_.begin();
-}
-std::vector<DictionaryMember>::iterator Dictionary::end() {
- return members_.end();
-}
-std::vector<DictionaryMember>::const_iterator Dictionary::end() const {
- return members_.end();
-}
-ParameterizedMember& Dictionary::operator[](std::size_t idx) {
- return members_[idx].second;
-}
-const ParameterizedMember& Dictionary::operator[](std::size_t idx) const {
- return members_[idx].second;
-}
-ParameterizedMember& Dictionary::at(std::size_t idx) {
- return (*this)[idx];
-}
-const ParameterizedMember& Dictionary::at(std::size_t idx) const {
- return (*this)[idx];
-}
-ParameterizedMember& Dictionary::operator[](base::StringPiece key) {
- auto it =
- std::find_if(members_.begin(), members_.end(),
- [key](const auto& member) { return member.first == key; });
- if (it != members_.end())
- return it->second;
- return (*(members_.insert(members_.end(), make_pair(std::string(key),
- ParameterizedMember()))))
- .second;
-}
-ParameterizedMember& Dictionary::at(base::StringPiece key) {
- auto it =
- std::find_if(members_.begin(), members_.end(),
- [key](const auto& member) { return member.first == key; });
- DCHECK(it != members_.end()) << "Provided key not found in dictionary";
- return it->second;
-}
-const ParameterizedMember& Dictionary::at(base::StringPiece key) const {
- auto it =
- std::find_if(members_.begin(), members_.end(),
- [key](const auto& member) { return member.first == key; });
- DCHECK(it != members_.end()) << "Provided key not found in dictionary";
- return it->second;
-}
-bool Dictionary::empty() const {
- return members_.empty();
-}
-std::size_t Dictionary::size() const {
- return members_.size();
-}
-bool Dictionary::contains(base::StringPiece key) const {
- for (auto& member : members_) {
- if (member.first == key)
- return true;
- }
- return false;
-}
-
-absl::optional<ParameterizedItem> ParseItem(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
- absl::optional<ParameterizedItem> item = parser.ReadItem();
- if (item && parser.FinishParsing())
- return item;
- return absl::nullopt;
-}
-
-absl::optional<Item> ParseBareItem(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
- absl::optional<Item> item = parser.ReadBareItem();
- if (item && parser.FinishParsing())
- return item;
- return absl::nullopt;
-}
-
-absl::optional<ParameterisedList> ParseParameterisedList(
- base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft09);
- absl::optional<ParameterisedList> param_list = parser.ReadParameterisedList();
- if (param_list && parser.FinishParsing())
- return param_list;
- return absl::nullopt;
-}
-
-absl::optional<ListOfLists> ParseListOfLists(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft09);
- absl::optional<ListOfLists> list_of_lists = parser.ReadListOfLists();
- if (list_of_lists && parser.FinishParsing())
- return list_of_lists;
- return absl::nullopt;
-}
-
-absl::optional<List> ParseList(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
- absl::optional<List> list = parser.ReadList();
- if (list && parser.FinishParsing())
- return list;
- return absl::nullopt;
-}
-
-absl::optional<Dictionary> ParseDictionary(const base::StringPiece& str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
- absl::optional<Dictionary> dictionary = parser.ReadDictionary();
- if (dictionary && parser.FinishParsing())
- return dictionary;
- return absl::nullopt;
-}
-
-absl::optional<std::string> SerializeItem(const Item& value) {
- StructuredHeaderSerializer s;
- if (s.WriteItem(ParameterizedItem(value, {})))
- return s.Output();
- return absl::nullopt;
-}
-
-absl::optional<std::string> SerializeItem(const ParameterizedItem& value) {
- StructuredHeaderSerializer s;
- if (s.WriteItem(value))
- return s.Output();
- return absl::nullopt;
-}
-
-absl::optional<std::string> SerializeList(const List& value) {
- StructuredHeaderSerializer s;
- if (s.WriteList(value))
- return s.Output();
- return absl::nullopt;
-}
-
-absl::optional<std::string> SerializeDictionary(const Dictionary& value) {
- StructuredHeaderSerializer s;
- if (s.WriteDictionary(value))
- return s.Output();
- return absl::nullopt;
-}
-
-} // namespace structured_headers
-} // namespace net
diff --git a/chromium/net/http/structured_headers.h b/chromium/net/http/structured_headers.h
index 262724694a9..97a1da5cf01 100644
--- a/chromium/net/http/structured_headers.h
+++ b/chromium/net/http/structured_headers.h
@@ -5,296 +5,69 @@
#ifndef NET_HTTP_STRUCTURED_HEADERS_H_
#define NET_HTTP_STRUCTURED_HEADERS_H_
-#include <algorithm>
-#include <map>
#include <string>
-#include <tuple>
-#include <vector>
+#include "base/strings/abseil_string_conversions.h"
#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
+#include "net/third_party/quiche/src/quiche/common/structured_headers.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
namespace structured_headers {
-// This file implements parsing of HTTP structured headers, as defined in
-// RFC8941 (https://www.rfc-editor.org/rfc/rfc8941.html). For compatibility with
-// the shipped implementation of Web Packaging, this file also supports a
-// previous revision of the standard, referred to here as "Draft 9".
-// (https://datatracker.ietf.org/doc/draft-ietf-httpbis-header-structure/09/)
-//
-// The major difference between the two revisions is in the various list
-// formats: Draft 9 describes "parameterised lists" and "lists-of-lists", while
-// the final RFC uses a single "list" syntax, whose members may be inner lists.
-// There should be no ambiguity, however, as the code which calls this parser
-// should be expecting only a single type for a given header.
-//
-// References within the code are tagged with either [SH09] or [RFC8941],
-// depending on which revision they refer to.
-//
-// Currently supported data types are:
-// Item:
-// integer: 123
-// string: "abc"
-// token: abc
-// byte sequence: *YWJj*
-// Parameterised list: abc_123;a=1;b=2; cdef_456, ghi;q="9";r="w"
-// List-of-lists: "foo";"bar", "baz", "bat"; "one"
-// List: "foo", "bar", "It was the best of times."
-// ("foo" "bar"), ("baz"), ("bat" "one"), ()
-// abc;a=1;b=2; cde_456, (ghi jkl);q="9";r=w
-// Dictionary: a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid=?0
-//
-// Functions are provided to parse each of these, which are intended to be
-// called with the complete value of an HTTP header (that is, any
-// sub-structure will be handled internally by the parser; the exported
-// functions are not intended to be called on partial header strings.) Input
-// values should be ASCII byte strings (non-ASCII characters should not be
-// present in Structured Header values, and will cause the entire header to fail
-// to parse.)
-
-class NET_EXPORT Item {
- public:
- enum ItemType {
- kNullType,
- kIntegerType,
- kDecimalType,
- kStringType,
- kTokenType,
- kByteSequenceType,
- kBooleanType
- };
- Item();
- explicit Item(int64_t value);
- explicit Item(double value);
- explicit Item(bool value);
-
- // Constructors for string-like items: Strings, Tokens and Byte Sequences.
- Item(const char* value, Item::ItemType type = kStringType);
- // Item(StringPiece value, Item::ItemType type = kStringType);
- Item(const std::string& value, Item::ItemType type = kStringType);
- Item(std::string&& value, Item::ItemType type = kStringType);
-
- NET_EXPORT friend bool operator==(const Item& lhs, const Item& rhs);
- inline friend bool operator!=(const Item& lhs, const Item& rhs) {
- return !(lhs == rhs);
- }
-
- bool is_null() const { return type_ == kNullType; }
- bool is_integer() const { return type_ == kIntegerType; }
- bool is_decimal() const { return type_ == kDecimalType; }
- bool is_string() const { return type_ == kStringType; }
- bool is_token() const { return type_ == kTokenType; }
- bool is_byte_sequence() const { return type_ == kByteSequenceType; }
- bool is_boolean() const { return type_ == kBooleanType; }
-
- int64_t GetInteger() const {
- DCHECK_EQ(type_, kIntegerType);
- return integer_value_;
- }
- double GetDecimal() const {
- DCHECK_EQ(type_, kDecimalType);
- return decimal_value_;
- }
- bool GetBoolean() const {
- DCHECK_EQ(type_, kBooleanType);
- return boolean_value_;
- }
- // TODO(iclelland): Split up accessors for String, Token and Byte Sequence.
- const std::string& GetString() const {
- DCHECK(type_ == kStringType || type_ == kTokenType ||
- type_ == kByteSequenceType);
- return string_value_;
- }
-
- ItemType Type() const { return type_; }
-
- private:
- ItemType type_ = kNullType;
- // TODO(iclelland): Make this class more memory-efficient, replacing the
- // values here with a union or std::variant (when available).
- int64_t integer_value_ = 0;
- std::string string_value_;
- double decimal_value_;
- bool boolean_value_;
-};
-
-// Holds a ParameterizedIdentifier (draft 9 only). The contained Item must be a
-// Token, and there may be any number of parameters. Parameter ordering is not
-// significant.
-struct NET_EXPORT ParameterisedIdentifier {
- using Parameters = std::map<std::string, Item>;
-
- Item identifier;
- Parameters params;
-
- ParameterisedIdentifier(const ParameterisedIdentifier&);
- ParameterisedIdentifier& operator=(const ParameterisedIdentifier&);
- ParameterisedIdentifier(Item, const Parameters&);
- ~ParameterisedIdentifier();
-};
-
-inline bool operator==(const ParameterisedIdentifier& lhs,
- const ParameterisedIdentifier& rhs) {
- return std::tie(lhs.identifier, lhs.params) ==
- std::tie(rhs.identifier, rhs.params);
+using Item = quiche::structured_headers::Item;
+using ParameterisedIdentifier =
+ quiche::structured_headers::ParameterisedIdentifier;
+using ParameterizedItem = quiche::structured_headers::ParameterizedItem;
+using ParameterizedMember = quiche::structured_headers::ParameterizedMember;
+using DictionaryMember = quiche::structured_headers::DictionaryMember;
+using Dictionary = quiche::structured_headers::Dictionary;
+using ParameterisedList = quiche::structured_headers::ParameterisedList;
+using ListOfLists = quiche::structured_headers::ListOfLists;
+using List = quiche::structured_headers::List;
+using Parameters = quiche::structured_headers::Parameters;
+
+inline absl::optional<ParameterizedItem> ParseItem(base::StringPiece str) {
+ return quiche::structured_headers::ParseItem(
+ base::StringPieceToStringView(str));
}
-
-using Parameters = std::vector<std::pair<std::string, Item>>;
-
-struct NET_EXPORT ParameterizedItem {
- Item item;
- Parameters params;
-
- ParameterizedItem(const ParameterizedItem&);
- ParameterizedItem& operator=(const ParameterizedItem&);
- ParameterizedItem(Item, const Parameters&);
- ~ParameterizedItem();
-};
-
-inline bool operator==(const ParameterizedItem& lhs,
- const ParameterizedItem& rhs) {
- return std::tie(lhs.item, lhs.params) == std::tie(rhs.item, rhs.params);
+inline absl::optional<Item> ParseBareItem(base::StringPiece str) {
+ return quiche::structured_headers::ParseBareItem(
+ base::StringPieceToStringView(str));
}
-
-inline bool operator!=(const ParameterizedItem& lhs,
- const ParameterizedItem& rhs) {
- return !(lhs == rhs);
+inline absl::optional<ParameterisedList> ParseParameterisedList(
+ base::StringPiece str) {
+ return quiche::structured_headers::ParseParameterisedList(
+ base::StringPieceToStringView(str));
}
-
-// Holds a ParameterizedMember, which may be either an single Item, or an Inner
-// List of ParameterizedItems, along with any number of parameters. Parameter
-// ordering is significant.
-struct NET_EXPORT ParameterizedMember {
- std::vector<ParameterizedItem> member;
- // If false, then |member| should only hold one Item.
- bool member_is_inner_list = false;
-
- Parameters params;
-
- ParameterizedMember();
- ParameterizedMember(const ParameterizedMember&);
- ParameterizedMember& operator=(const ParameterizedMember&);
- ParameterizedMember(std::vector<ParameterizedItem>,
- bool member_is_inner_list,
- const Parameters&);
- // Shorthand constructor for a member which is an inner list.
- ParameterizedMember(std::vector<ParameterizedItem>, const Parameters&);
- // Shorthand constructor for a member which is a single Item.
- ParameterizedMember(Item, const Parameters&);
- ~ParameterizedMember();
-};
-
-inline bool operator==(const ParameterizedMember& lhs,
- const ParameterizedMember& rhs) {
- return std::tie(lhs.member, lhs.member_is_inner_list, lhs.params) ==
- std::tie(rhs.member, rhs.member_is_inner_list, rhs.params);
+inline absl::optional<ListOfLists> ParseListOfLists(base::StringPiece str) {
+ return quiche::structured_headers::ParseListOfLists(
+ base::StringPieceToStringView(str));
}
-
-using DictionaryMember = std::pair<std::string, ParameterizedMember>;
-
-// Structured Headers Draft 15 Dictionary.
-class NET_EXPORT Dictionary {
- public:
- using iterator = std::vector<DictionaryMember>::iterator;
- using const_iterator = std::vector<DictionaryMember>::const_iterator;
-
- Dictionary();
- Dictionary(const Dictionary&);
- explicit Dictionary(std::vector<DictionaryMember> members);
- ~Dictionary();
- Dictionary& operator=(const Dictionary&) = default;
- iterator begin();
- const_iterator begin() const;
- iterator end();
- const_iterator end() const;
-
- // operator[](size_t) and at(size_t) will both abort the program in case of
- // out of bounds access.
- ParameterizedMember& operator[](std::size_t idx);
- const ParameterizedMember& operator[](std::size_t idx) const;
- ParameterizedMember& at(std::size_t idx);
- const ParameterizedMember& at(std::size_t idx) const;
-
- // Consistent with std::map, if |key| does not exist in the Dictionary, then
- // operator[](base::StringPiece) will create an entry for it, but at() will
- // abort the entire program.
- ParameterizedMember& operator[](base::StringPiece key);
- ParameterizedMember& at(base::StringPiece key);
- const ParameterizedMember& at(base::StringPiece key) const;
-
- bool empty() const;
- std::size_t size() const;
- bool contains(base::StringPiece key) const;
- friend bool operator==(const Dictionary& lhs, const Dictionary& rhs);
- friend bool operator!=(const Dictionary& lhs, const Dictionary& rhs);
-
- private:
- // Uses a vector to hold pairs of key and dictionary member. This makes
- // look up by index and serialization much easier.
- std::vector<DictionaryMember> members_;
-};
-
-inline bool operator==(const Dictionary& lhs, const Dictionary& rhs) {
- return lhs.members_ == rhs.members_;
+inline absl::optional<List> ParseList(base::StringPiece str) {
+ return quiche::structured_headers::ParseList(
+ base::StringPieceToStringView(str));
}
-
-inline bool operator!=(const Dictionary& lhs, const Dictionary& rhs) {
- return !(lhs == rhs);
+inline absl::optional<Dictionary> ParseDictionary(
+ const base::StringPiece& str) {
+ return quiche::structured_headers::ParseDictionary(
+ base::StringPieceToStringView(str));
}
-// Structured Headers Draft 09 Parameterised List.
-using ParameterisedList = std::vector<ParameterisedIdentifier>;
-// Structured Headers Draft 09 List of Lists.
-using ListOfLists = std::vector<std::vector<Item>>;
-// Structured Headers Draft 15 List.
-using List = std::vector<ParameterizedMember>;
-
-// Returns the result of parsing the header value as an Item, if it can be
-// parsed as one, or nullopt if it cannot. Note that this uses the Draft 15
-// parsing rules, and so applies tighter range limits to integers.
-NET_EXPORT absl::optional<ParameterizedItem> ParseItem(base::StringPiece str);
-
-// Returns the result of parsing the header value as an Item with no parameters,
-// or nullopt if it cannot. Note that this uses the Draft 15 parsing rules, and
-// so applies tighter range limits to integers.
-NET_EXPORT absl::optional<Item> ParseBareItem(base::StringPiece str);
-
-// Returns the result of parsing the header value as a Parameterised List, if it
-// can be parsed as one, or nullopt if it cannot. Note that parameter keys will
-// be returned as strings, which are guaranteed to be ASCII-encoded. List items,
-// as well as parameter values, will be returned as Items. This method uses the
-// Draft 09 parsing rules for Items, so integers have the 64-bit int range.
-// Structured-Headers Draft 09 only.
-NET_EXPORT absl::optional<ParameterisedList> ParseParameterisedList(
- base::StringPiece str);
-
-// Returns the result of parsing the header value as a List of Lists, if it can
-// be parsed as one, or nullopt if it cannot. Inner list items will be returned
-// as Items. This method uses the Draft 09 parsing rules for Items, so integers
-// have the 64-bit int range.
-// Structured-Headers Draft 09 only.
-NET_EXPORT absl::optional<ListOfLists> ParseListOfLists(base::StringPiece str);
-
-// Returns the result of parsing the header value as a general List, if it can
-// be parsed as one, or nullopt if it cannot.
-// Structured-Headers Draft 15 only.
-NET_EXPORT absl::optional<List> ParseList(base::StringPiece str);
-
-// Returns the result of parsing the header value as a general Dictionary, if it
-// can be parsed as one, or nullopt if it cannot. Structured-Headers Draft 15
-// only.
-NET_EXPORT absl::optional<Dictionary> ParseDictionary(
- const base::StringPiece& str);
-
-// Serialization is implemented for Structured-Headers Draft 15 only.
-NET_EXPORT absl::optional<std::string> SerializeItem(const Item& value);
-NET_EXPORT absl::optional<std::string> SerializeItem(
- const ParameterizedItem& value);
-NET_EXPORT absl::optional<std::string> SerializeList(const List& value);
-NET_EXPORT absl::optional<std::string> SerializeDictionary(
- const Dictionary& value);
+inline absl::optional<std::string> SerializeItem(const Item& value) {
+ return quiche::structured_headers::SerializeItem(value);
+}
+inline absl::optional<std::string> SerializeItem(
+ const ParameterizedItem& value) {
+ return quiche::structured_headers::SerializeItem(value);
+}
+inline absl::optional<std::string> SerializeList(const List& value) {
+ return quiche::structured_headers::SerializeList(value);
+}
+inline absl::optional<std::string> SerializeDictionary(
+ const Dictionary& value) {
+ return quiche::structured_headers::SerializeDictionary(value);
+}
} // namespace structured_headers
} // namespace net
diff --git a/chromium/net/http/structured_headers_generated_unittest.cc b/chromium/net/http/structured_headers_generated_unittest.cc
deleted file mode 100644
index 82d1e01205f..00000000000
--- a/chromium/net/http/structured_headers_generated_unittest.cc
+++ /dev/null
@@ -1,3178 +0,0 @@
-// Copyright 2020 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 "net/http/structured_headers.h"
-
-#include <math.h>
-
-#include <limits>
-#include <string>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-// This file contains tests cases for the Structured Header parser and
-// serializer, taken from the public test case repository at
-// https://github.com/httpwg/structured-field-tests. All of the tests are named,
-// so a given test case can be found in the JSON files in that repository by
-// searching for the test name. This file is generated, with the test cases
-// being automatically translated from the JSON source to C++ unit tests. Please
-// do not modify, as the contents will be overwritten when this is re-generated.
-
-// Generated on 2022-03-05 from structured-field-tests.git @
-// 4d33b9c2f4e0a7d7d1d733ccf48783aaead8ca4d
-
-namespace net {
-namespace structured_headers {
-namespace {
-
-// Helpers to make test cases clearer
-
-Item Integer(int64_t value) {
- return Item(value);
-}
-
-std::pair<std::string, Item> BooleanParam(std::string key, bool value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> DoubleParam(std::string key, double value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> Param(std::string key, int64_t value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> Param(std::string key, std::string value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> TokenParam(std::string key, std::string value) {
- return std::make_pair(key, Item(value, Item::kTokenType));
-}
-
-const struct ParameterizedItemTestCase {
- const char* name;
- const char* raw;
- size_t raw_len;
- const absl::optional<ParameterizedItem>
- expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} parameterized_item_test_cases[] = {
-
- // binary.json
- {"basic binary",
- ":aGVsbG8=:",
- 10,
- {{Item("hello", Item::kByteSequenceType), {}}}},
- {"empty binary", "::", 2, {{Item("", Item::kByteSequenceType), {}}}},
- {"bad paddding",
- ":aGVsbG8:",
- 9,
- {{Item("hello", Item::kByteSequenceType), {}}},
- ":aGVsbG8=:"},
- {"bad end delimiter", ":aGVsbG8=", 9, absl::nullopt},
- {"extra whitespace", ":aGVsb G8=:", 11, absl::nullopt},
- {"extra chars", ":aGVsbG!8=:", 11, absl::nullopt},
- {"suffix chars", ":aGVsbG8=!:", 11, absl::nullopt},
- {"non-zero pad bits",
- ":iZ==:",
- 6,
- {{Item("\211", Item::kByteSequenceType), {}}},
- ":iQ==:"},
- {"non-ASCII binary",
- ":/+Ah:",
- 6,
- {{Item("\377\340!", Item::kByteSequenceType), {}}}},
- {"base64url binary", ":_-Ah:", 6, absl::nullopt},
- // boolean.json
- {"basic true boolean", "?1", 2, {{Item(true), {}}}},
- {"basic false boolean", "?0", 2, {{Item(false), {}}}},
- {"unknown boolean", "?Q", 2, absl::nullopt},
- {"whitespace boolean", "? 1", 3, absl::nullopt},
- {"negative zero boolean", "?-0", 3, absl::nullopt},
- {"T boolean", "?T", 2, absl::nullopt},
- {"F boolean", "?F", 2, absl::nullopt},
- {"t boolean", "?t", 2, absl::nullopt},
- {"f boolean", "?f", 2, absl::nullopt},
- {"spelled-out True boolean", "?True", 5, absl::nullopt},
- {"spelled-out False boolean", "?False", 6, absl::nullopt},
- // examples.json
- {"Foo-Example",
- "2; foourl=\"https://foo.example.com/\"",
- 36,
- {{Integer(2), {Param("foourl", "https://foo.example.com/")}}},
- "2;foourl=\"https://foo.example.com/\""},
- {"Example-IntHeader",
- "1; a; b=?0",
- 10,
- {{Integer(1), {BooleanParam("a", true), BooleanParam("b", false)}}},
- "1;a;b=?0"},
- {"Example-IntItemHeader", "5", 1, {{Integer(5), {}}}},
- {"Example-IntItemHeader (params)",
- "5; foo=bar",
- 10,
- {{Integer(5), {TokenParam("foo", "bar")}}},
- "5;foo=bar"},
- {"Example-IntegerHeader", "42", 2, {{Integer(42), {}}}},
- {"Example-FloatHeader", "4.5", 3, {{Item(4.500000), {}}}},
- {"Example-StringHeader",
- "\"hello world\"",
- 13,
- {{Item("hello world"), {}}}},
- {"Example-BinaryHdr",
- ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:",
- 46,
- {{Item("pretend this is binary content.", Item::kByteSequenceType), {}}}},
- {"Example-BoolHdr", "?1", 2, {{Item(true), {}}}},
- // item.json
- {"empty item", "", 0, absl::nullopt},
- {"leading space", " \t 1", 4, absl::nullopt},
- {"trailing space", "1 \t ", 4, absl::nullopt},
- {"leading and trailing space", " 1 ", 5, {{Integer(1), {}}}, "1"},
- {"leading and trailing whitespace", " 1 ", 8, {{Integer(1), {}}}, "1"},
- // number-generated.json
- {"1 digits of zero", "0", 1, {{Integer(0), {}}}, "0"},
- {"1 digit small integer", "1", 1, {{Integer(1), {}}}},
- {"1 digit large integer", "9", 1, {{Integer(9), {}}}},
- {"2 digits of zero", "00", 2, {{Integer(0), {}}}, "0"},
- {"2 digit small integer", "11", 2, {{Integer(11), {}}}},
- {"2 digit large integer", "99", 2, {{Integer(99), {}}}},
- {"3 digits of zero", "000", 3, {{Integer(0), {}}}, "0"},
- {"3 digit small integer", "111", 3, {{Integer(111), {}}}},
- {"3 digit large integer", "999", 3, {{Integer(999), {}}}},
- {"4 digits of zero", "0000", 4, {{Integer(0), {}}}, "0"},
- {"4 digit small integer", "1111", 4, {{Integer(1111), {}}}},
- {"4 digit large integer", "9999", 4, {{Integer(9999), {}}}},
- {"5 digits of zero", "00000", 5, {{Integer(0), {}}}, "0"},
- {"5 digit small integer", "11111", 5, {{Integer(11111), {}}}},
- {"5 digit large integer", "99999", 5, {{Integer(99999), {}}}},
- {"6 digits of zero", "000000", 6, {{Integer(0), {}}}, "0"},
- {"6 digit small integer", "111111", 6, {{Integer(111111), {}}}},
- {"6 digit large integer", "999999", 6, {{Integer(999999), {}}}},
- {"7 digits of zero", "0000000", 7, {{Integer(0), {}}}, "0"},
- {"7 digit small integer", "1111111", 7, {{Integer(1111111), {}}}},
- {"7 digit large integer", "9999999", 7, {{Integer(9999999), {}}}},
- {"8 digits of zero", "00000000", 8, {{Integer(0), {}}}, "0"},
- {"8 digit small integer", "11111111", 8, {{Integer(11111111), {}}}},
- {"8 digit large integer", "99999999", 8, {{Integer(99999999), {}}}},
- {"9 digits of zero", "000000000", 9, {{Integer(0), {}}}, "0"},
- {"9 digit small integer", "111111111", 9, {{Integer(111111111), {}}}},
- {"9 digit large integer", "999999999", 9, {{Integer(999999999), {}}}},
- {"10 digits of zero", "0000000000", 10, {{Integer(0), {}}}, "0"},
- {"10 digit small integer", "1111111111", 10, {{Integer(1111111111), {}}}},
- {"10 digit large integer", "9999999999", 10, {{Integer(9999999999), {}}}},
- {"11 digits of zero", "00000000000", 11, {{Integer(0), {}}}, "0"},
- {"11 digit small integer", "11111111111", 11, {{Integer(11111111111), {}}}},
- {"11 digit large integer", "99999999999", 11, {{Integer(99999999999), {}}}},
- {"12 digits of zero", "000000000000", 12, {{Integer(0), {}}}, "0"},
- {"12 digit small integer",
- "111111111111",
- 12,
- {{Integer(111111111111), {}}}},
- {"12 digit large integer",
- "999999999999",
- 12,
- {{Integer(999999999999), {}}}},
- {"13 digits of zero", "0000000000000", 13, {{Integer(0), {}}}, "0"},
- {"13 digit small integer",
- "1111111111111",
- 13,
- {{Integer(1111111111111), {}}}},
- {"13 digit large integer",
- "9999999999999",
- 13,
- {{Integer(9999999999999), {}}}},
- {"14 digits of zero", "00000000000000", 14, {{Integer(0), {}}}, "0"},
- {"14 digit small integer",
- "11111111111111",
- 14,
- {{Integer(11111111111111), {}}}},
- {"14 digit large integer",
- "99999999999999",
- 14,
- {{Integer(99999999999999), {}}}},
- {"15 digits of zero", "000000000000000", 15, {{Integer(0), {}}}, "0"},
- {"15 digit small integer",
- "111111111111111",
- 15,
- {{Integer(111111111111111), {}}}},
- {"15 digit large integer",
- "999999999999999",
- 15,
- {{Integer(999999999999999), {}}}},
- {"2 digit 0, 1 fractional small decimal",
- "0.1",
- 3,
- {{Item(0.100000), {}}},
- "0.1"},
- {"2 digit, 1 fractional 0 decimal",
- "1.0",
- 3,
- {{Item(1.000000), {}}},
- "1.0"},
- {"2 digit, 1 fractional small decimal", "1.1", 3, {{Item(1.100000), {}}}},
- {"2 digit, 1 fractional large decimal", "9.9", 3, {{Item(9.900000), {}}}},
- {"3 digit 0, 2 fractional small decimal",
- "0.11",
- 4,
- {{Item(0.110000), {}}},
- "0.11"},
- {"3 digit, 2 fractional 0 decimal",
- "1.00",
- 4,
- {{Item(1.000000), {}}},
- "1.0"},
- {"3 digit, 2 fractional small decimal", "1.11", 4, {{Item(1.110000), {}}}},
- {"3 digit, 2 fractional large decimal", "9.99", 4, {{Item(9.990000), {}}}},
- {"4 digit 0, 3 fractional small decimal",
- "0.111",
- 5,
- {{Item(0.111000), {}}},
- "0.111"},
- {"4 digit, 3 fractional 0 decimal",
- "1.000",
- 5,
- {{Item(1.000000), {}}},
- "1.0"},
- {"4 digit, 3 fractional small decimal", "1.111", 5, {{Item(1.111000), {}}}},
- {"4 digit, 3 fractional large decimal", "9.999", 5, {{Item(9.999000), {}}}},
- {"3 digit 0, 1 fractional small decimal",
- "00.1",
- 4,
- {{Item(0.100000), {}}},
- "0.1"},
- {"3 digit, 1 fractional 0 decimal",
- "11.0",
- 4,
- {{Item(11.000000), {}}},
- "11.0"},
- {"3 digit, 1 fractional small decimal", "11.1", 4, {{Item(11.100000), {}}}},
- {"3 digit, 1 fractional large decimal", "99.9", 4, {{Item(99.900000), {}}}},
- {"4 digit 0, 2 fractional small decimal",
- "00.11",
- 5,
- {{Item(0.110000), {}}},
- "0.11"},
- {"4 digit, 2 fractional 0 decimal",
- "11.00",
- 5,
- {{Item(11.000000), {}}},
- "11.0"},
- {"4 digit, 2 fractional small decimal",
- "11.11",
- 5,
- {{Item(11.110000), {}}}},
- {"4 digit, 2 fractional large decimal",
- "99.99",
- 5,
- {{Item(99.990000), {}}}},
- {"5 digit 0, 3 fractional small decimal",
- "00.111",
- 6,
- {{Item(0.111000), {}}},
- "0.111"},
- {"5 digit, 3 fractional 0 decimal",
- "11.000",
- 6,
- {{Item(11.000000), {}}},
- "11.0"},
- {"5 digit, 3 fractional small decimal",
- "11.111",
- 6,
- {{Item(11.111000), {}}}},
- {"5 digit, 3 fractional large decimal",
- "99.999",
- 6,
- {{Item(99.999000), {}}}},
- {"4 digit 0, 1 fractional small decimal",
- "000.1",
- 5,
- {{Item(0.100000), {}}},
- "0.1"},
- {"4 digit, 1 fractional 0 decimal",
- "111.0",
- 5,
- {{Item(111.000000), {}}},
- "111.0"},
- {"4 digit, 1 fractional small decimal",
- "111.1",
- 5,
- {{Item(111.100000), {}}}},
- {"4 digit, 1 fractional large decimal",
- "999.9",
- 5,
- {{Item(999.900000), {}}}},
- {"5 digit 0, 2 fractional small decimal",
- "000.11",
- 6,
- {{Item(0.110000), {}}},
- "0.11"},
- {"5 digit, 2 fractional 0 decimal",
- "111.00",
- 6,
- {{Item(111.000000), {}}},
- "111.0"},
- {"5 digit, 2 fractional small decimal",
- "111.11",
- 6,
- {{Item(111.110000), {}}}},
- {"5 digit, 2 fractional large decimal",
- "999.99",
- 6,
- {{Item(999.990000), {}}}},
- {"6 digit 0, 3 fractional small decimal",
- "000.111",
- 7,
- {{Item(0.111000), {}}},
- "0.111"},
- {"6 digit, 3 fractional 0 decimal",
- "111.000",
- 7,
- {{Item(111.000000), {}}},
- "111.0"},
- {"6 digit, 3 fractional small decimal",
- "111.111",
- 7,
- {{Item(111.111000), {}}}},
- {"6 digit, 3 fractional large decimal",
- "999.999",
- 7,
- {{Item(999.999000), {}}}},
- {"5 digit 0, 1 fractional small decimal",
- "0000.1",
- 6,
- {{Item(0.100000), {}}},
- "0.1"},
- {"5 digit, 1 fractional 0 decimal",
- "1111.0",
- 6,
- {{Item(1111.000000), {}}},
- "1111.0"},
- {"5 digit, 1 fractional small decimal",
- "1111.1",
- 6,
- {{Item(1111.100000), {}}}},
- {"5 digit, 1 fractional large decimal",
- "9999.9",
- 6,
- {{Item(9999.900000), {}}}},
- {"6 digit 0, 2 fractional small decimal",
- "0000.11",
- 7,
- {{Item(0.110000), {}}},
- "0.11"},
- {"6 digit, 2 fractional 0 decimal",
- "1111.00",
- 7,
- {{Item(1111.000000), {}}},
- "1111.0"},
- {"6 digit, 2 fractional small decimal",
- "1111.11",
- 7,
- {{Item(1111.110000), {}}}},
- {"6 digit, 2 fractional large decimal",
- "9999.99",
- 7,
- {{Item(9999.990000), {}}}},
- {"7 digit 0, 3 fractional small decimal",
- "0000.111",
- 8,
- {{Item(0.111000), {}}},
- "0.111"},
- {"7 digit, 3 fractional 0 decimal",
- "1111.000",
- 8,
- {{Item(1111.000000), {}}},
- "1111.0"},
- {"7 digit, 3 fractional small decimal",
- "1111.111",
- 8,
- {{Item(1111.111000), {}}}},
- {"7 digit, 3 fractional large decimal",
- "9999.999",
- 8,
- {{Item(9999.999000), {}}}},
- {"6 digit 0, 1 fractional small decimal",
- "00000.1",
- 7,
- {{Item(0.100000), {}}},
- "0.1"},
- {"6 digit, 1 fractional 0 decimal",
- "11111.0",
- 7,
- {{Item(11111.000000), {}}},
- "11111.0"},
- {"6 digit, 1 fractional small decimal",
- "11111.1",
- 7,
- {{Item(11111.100000), {}}}},
- {"6 digit, 1 fractional large decimal",
- "99999.9",
- 7,
- {{Item(99999.900000), {}}}},
- {"7 digit 0, 2 fractional small decimal",
- "00000.11",
- 8,
- {{Item(0.110000), {}}},
- "0.11"},
- {"7 digit, 2 fractional 0 decimal",
- "11111.00",
- 8,
- {{Item(11111.000000), {}}},
- "11111.0"},
- {"7 digit, 2 fractional small decimal",
- "11111.11",
- 8,
- {{Item(11111.110000), {}}}},
- {"7 digit, 2 fractional large decimal",
- "99999.99",
- 8,
- {{Item(99999.990000), {}}}},
- {"8 digit 0, 3 fractional small decimal",
- "00000.111",
- 9,
- {{Item(0.111000), {}}},
- "0.111"},
- {"8 digit, 3 fractional 0 decimal",
- "11111.000",
- 9,
- {{Item(11111.000000), {}}},
- "11111.0"},
- {"8 digit, 3 fractional small decimal",
- "11111.111",
- 9,
- {{Item(11111.111000), {}}}},
- {"8 digit, 3 fractional large decimal",
- "99999.999",
- 9,
- {{Item(99999.999000), {}}}},
- {"7 digit 0, 1 fractional small decimal",
- "000000.1",
- 8,
- {{Item(0.100000), {}}},
- "0.1"},
- {"7 digit, 1 fractional 0 decimal",
- "111111.0",
- 8,
- {{Item(111111.000000), {}}},
- "111111.0"},
- {"7 digit, 1 fractional small decimal",
- "111111.1",
- 8,
- {{Item(111111.100000), {}}}},
- {"7 digit, 1 fractional large decimal",
- "999999.9",
- 8,
- {{Item(999999.900000), {}}}},
- {"8 digit 0, 2 fractional small decimal",
- "000000.11",
- 9,
- {{Item(0.110000), {}}},
- "0.11"},
- {"8 digit, 2 fractional 0 decimal",
- "111111.00",
- 9,
- {{Item(111111.000000), {}}},
- "111111.0"},
- {"8 digit, 2 fractional small decimal",
- "111111.11",
- 9,
- {{Item(111111.110000), {}}}},
- {"8 digit, 2 fractional large decimal",
- "999999.99",
- 9,
- {{Item(999999.990000), {}}}},
- {"9 digit 0, 3 fractional small decimal",
- "000000.111",
- 10,
- {{Item(0.111000), {}}},
- "0.111"},
- {"9 digit, 3 fractional 0 decimal",
- "111111.000",
- 10,
- {{Item(111111.000000), {}}},
- "111111.0"},
- {"9 digit, 3 fractional small decimal",
- "111111.111",
- 10,
- {{Item(111111.111000), {}}}},
- {"9 digit, 3 fractional large decimal",
- "999999.999",
- 10,
- {{Item(999999.999000), {}}}},
- {"8 digit 0, 1 fractional small decimal",
- "0000000.1",
- 9,
- {{Item(0.100000), {}}},
- "0.1"},
- {"8 digit, 1 fractional 0 decimal",
- "1111111.0",
- 9,
- {{Item(1111111.000000), {}}},
- "1111111.0"},
- {"8 digit, 1 fractional small decimal",
- "1111111.1",
- 9,
- {{Item(1111111.100000), {}}}},
- {"8 digit, 1 fractional large decimal",
- "9999999.9",
- 9,
- {{Item(9999999.900000), {}}}},
- {"9 digit 0, 2 fractional small decimal",
- "0000000.11",
- 10,
- {{Item(0.110000), {}}},
- "0.11"},
- {"9 digit, 2 fractional 0 decimal",
- "1111111.00",
- 10,
- {{Item(1111111.000000), {}}},
- "1111111.0"},
- {"9 digit, 2 fractional small decimal",
- "1111111.11",
- 10,
- {{Item(1111111.110000), {}}}},
- {"9 digit, 2 fractional large decimal",
- "9999999.99",
- 10,
- {{Item(9999999.990000), {}}}},
- {"10 digit 0, 3 fractional small decimal",
- "0000000.111",
- 11,
- {{Item(0.111000), {}}},
- "0.111"},
- {"10 digit, 3 fractional 0 decimal",
- "1111111.000",
- 11,
- {{Item(1111111.000000), {}}},
- "1111111.0"},
- {"10 digit, 3 fractional small decimal",
- "1111111.111",
- 11,
- {{Item(1111111.111000), {}}}},
- {"10 digit, 3 fractional large decimal",
- "9999999.999",
- 11,
- {{Item(9999999.999000), {}}}},
- {"9 digit 0, 1 fractional small decimal",
- "00000000.1",
- 10,
- {{Item(0.100000), {}}},
- "0.1"},
- {"9 digit, 1 fractional 0 decimal",
- "11111111.0",
- 10,
- {{Item(11111111.000000), {}}},
- "11111111.0"},
- {"9 digit, 1 fractional small decimal",
- "11111111.1",
- 10,
- {{Item(11111111.100000), {}}}},
- {"9 digit, 1 fractional large decimal",
- "99999999.9",
- 10,
- {{Item(99999999.900000), {}}}},
- {"10 digit 0, 2 fractional small decimal",
- "00000000.11",
- 11,
- {{Item(0.110000), {}}},
- "0.11"},
- {"10 digit, 2 fractional 0 decimal",
- "11111111.00",
- 11,
- {{Item(11111111.000000), {}}},
- "11111111.0"},
- {"10 digit, 2 fractional small decimal",
- "11111111.11",
- 11,
- {{Item(11111111.110000), {}}}},
- {"10 digit, 2 fractional large decimal",
- "99999999.99",
- 11,
- {{Item(99999999.990000), {}}}},
- {"11 digit 0, 3 fractional small decimal",
- "00000000.111",
- 12,
- {{Item(0.111000), {}}},
- "0.111"},
- {"11 digit, 3 fractional 0 decimal",
- "11111111.000",
- 12,
- {{Item(11111111.000000), {}}},
- "11111111.0"},
- {"11 digit, 3 fractional small decimal",
- "11111111.111",
- 12,
- {{Item(11111111.111000), {}}}},
- {"11 digit, 3 fractional large decimal",
- "99999999.999",
- 12,
- {{Item(99999999.999000), {}}}},
- {"10 digit 0, 1 fractional small decimal",
- "000000000.1",
- 11,
- {{Item(0.100000), {}}},
- "0.1"},
- {"10 digit, 1 fractional 0 decimal",
- "111111111.0",
- 11,
- {{Item(111111111.000000), {}}},
- "111111111.0"},
- {"10 digit, 1 fractional small decimal",
- "111111111.1",
- 11,
- {{Item(111111111.100000), {}}}},
- {"10 digit, 1 fractional large decimal",
- "999999999.9",
- 11,
- {{Item(999999999.900000), {}}}},
- {"11 digit 0, 2 fractional small decimal",
- "000000000.11",
- 12,
- {{Item(0.110000), {}}},
- "0.11"},
- {"11 digit, 2 fractional 0 decimal",
- "111111111.00",
- 12,
- {{Item(111111111.000000), {}}},
- "111111111.0"},
- {"11 digit, 2 fractional small decimal",
- "111111111.11",
- 12,
- {{Item(111111111.110000), {}}}},
- {"11 digit, 2 fractional large decimal",
- "999999999.99",
- 12,
- {{Item(999999999.990000), {}}}},
- {"12 digit 0, 3 fractional small decimal",
- "000000000.111",
- 13,
- {{Item(0.111000), {}}},
- "0.111"},
- {"12 digit, 3 fractional 0 decimal",
- "111111111.000",
- 13,
- {{Item(111111111.000000), {}}},
- "111111111.0"},
- {"12 digit, 3 fractional small decimal",
- "111111111.111",
- 13,
- {{Item(111111111.111000), {}}}},
- {"12 digit, 3 fractional large decimal",
- "999999999.999",
- 13,
- {{Item(999999999.999000), {}}}},
- {"11 digit 0, 1 fractional small decimal",
- "0000000000.1",
- 12,
- {{Item(0.100000), {}}},
- "0.1"},
- {"11 digit, 1 fractional 0 decimal",
- "1111111111.0",
- 12,
- {{Item(1111111111.000000), {}}},
- "1111111111.0"},
- {"11 digit, 1 fractional small decimal",
- "1111111111.1",
- 12,
- {{Item(1111111111.100000), {}}}},
- {"11 digit, 1 fractional large decimal",
- "9999999999.9",
- 12,
- {{Item(9999999999.900000), {}}}},
- {"12 digit 0, 2 fractional small decimal",
- "0000000000.11",
- 13,
- {{Item(0.110000), {}}},
- "0.11"},
- {"12 digit, 2 fractional 0 decimal",
- "1111111111.00",
- 13,
- {{Item(1111111111.000000), {}}},
- "1111111111.0"},
- {"12 digit, 2 fractional small decimal",
- "1111111111.11",
- 13,
- {{Item(1111111111.110000), {}}}},
- {"12 digit, 2 fractional large decimal",
- "9999999999.99",
- 13,
- {{Item(9999999999.990000), {}}}},
- {"13 digit 0, 3 fractional small decimal",
- "0000000000.111",
- 14,
- {{Item(0.111000), {}}},
- "0.111"},
- {"13 digit, 3 fractional 0 decimal",
- "1111111111.000",
- 14,
- {{Item(1111111111.000000), {}}},
- "1111111111.0"},
- {"13 digit, 3 fractional small decimal",
- "1111111111.111",
- 14,
- {{Item(1111111111.111000), {}}}},
- {"13 digit, 3 fractional large decimal",
- "9999999999.999",
- 14,
- {{Item(9999999999.999001), {}}}},
- {"12 digit 0, 1 fractional small decimal",
- "00000000000.1",
- 13,
- {{Item(0.100000), {}}},
- "0.1"},
- {"12 digit, 1 fractional 0 decimal",
- "11111111111.0",
- 13,
- {{Item(11111111111.000000), {}}},
- "11111111111.0"},
- {"12 digit, 1 fractional small decimal",
- "11111111111.1",
- 13,
- {{Item(11111111111.100000), {}}}},
- {"12 digit, 1 fractional large decimal",
- "99999999999.9",
- 13,
- {{Item(99999999999.899994), {}}}},
- {"13 digit 0, 2 fractional small decimal",
- "00000000000.11",
- 14,
- {{Item(0.110000), {}}},
- "0.11"},
- {"13 digit, 2 fractional 0 decimal",
- "11111111111.00",
- 14,
- {{Item(11111111111.000000), {}}},
- "11111111111.0"},
- {"13 digit, 2 fractional small decimal",
- "11111111111.11",
- 14,
- {{Item(11111111111.110001), {}}}},
- {"13 digit, 2 fractional large decimal",
- "99999999999.99",
- 14,
- {{Item(99999999999.990005), {}}}},
- {"14 digit 0, 3 fractional small decimal",
- "00000000000.111",
- 15,
- {{Item(0.111000), {}}},
- "0.111"},
- {"14 digit, 3 fractional 0 decimal",
- "11111111111.000",
- 15,
- {{Item(11111111111.000000), {}}},
- "11111111111.0"},
- {"14 digit, 3 fractional small decimal",
- "11111111111.111",
- 15,
- {{Item(11111111111.111000), {}}}},
- {"14 digit, 3 fractional large decimal",
- "99999999999.999",
- 15,
- {{Item(99999999999.998993), {}}}},
- {"13 digit 0, 1 fractional small decimal",
- "000000000000.1",
- 14,
- {{Item(0.100000), {}}},
- "0.1"},
- {"13 digit, 1 fractional 0 decimal",
- "111111111111.0",
- 14,
- {{Item(111111111111.000000), {}}},
- "111111111111.0"},
- {"13 digit, 1 fractional small decimal",
- "111111111111.1",
- 14,
- {{Item(111111111111.100006), {}}}},
- {"13 digit, 1 fractional large decimal",
- "999999999999.9",
- 14,
- {{Item(999999999999.900024), {}}}},
- {"14 digit 0, 2 fractional small decimal",
- "000000000000.11",
- 15,
- {{Item(0.110000), {}}},
- "0.11"},
- {"14 digit, 2 fractional 0 decimal",
- "111111111111.00",
- 15,
- {{Item(111111111111.000000), {}}},
- "111111111111.0"},
- {"14 digit, 2 fractional small decimal",
- "111111111111.11",
- 15,
- {{Item(111111111111.110001), {}}}},
- {"14 digit, 2 fractional large decimal",
- "999999999999.99",
- 15,
- {{Item(999999999999.989990), {}}}},
- {"15 digit 0, 3 fractional small decimal",
- "000000000000.111",
- 16,
- {{Item(0.111000), {}}},
- "0.111"},
- {"15 digit, 3 fractional 0 decimal",
- "111111111111.000",
- 16,
- {{Item(111111111111.000000), {}}},
- "111111111111.0"},
- {"15 digit, 3 fractional small decimal",
- "111111111111.111",
- 16,
- {{Item(111111111111.110992), {}}}},
- {"15 digit, 3 fractional large decimal",
- "999999999999.999",
- 16,
- {{Item(999999999999.999023), {}}}},
- {"too many digit 0 decimal", "000000000000000.0", 17, absl::nullopt},
- {"too many fractional digits 0 decimal", "000000000000.0000", 17,
- absl::nullopt},
- {"too many digit 9 decimal", "999999999999999.9", 17, absl::nullopt},
- {"too many fractional digits 9 decimal", "999999999999.9999", 17,
- absl::nullopt},
- // number.json
- {"basic integer", "42", 2, {{Integer(42), {}}}},
- {"zero integer", "0", 1, {{Integer(0), {}}}},
- {"negative zero", "-0", 2, {{Integer(0), {}}}, "0"},
- {"double negative zero", "--0", 3, absl::nullopt},
- {"negative integer", "-42", 3, {{Integer(-42), {}}}},
- {"leading 0 integer", "042", 3, {{Integer(42), {}}}, "42"},
- {"leading 0 negative integer", "-042", 4, {{Integer(-42), {}}}, "-42"},
- {"leading 0 zero", "00", 2, {{Integer(0), {}}}, "0"},
- {"comma", "2,3", 3, absl::nullopt},
- {"negative non-DIGIT first character", "-a23", 4, absl::nullopt},
- {"sign out of place", "4-2", 3, absl::nullopt},
- {"whitespace after sign", "- 42", 4, absl::nullopt},
- {"long integer", "123456789012345", 15, {{Integer(123456789012345), {}}}},
- {"long negative integer",
- "-123456789012345",
- 16,
- {{Integer(-123456789012345), {}}}},
- {"too long integer", "1234567890123456", 16, absl::nullopt},
- {"negative too long integer", "-1234567890123456", 17, absl::nullopt},
- {"simple decimal", "1.23", 4, {{Item(1.230000), {}}}},
- {"negative decimal", "-1.23", 5, {{Item(-1.230000), {}}}},
- {"decimal, whitespace after decimal", "1. 23", 5, absl::nullopt},
- {"decimal, whitespace before decimal", "1 .23", 5, absl::nullopt},
- {"negative decimal, whitespace after sign", "- 1.23", 6, absl::nullopt},
- {"tricky precision decimal",
- "123456789012.1",
- 14,
- {{Item(123456789012.100006), {}}}},
- {"double decimal decimal", "1.5.4", 5, absl::nullopt},
- {"adjacent double decimal decimal", "1..4", 4, absl::nullopt},
- {"decimal with three fractional digits",
- "1.123",
- 5,
- {{Item(1.123000), {}}}},
- {"negative decimal with three fractional digits",
- "-1.123",
- 6,
- {{Item(-1.123000), {}}}},
- {"decimal with four fractional digits", "1.1234", 6, absl::nullopt},
- {"negative decimal with four fractional digits", "-1.1234", 7,
- absl::nullopt},
- {"decimal with thirteen integer digits", "1234567890123.0", 15,
- absl::nullopt},
- {"negative decimal with thirteen integer digits", "-1234567890123.0", 16,
- absl::nullopt},
- // string-generated.json
- {"0x00 in string", "\" \000 \"", 5, absl::nullopt},
- {"0x01 in string", "\" \001 \"", 5, absl::nullopt},
- {"0x02 in string", "\" \002 \"", 5, absl::nullopt},
- {"0x03 in string", "\" \003 \"", 5, absl::nullopt},
- {"0x04 in string", "\" \004 \"", 5, absl::nullopt},
- {"0x05 in string", "\" \005 \"", 5, absl::nullopt},
- {"0x06 in string", "\" \006 \"", 5, absl::nullopt},
- {"0x07 in string", "\" \a \"", 5, absl::nullopt},
- {"0x08 in string", "\" \b \"", 5, absl::nullopt},
- {"0x09 in string", "\" \t \"", 5, absl::nullopt},
- {"0x0a in string", "\" \n \"", 5, absl::nullopt},
- {"0x0b in string", "\" \v \"", 5, absl::nullopt},
- {"0x0c in string", "\" \f \"", 5, absl::nullopt},
- {"0x0d in string", "\" \r \"", 5, absl::nullopt},
- {"0x0e in string", "\" \016 \"", 5, absl::nullopt},
- {"0x0f in string", "\" \017 \"", 5, absl::nullopt},
- {"0x10 in string", "\" \020 \"", 5, absl::nullopt},
- {"0x11 in string", "\" \021 \"", 5, absl::nullopt},
- {"0x12 in string", "\" \022 \"", 5, absl::nullopt},
- {"0x13 in string", "\" \023 \"", 5, absl::nullopt},
- {"0x14 in string", "\" \024 \"", 5, absl::nullopt},
- {"0x15 in string", "\" \025 \"", 5, absl::nullopt},
- {"0x16 in string", "\" \026 \"", 5, absl::nullopt},
- {"0x17 in string", "\" \027 \"", 5, absl::nullopt},
- {"0x18 in string", "\" \030 \"", 5, absl::nullopt},
- {"0x19 in string", "\" \031 \"", 5, absl::nullopt},
- {"0x1a in string", "\" \032 \"", 5, absl::nullopt},
- {"0x1b in string", "\" \033 \"", 5, absl::nullopt},
- {"0x1c in string", "\" \034 \"", 5, absl::nullopt},
- {"0x1d in string", "\" \035 \"", 5, absl::nullopt},
- {"0x1e in string", "\" \036 \"", 5, absl::nullopt},
- {"0x1f in string", "\" \037 \"", 5, absl::nullopt},
- {"0x20 in string", "\" \"", 5, {{Item(" "), {}}}},
- {"0x21 in string", "\" ! \"", 5, {{Item(" ! "), {}}}},
- {"0x22 in string", "\" \" \"", 5, absl::nullopt},
- {"0x23 in string", "\" # \"", 5, {{Item(" # "), {}}}},
- {"0x24 in string", "\" $ \"", 5, {{Item(" $ "), {}}}},
- {"0x25 in string", "\" % \"", 5, {{Item(" % "), {}}}},
- {"0x26 in string", "\" & \"", 5, {{Item(" & "), {}}}},
- {"0x27 in string", "\" ' \"", 5, {{Item(" ' "), {}}}},
- {"0x28 in string", "\" ( \"", 5, {{Item(" ( "), {}}}},
- {"0x29 in string", "\" ) \"", 5, {{Item(" ) "), {}}}},
- {"0x2a in string", "\" * \"", 5, {{Item(" * "), {}}}},
- {"0x2b in string", "\" + \"", 5, {{Item(" + "), {}}}},
- {"0x2c in string", "\" , \"", 5, {{Item(" , "), {}}}},
- {"0x2d in string", "\" - \"", 5, {{Item(" - "), {}}}},
- {"0x2e in string", "\" . \"", 5, {{Item(" . "), {}}}},
- {"0x2f in string", "\" / \"", 5, {{Item(" / "), {}}}},
- {"0x30 in string", "\" 0 \"", 5, {{Item(" 0 "), {}}}},
- {"0x31 in string", "\" 1 \"", 5, {{Item(" 1 "), {}}}},
- {"0x32 in string", "\" 2 \"", 5, {{Item(" 2 "), {}}}},
- {"0x33 in string", "\" 3 \"", 5, {{Item(" 3 "), {}}}},
- {"0x34 in string", "\" 4 \"", 5, {{Item(" 4 "), {}}}},
- {"0x35 in string", "\" 5 \"", 5, {{Item(" 5 "), {}}}},
- {"0x36 in string", "\" 6 \"", 5, {{Item(" 6 "), {}}}},
- {"0x37 in string", "\" 7 \"", 5, {{Item(" 7 "), {}}}},
- {"0x38 in string", "\" 8 \"", 5, {{Item(" 8 "), {}}}},
- {"0x39 in string", "\" 9 \"", 5, {{Item(" 9 "), {}}}},
- {"0x3a in string", "\" : \"", 5, {{Item(" : "), {}}}},
- {"0x3b in string", "\" ; \"", 5, {{Item(" ; "), {}}}},
- {"0x3c in string", "\" < \"", 5, {{Item(" < "), {}}}},
- {"0x3d in string", "\" = \"", 5, {{Item(" = "), {}}}},
- {"0x3e in string", "\" > \"", 5, {{Item(" > "), {}}}},
- {"0x3f in string", "\" ? \"", 5, {{Item(" ? "), {}}}},
- {"0x40 in string", "\" @ \"", 5, {{Item(" @ "), {}}}},
- {"0x41 in string", "\" A \"", 5, {{Item(" A "), {}}}},
- {"0x42 in string", "\" B \"", 5, {{Item(" B "), {}}}},
- {"0x43 in string", "\" C \"", 5, {{Item(" C "), {}}}},
- {"0x44 in string", "\" D \"", 5, {{Item(" D "), {}}}},
- {"0x45 in string", "\" E \"", 5, {{Item(" E "), {}}}},
- {"0x46 in string", "\" F \"", 5, {{Item(" F "), {}}}},
- {"0x47 in string", "\" G \"", 5, {{Item(" G "), {}}}},
- {"0x48 in string", "\" H \"", 5, {{Item(" H "), {}}}},
- {"0x49 in string", "\" I \"", 5, {{Item(" I "), {}}}},
- {"0x4a in string", "\" J \"", 5, {{Item(" J "), {}}}},
- {"0x4b in string", "\" K \"", 5, {{Item(" K "), {}}}},
- {"0x4c in string", "\" L \"", 5, {{Item(" L "), {}}}},
- {"0x4d in string", "\" M \"", 5, {{Item(" M "), {}}}},
- {"0x4e in string", "\" N \"", 5, {{Item(" N "), {}}}},
- {"0x4f in string", "\" O \"", 5, {{Item(" O "), {}}}},
- {"0x50 in string", "\" P \"", 5, {{Item(" P "), {}}}},
- {"0x51 in string", "\" Q \"", 5, {{Item(" Q "), {}}}},
- {"0x52 in string", "\" R \"", 5, {{Item(" R "), {}}}},
- {"0x53 in string", "\" S \"", 5, {{Item(" S "), {}}}},
- {"0x54 in string", "\" T \"", 5, {{Item(" T "), {}}}},
- {"0x55 in string", "\" U \"", 5, {{Item(" U "), {}}}},
- {"0x56 in string", "\" V \"", 5, {{Item(" V "), {}}}},
- {"0x57 in string", "\" W \"", 5, {{Item(" W "), {}}}},
- {"0x58 in string", "\" X \"", 5, {{Item(" X "), {}}}},
- {"0x59 in string", "\" Y \"", 5, {{Item(" Y "), {}}}},
- {"0x5a in string", "\" Z \"", 5, {{Item(" Z "), {}}}},
- {"0x5b in string", "\" [ \"", 5, {{Item(" [ "), {}}}},
- {"0x5c in string", "\" \\ \"", 5, absl::nullopt},
- {"0x5d in string", "\" ] \"", 5, {{Item(" ] "), {}}}},
- {"0x5e in string", "\" ^ \"", 5, {{Item(" ^ "), {}}}},
- {"0x5f in string", "\" _ \"", 5, {{Item(" _ "), {}}}},
- {"0x60 in string", "\" ` \"", 5, {{Item(" ` "), {}}}},
- {"0x61 in string", "\" a \"", 5, {{Item(" a "), {}}}},
- {"0x62 in string", "\" b \"", 5, {{Item(" b "), {}}}},
- {"0x63 in string", "\" c \"", 5, {{Item(" c "), {}}}},
- {"0x64 in string", "\" d \"", 5, {{Item(" d "), {}}}},
- {"0x65 in string", "\" e \"", 5, {{Item(" e "), {}}}},
- {"0x66 in string", "\" f \"", 5, {{Item(" f "), {}}}},
- {"0x67 in string", "\" g \"", 5, {{Item(" g "), {}}}},
- {"0x68 in string", "\" h \"", 5, {{Item(" h "), {}}}},
- {"0x69 in string", "\" i \"", 5, {{Item(" i "), {}}}},
- {"0x6a in string", "\" j \"", 5, {{Item(" j "), {}}}},
- {"0x6b in string", "\" k \"", 5, {{Item(" k "), {}}}},
- {"0x6c in string", "\" l \"", 5, {{Item(" l "), {}}}},
- {"0x6d in string", "\" m \"", 5, {{Item(" m "), {}}}},
- {"0x6e in string", "\" n \"", 5, {{Item(" n "), {}}}},
- {"0x6f in string", "\" o \"", 5, {{Item(" o "), {}}}},
- {"0x70 in string", "\" p \"", 5, {{Item(" p "), {}}}},
- {"0x71 in string", "\" q \"", 5, {{Item(" q "), {}}}},
- {"0x72 in string", "\" r \"", 5, {{Item(" r "), {}}}},
- {"0x73 in string", "\" s \"", 5, {{Item(" s "), {}}}},
- {"0x74 in string", "\" t \"", 5, {{Item(" t "), {}}}},
- {"0x75 in string", "\" u \"", 5, {{Item(" u "), {}}}},
- {"0x76 in string", "\" v \"", 5, {{Item(" v "), {}}}},
- {"0x77 in string", "\" w \"", 5, {{Item(" w "), {}}}},
- {"0x78 in string", "\" x \"", 5, {{Item(" x "), {}}}},
- {"0x79 in string", "\" y \"", 5, {{Item(" y "), {}}}},
- {"0x7a in string", "\" z \"", 5, {{Item(" z "), {}}}},
- {"0x7b in string", "\" { \"", 5, {{Item(" { "), {}}}},
- {"0x7c in string", "\" | \"", 5, {{Item(" | "), {}}}},
- {"0x7d in string", "\" } \"", 5, {{Item(" } "), {}}}},
- {"0x7e in string", "\" ~ \"", 5, {{Item(" ~ "), {}}}},
- {"0x7f in string", "\" \177 \"", 5, absl::nullopt},
- {"Escaped 0x00 in string", "\"\\\000\"", 4, absl::nullopt},
- {"Escaped 0x01 in string", "\"\\\001\"", 4, absl::nullopt},
- {"Escaped 0x02 in string", "\"\\\002\"", 4, absl::nullopt},
- {"Escaped 0x03 in string", "\"\\\003\"", 4, absl::nullopt},
- {"Escaped 0x04 in string", "\"\\\004\"", 4, absl::nullopt},
- {"Escaped 0x05 in string", "\"\\\005\"", 4, absl::nullopt},
- {"Escaped 0x06 in string", "\"\\\006\"", 4, absl::nullopt},
- {"Escaped 0x07 in string", "\"\\\a\"", 4, absl::nullopt},
- {"Escaped 0x08 in string", "\"\\\b\"", 4, absl::nullopt},
- {"Escaped 0x09 in string", "\"\\\t\"", 4, absl::nullopt},
- {"Escaped 0x0a in string", "\"\\\n\"", 4, absl::nullopt},
- {"Escaped 0x0b in string", "\"\\\v\"", 4, absl::nullopt},
- {"Escaped 0x0c in string", "\"\\\f\"", 4, absl::nullopt},
- {"Escaped 0x0d in string", "\"\\\r\"", 4, absl::nullopt},
- {"Escaped 0x0e in string", "\"\\\016\"", 4, absl::nullopt},
- {"Escaped 0x0f in string", "\"\\\017\"", 4, absl::nullopt},
- {"Escaped 0x10 in string", "\"\\\020\"", 4, absl::nullopt},
- {"Escaped 0x11 in string", "\"\\\021\"", 4, absl::nullopt},
- {"Escaped 0x12 in string", "\"\\\022\"", 4, absl::nullopt},
- {"Escaped 0x13 in string", "\"\\\023\"", 4, absl::nullopt},
- {"Escaped 0x14 in string", "\"\\\024\"", 4, absl::nullopt},
- {"Escaped 0x15 in string", "\"\\\025\"", 4, absl::nullopt},
- {"Escaped 0x16 in string", "\"\\\026\"", 4, absl::nullopt},
- {"Escaped 0x17 in string", "\"\\\027\"", 4, absl::nullopt},
- {"Escaped 0x18 in string", "\"\\\030\"", 4, absl::nullopt},
- {"Escaped 0x19 in string", "\"\\\031\"", 4, absl::nullopt},
- {"Escaped 0x1a in string", "\"\\\032\"", 4, absl::nullopt},
- {"Escaped 0x1b in string", "\"\\\033\"", 4, absl::nullopt},
- {"Escaped 0x1c in string", "\"\\\034\"", 4, absl::nullopt},
- {"Escaped 0x1d in string", "\"\\\035\"", 4, absl::nullopt},
- {"Escaped 0x1e in string", "\"\\\036\"", 4, absl::nullopt},
- {"Escaped 0x1f in string", "\"\\\037\"", 4, absl::nullopt},
- {"Escaped 0x20 in string", "\"\\ \"", 4, absl::nullopt},
- {"Escaped 0x21 in string", "\"\\!\"", 4, absl::nullopt},
- {"Escaped 0x22 in string", "\"\\\"\"", 4, {{Item("\""), {}}}},
- {"Escaped 0x23 in string", "\"\\#\"", 4, absl::nullopt},
- {"Escaped 0x24 in string", "\"\\$\"", 4, absl::nullopt},
- {"Escaped 0x25 in string", "\"\\%\"", 4, absl::nullopt},
- {"Escaped 0x26 in string", "\"\\&\"", 4, absl::nullopt},
- {"Escaped 0x27 in string", "\"\\'\"", 4, absl::nullopt},
- {"Escaped 0x28 in string", "\"\\(\"", 4, absl::nullopt},
- {"Escaped 0x29 in string", "\"\\)\"", 4, absl::nullopt},
- {"Escaped 0x2a in string", "\"\\*\"", 4, absl::nullopt},
- {"Escaped 0x2b in string", "\"\\+\"", 4, absl::nullopt},
- {"Escaped 0x2c in string", "\"\\,\"", 4, absl::nullopt},
- {"Escaped 0x2d in string", "\"\\-\"", 4, absl::nullopt},
- {"Escaped 0x2e in string", "\"\\.\"", 4, absl::nullopt},
- {"Escaped 0x2f in string", "\"\\/\"", 4, absl::nullopt},
- {"Escaped 0x30 in string", "\"\\0\"", 4, absl::nullopt},
- {"Escaped 0x31 in string", "\"\\1\"", 4, absl::nullopt},
- {"Escaped 0x32 in string", "\"\\2\"", 4, absl::nullopt},
- {"Escaped 0x33 in string", "\"\\3\"", 4, absl::nullopt},
- {"Escaped 0x34 in string", "\"\\4\"", 4, absl::nullopt},
- {"Escaped 0x35 in string", "\"\\5\"", 4, absl::nullopt},
- {"Escaped 0x36 in string", "\"\\6\"", 4, absl::nullopt},
- {"Escaped 0x37 in string", "\"\\7\"", 4, absl::nullopt},
- {"Escaped 0x38 in string", "\"\\8\"", 4, absl::nullopt},
- {"Escaped 0x39 in string", "\"\\9\"", 4, absl::nullopt},
- {"Escaped 0x3a in string", "\"\\:\"", 4, absl::nullopt},
- {"Escaped 0x3b in string", "\"\\;\"", 4, absl::nullopt},
- {"Escaped 0x3c in string", "\"\\<\"", 4, absl::nullopt},
- {"Escaped 0x3d in string", "\"\\=\"", 4, absl::nullopt},
- {"Escaped 0x3e in string", "\"\\>\"", 4, absl::nullopt},
- {"Escaped 0x3f in string", "\"\\?\"", 4, absl::nullopt},
- {"Escaped 0x40 in string", "\"\\@\"", 4, absl::nullopt},
- {"Escaped 0x41 in string", "\"\\A\"", 4, absl::nullopt},
- {"Escaped 0x42 in string", "\"\\B\"", 4, absl::nullopt},
- {"Escaped 0x43 in string", "\"\\C\"", 4, absl::nullopt},
- {"Escaped 0x44 in string", "\"\\D\"", 4, absl::nullopt},
- {"Escaped 0x45 in string", "\"\\E\"", 4, absl::nullopt},
- {"Escaped 0x46 in string", "\"\\F\"", 4, absl::nullopt},
- {"Escaped 0x47 in string", "\"\\G\"", 4, absl::nullopt},
- {"Escaped 0x48 in string", "\"\\H\"", 4, absl::nullopt},
- {"Escaped 0x49 in string", "\"\\I\"", 4, absl::nullopt},
- {"Escaped 0x4a in string", "\"\\J\"", 4, absl::nullopt},
- {"Escaped 0x4b in string", "\"\\K\"", 4, absl::nullopt},
- {"Escaped 0x4c in string", "\"\\L\"", 4, absl::nullopt},
- {"Escaped 0x4d in string", "\"\\M\"", 4, absl::nullopt},
- {"Escaped 0x4e in string", "\"\\N\"", 4, absl::nullopt},
- {"Escaped 0x4f in string", "\"\\O\"", 4, absl::nullopt},
- {"Escaped 0x50 in string", "\"\\P\"", 4, absl::nullopt},
- {"Escaped 0x51 in string", "\"\\Q\"", 4, absl::nullopt},
- {"Escaped 0x52 in string", "\"\\R\"", 4, absl::nullopt},
- {"Escaped 0x53 in string", "\"\\S\"", 4, absl::nullopt},
- {"Escaped 0x54 in string", "\"\\T\"", 4, absl::nullopt},
- {"Escaped 0x55 in string", "\"\\U\"", 4, absl::nullopt},
- {"Escaped 0x56 in string", "\"\\V\"", 4, absl::nullopt},
- {"Escaped 0x57 in string", "\"\\W\"", 4, absl::nullopt},
- {"Escaped 0x58 in string", "\"\\X\"", 4, absl::nullopt},
- {"Escaped 0x59 in string", "\"\\Y\"", 4, absl::nullopt},
- {"Escaped 0x5a in string", "\"\\Z\"", 4, absl::nullopt},
- {"Escaped 0x5b in string", "\"\\[\"", 4, absl::nullopt},
- {"Escaped 0x5c in string", "\"\\\\\"", 4, {{Item("\\"), {}}}},
- {"Escaped 0x5d in string", "\"\\]\"", 4, absl::nullopt},
- {"Escaped 0x5e in string", "\"\\^\"", 4, absl::nullopt},
- {"Escaped 0x5f in string", "\"\\_\"", 4, absl::nullopt},
- {"Escaped 0x60 in string", "\"\\`\"", 4, absl::nullopt},
- {"Escaped 0x61 in string", "\"\\a\"", 4, absl::nullopt},
- {"Escaped 0x62 in string", "\"\\b\"", 4, absl::nullopt},
- {"Escaped 0x63 in string", "\"\\c\"", 4, absl::nullopt},
- {"Escaped 0x64 in string", "\"\\d\"", 4, absl::nullopt},
- {"Escaped 0x65 in string", "\"\\e\"", 4, absl::nullopt},
- {"Escaped 0x66 in string", "\"\\f\"", 4, absl::nullopt},
- {"Escaped 0x67 in string", "\"\\g\"", 4, absl::nullopt},
- {"Escaped 0x68 in string", "\"\\h\"", 4, absl::nullopt},
- {"Escaped 0x69 in string", "\"\\i\"", 4, absl::nullopt},
- {"Escaped 0x6a in string", "\"\\j\"", 4, absl::nullopt},
- {"Escaped 0x6b in string", "\"\\k\"", 4, absl::nullopt},
- {"Escaped 0x6c in string", "\"\\l\"", 4, absl::nullopt},
- {"Escaped 0x6d in string", "\"\\m\"", 4, absl::nullopt},
- {"Escaped 0x6e in string", "\"\\n\"", 4, absl::nullopt},
- {"Escaped 0x6f in string", "\"\\o\"", 4, absl::nullopt},
- {"Escaped 0x70 in string", "\"\\p\"", 4, absl::nullopt},
- {"Escaped 0x71 in string", "\"\\q\"", 4, absl::nullopt},
- {"Escaped 0x72 in string", "\"\\r\"", 4, absl::nullopt},
- {"Escaped 0x73 in string", "\"\\s\"", 4, absl::nullopt},
- {"Escaped 0x74 in string", "\"\\t\"", 4, absl::nullopt},
- {"Escaped 0x75 in string", "\"\\u\"", 4, absl::nullopt},
- {"Escaped 0x76 in string", "\"\\v\"", 4, absl::nullopt},
- {"Escaped 0x77 in string", "\"\\w\"", 4, absl::nullopt},
- {"Escaped 0x78 in string", "\"\\x\"", 4, absl::nullopt},
- {"Escaped 0x79 in string", "\"\\y\"", 4, absl::nullopt},
- {"Escaped 0x7a in string", "\"\\z\"", 4, absl::nullopt},
- {"Escaped 0x7b in string", "\"\\{\"", 4, absl::nullopt},
- {"Escaped 0x7c in string", "\"\\|\"", 4, absl::nullopt},
- {"Escaped 0x7d in string", "\"\\}\"", 4, absl::nullopt},
- {"Escaped 0x7e in string", "\"\\~\"", 4, absl::nullopt},
- {"Escaped 0x7f in string", "\"\\\177\"", 4, absl::nullopt},
- // string.json
- {"basic string", "\"foo bar\"", 9, {{Item("foo bar"), {}}}},
- {"empty string", "\"\"", 2, {{Item(""), {}}}},
- {"long string",
- "\"foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo \"",
- 262,
- {{Item("foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
- "foo "),
- {}}}},
- {"whitespace string", "\" \"", 5, {{Item(" "), {}}}},
- {"non-ascii string", "\"f\374\374\"", 5, absl::nullopt},
- {"tab in string", "\"\\t\"", 4, absl::nullopt},
- {"newline in string", "\" \\n \"", 6, absl::nullopt},
- {"single quoted string", "'foo'", 5, absl::nullopt},
- {"unbalanced string", "\"foo", 4, absl::nullopt},
- {"string quoting",
- "\"foo \\\"bar\\\" \\\\ baz\"",
- 20,
- {{Item("foo \"bar\" \\ baz"), {}}}},
- {"bad string quoting", "\"foo \\,\"", 8, absl::nullopt},
- {"ending string quote", "\"foo \\\"", 7, absl::nullopt},
- {"abruptly ending string quote", "\"foo \\", 6, absl::nullopt},
- // token-generated.json
- {"0x00 in token", "a\000a", 3, absl::nullopt},
- {"0x01 in token", "a\001a", 3, absl::nullopt},
- {"0x02 in token", "a\002a", 3, absl::nullopt},
- {"0x03 in token", "a\003a", 3, absl::nullopt},
- {"0x04 in token", "a\004a", 3, absl::nullopt},
- {"0x05 in token", "a\005a", 3, absl::nullopt},
- {"0x06 in token", "a\006a", 3, absl::nullopt},
- {"0x07 in token", "a\aa", 3, absl::nullopt},
- {"0x08 in token", "a\ba", 3, absl::nullopt},
- {"0x09 in token", "a\ta", 3, absl::nullopt},
- {"0x0a in token", "a\na", 3, absl::nullopt},
- {"0x0b in token", "a\va", 3, absl::nullopt},
- {"0x0c in token", "a\fa", 3, absl::nullopt},
- {"0x0d in token", "a\ra", 3, absl::nullopt},
- {"0x0e in token", "a\016a", 3, absl::nullopt},
- {"0x0f in token", "a\017a", 3, absl::nullopt},
- {"0x10 in token", "a\020a", 3, absl::nullopt},
- {"0x11 in token", "a\021a", 3, absl::nullopt},
- {"0x12 in token", "a\022a", 3, absl::nullopt},
- {"0x13 in token", "a\023a", 3, absl::nullopt},
- {"0x14 in token", "a\024a", 3, absl::nullopt},
- {"0x15 in token", "a\025a", 3, absl::nullopt},
- {"0x16 in token", "a\026a", 3, absl::nullopt},
- {"0x17 in token", "a\027a", 3, absl::nullopt},
- {"0x18 in token", "a\030a", 3, absl::nullopt},
- {"0x19 in token", "a\031a", 3, absl::nullopt},
- {"0x1a in token", "a\032a", 3, absl::nullopt},
- {"0x1b in token", "a\033a", 3, absl::nullopt},
- {"0x1c in token", "a\034a", 3, absl::nullopt},
- {"0x1d in token", "a\035a", 3, absl::nullopt},
- {"0x1e in token", "a\036a", 3, absl::nullopt},
- {"0x1f in token", "a\037a", 3, absl::nullopt},
- {"0x20 in token", "a a", 3, absl::nullopt},
- {"0x21 in token", "a!a", 3, {{Item("a!a", Item::kTokenType), {}}}},
- {"0x22 in token", "a\"a", 3, absl::nullopt},
- {"0x23 in token", "a#a", 3, {{Item("a#a", Item::kTokenType), {}}}},
- {"0x24 in token", "a$a", 3, {{Item("a$a", Item::kTokenType), {}}}},
- {"0x25 in token", "a%a", 3, {{Item("a%a", Item::kTokenType), {}}}},
- {"0x26 in token", "a&a", 3, {{Item("a&a", Item::kTokenType), {}}}},
- {"0x27 in token", "a'a", 3, {{Item("a'a", Item::kTokenType), {}}}},
- {"0x28 in token", "a(a", 3, absl::nullopt},
- {"0x29 in token", "a)a", 3, absl::nullopt},
- {"0x2a in token", "a*a", 3, {{Item("a*a", Item::kTokenType), {}}}},
- {"0x2b in token", "a+a", 3, {{Item("a+a", Item::kTokenType), {}}}},
- {"0x2c in token", "a,a", 3, absl::nullopt},
- {"0x2d in token", "a-a", 3, {{Item("a-a", Item::kTokenType), {}}}},
- {"0x2e in token", "a.a", 3, {{Item("a.a", Item::kTokenType), {}}}},
- {"0x2f in token", "a/a", 3, {{Item("a/a", Item::kTokenType), {}}}},
- {"0x30 in token", "a0a", 3, {{Item("a0a", Item::kTokenType), {}}}},
- {"0x31 in token", "a1a", 3, {{Item("a1a", Item::kTokenType), {}}}},
- {"0x32 in token", "a2a", 3, {{Item("a2a", Item::kTokenType), {}}}},
- {"0x33 in token", "a3a", 3, {{Item("a3a", Item::kTokenType), {}}}},
- {"0x34 in token", "a4a", 3, {{Item("a4a", Item::kTokenType), {}}}},
- {"0x35 in token", "a5a", 3, {{Item("a5a", Item::kTokenType), {}}}},
- {"0x36 in token", "a6a", 3, {{Item("a6a", Item::kTokenType), {}}}},
- {"0x37 in token", "a7a", 3, {{Item("a7a", Item::kTokenType), {}}}},
- {"0x38 in token", "a8a", 3, {{Item("a8a", Item::kTokenType), {}}}},
- {"0x39 in token", "a9a", 3, {{Item("a9a", Item::kTokenType), {}}}},
- {"0x3a in token", "a:a", 3, {{Item("a:a", Item::kTokenType), {}}}},
- {"0x3b in token",
- "a;a",
- 3,
- {{Item("a", Item::kTokenType), {BooleanParam("a", true)}}}},
- {"0x3c in token", "a<a", 3, absl::nullopt},
- {"0x3d in token", "a=a", 3, absl::nullopt},
- {"0x3e in token", "a>a", 3, absl::nullopt},
- {"0x3f in token", "a?a", 3, absl::nullopt},
- {"0x40 in token", "a@a", 3, absl::nullopt},
- {"0x41 in token", "aAa", 3, {{Item("aAa", Item::kTokenType), {}}}},
- {"0x42 in token", "aBa", 3, {{Item("aBa", Item::kTokenType), {}}}},
- {"0x43 in token", "aCa", 3, {{Item("aCa", Item::kTokenType), {}}}},
- {"0x44 in token", "aDa", 3, {{Item("aDa", Item::kTokenType), {}}}},
- {"0x45 in token", "aEa", 3, {{Item("aEa", Item::kTokenType), {}}}},
- {"0x46 in token", "aFa", 3, {{Item("aFa", Item::kTokenType), {}}}},
- {"0x47 in token", "aGa", 3, {{Item("aGa", Item::kTokenType), {}}}},
- {"0x48 in token", "aHa", 3, {{Item("aHa", Item::kTokenType), {}}}},
- {"0x49 in token", "aIa", 3, {{Item("aIa", Item::kTokenType), {}}}},
- {"0x4a in token", "aJa", 3, {{Item("aJa", Item::kTokenType), {}}}},
- {"0x4b in token", "aKa", 3, {{Item("aKa", Item::kTokenType), {}}}},
- {"0x4c in token", "aLa", 3, {{Item("aLa", Item::kTokenType), {}}}},
- {"0x4d in token", "aMa", 3, {{Item("aMa", Item::kTokenType), {}}}},
- {"0x4e in token", "aNa", 3, {{Item("aNa", Item::kTokenType), {}}}},
- {"0x4f in token", "aOa", 3, {{Item("aOa", Item::kTokenType), {}}}},
- {"0x50 in token", "aPa", 3, {{Item("aPa", Item::kTokenType), {}}}},
- {"0x51 in token", "aQa", 3, {{Item("aQa", Item::kTokenType), {}}}},
- {"0x52 in token", "aRa", 3, {{Item("aRa", Item::kTokenType), {}}}},
- {"0x53 in token", "aSa", 3, {{Item("aSa", Item::kTokenType), {}}}},
- {"0x54 in token", "aTa", 3, {{Item("aTa", Item::kTokenType), {}}}},
- {"0x55 in token", "aUa", 3, {{Item("aUa", Item::kTokenType), {}}}},
- {"0x56 in token", "aVa", 3, {{Item("aVa", Item::kTokenType), {}}}},
- {"0x57 in token", "aWa", 3, {{Item("aWa", Item::kTokenType), {}}}},
- {"0x58 in token", "aXa", 3, {{Item("aXa", Item::kTokenType), {}}}},
- {"0x59 in token", "aYa", 3, {{Item("aYa", Item::kTokenType), {}}}},
- {"0x5a in token", "aZa", 3, {{Item("aZa", Item::kTokenType), {}}}},
- {"0x5b in token", "a[a", 3, absl::nullopt},
- {"0x5c in token", "a\\a", 3, absl::nullopt},
- {"0x5d in token", "a]a", 3, absl::nullopt},
- {"0x5e in token", "a^a", 3, {{Item("a^a", Item::kTokenType), {}}}},
- {"0x5f in token", "a_a", 3, {{Item("a_a", Item::kTokenType), {}}}},
- {"0x60 in token", "a`a", 3, {{Item("a`a", Item::kTokenType), {}}}},
- {"0x61 in token", "aaa", 3, {{Item("aaa", Item::kTokenType), {}}}},
- {"0x62 in token", "aba", 3, {{Item("aba", Item::kTokenType), {}}}},
- {"0x63 in token", "aca", 3, {{Item("aca", Item::kTokenType), {}}}},
- {"0x64 in token", "ada", 3, {{Item("ada", Item::kTokenType), {}}}},
- {"0x65 in token", "aea", 3, {{Item("aea", Item::kTokenType), {}}}},
- {"0x66 in token", "afa", 3, {{Item("afa", Item::kTokenType), {}}}},
- {"0x67 in token", "aga", 3, {{Item("aga", Item::kTokenType), {}}}},
- {"0x68 in token", "aha", 3, {{Item("aha", Item::kTokenType), {}}}},
- {"0x69 in token", "aia", 3, {{Item("aia", Item::kTokenType), {}}}},
- {"0x6a in token", "aja", 3, {{Item("aja", Item::kTokenType), {}}}},
- {"0x6b in token", "aka", 3, {{Item("aka", Item::kTokenType), {}}}},
- {"0x6c in token", "ala", 3, {{Item("ala", Item::kTokenType), {}}}},
- {"0x6d in token", "ama", 3, {{Item("ama", Item::kTokenType), {}}}},
- {"0x6e in token", "ana", 3, {{Item("ana", Item::kTokenType), {}}}},
- {"0x6f in token", "aoa", 3, {{Item("aoa", Item::kTokenType), {}}}},
- {"0x70 in token", "apa", 3, {{Item("apa", Item::kTokenType), {}}}},
- {"0x71 in token", "aqa", 3, {{Item("aqa", Item::kTokenType), {}}}},
- {"0x72 in token", "ara", 3, {{Item("ara", Item::kTokenType), {}}}},
- {"0x73 in token", "asa", 3, {{Item("asa", Item::kTokenType), {}}}},
- {"0x74 in token", "ata", 3, {{Item("ata", Item::kTokenType), {}}}},
- {"0x75 in token", "aua", 3, {{Item("aua", Item::kTokenType), {}}}},
- {"0x76 in token", "ava", 3, {{Item("ava", Item::kTokenType), {}}}},
- {"0x77 in token", "awa", 3, {{Item("awa", Item::kTokenType), {}}}},
- {"0x78 in token", "axa", 3, {{Item("axa", Item::kTokenType), {}}}},
- {"0x79 in token", "aya", 3, {{Item("aya", Item::kTokenType), {}}}},
- {"0x7a in token", "aza", 3, {{Item("aza", Item::kTokenType), {}}}},
- {"0x7b in token", "a{a", 3, absl::nullopt},
- {"0x7c in token", "a|a", 3, {{Item("a|a", Item::kTokenType), {}}}},
- {"0x7d in token", "a}a", 3, absl::nullopt},
- {"0x7e in token", "a~a", 3, {{Item("a~a", Item::kTokenType), {}}}},
- {"0x7f in token", "a\177a", 3, absl::nullopt},
- {"0x00 starting an token", "\000a", 2, absl::nullopt},
- {"0x01 starting an token", "\001a", 2, absl::nullopt},
- {"0x02 starting an token", "\002a", 2, absl::nullopt},
- {"0x03 starting an token", "\003a", 2, absl::nullopt},
- {"0x04 starting an token", "\004a", 2, absl::nullopt},
- {"0x05 starting an token", "\005a", 2, absl::nullopt},
- {"0x06 starting an token", "\006a", 2, absl::nullopt},
- {"0x07 starting an token", "\aa", 2, absl::nullopt},
- {"0x08 starting an token", "\ba", 2, absl::nullopt},
- {"0x09 starting an token", "\ta", 2, absl::nullopt},
- {"0x0a starting an token", "\na", 2, absl::nullopt},
- {"0x0b starting an token", "\va", 2, absl::nullopt},
- {"0x0c starting an token", "\fa", 2, absl::nullopt},
- {"0x0d starting an token", "\ra", 2, absl::nullopt},
- {"0x0e starting an token", "\016a", 2, absl::nullopt},
- {"0x0f starting an token", "\017a", 2, absl::nullopt},
- {"0x10 starting an token", "\020a", 2, absl::nullopt},
- {"0x11 starting an token", "\021a", 2, absl::nullopt},
- {"0x12 starting an token", "\022a", 2, absl::nullopt},
- {"0x13 starting an token", "\023a", 2, absl::nullopt},
- {"0x14 starting an token", "\024a", 2, absl::nullopt},
- {"0x15 starting an token", "\025a", 2, absl::nullopt},
- {"0x16 starting an token", "\026a", 2, absl::nullopt},
- {"0x17 starting an token", "\027a", 2, absl::nullopt},
- {"0x18 starting an token", "\030a", 2, absl::nullopt},
- {"0x19 starting an token", "\031a", 2, absl::nullopt},
- {"0x1a starting an token", "\032a", 2, absl::nullopt},
- {"0x1b starting an token", "\033a", 2, absl::nullopt},
- {"0x1c starting an token", "\034a", 2, absl::nullopt},
- {"0x1d starting an token", "\035a", 2, absl::nullopt},
- {"0x1e starting an token", "\036a", 2, absl::nullopt},
- {"0x1f starting an token", "\037a", 2, absl::nullopt},
- {"0x20 starting an token",
- " a",
- 2,
- {{Item("a", Item::kTokenType), {}}},
- "a"},
- {"0x21 starting an token", "!a", 2, absl::nullopt},
- {"0x22 starting an token", "\"a", 2, absl::nullopt},
- {"0x23 starting an token", "#a", 2, absl::nullopt},
- {"0x24 starting an token", "$a", 2, absl::nullopt},
- {"0x25 starting an token", "%a", 2, absl::nullopt},
- {"0x26 starting an token", "&a", 2, absl::nullopt},
- {"0x27 starting an token", "'a", 2, absl::nullopt},
- {"0x28 starting an token", "(a", 2, absl::nullopt},
- {"0x29 starting an token", ")a", 2, absl::nullopt},
- {"0x2a starting an token", "*a", 2, {{Item("*a", Item::kTokenType), {}}}},
- {"0x2b starting an token", "+a", 2, absl::nullopt},
- {"0x2c starting an token", ",a", 2, absl::nullopt},
- {"0x2d starting an token", "-a", 2, absl::nullopt},
- {"0x2e starting an token", ".a", 2, absl::nullopt},
- {"0x2f starting an token", "/a", 2, absl::nullopt},
- {"0x30 starting an token", "0a", 2, absl::nullopt},
- {"0x31 starting an token", "1a", 2, absl::nullopt},
- {"0x32 starting an token", "2a", 2, absl::nullopt},
- {"0x33 starting an token", "3a", 2, absl::nullopt},
- {"0x34 starting an token", "4a", 2, absl::nullopt},
- {"0x35 starting an token", "5a", 2, absl::nullopt},
- {"0x36 starting an token", "6a", 2, absl::nullopt},
- {"0x37 starting an token", "7a", 2, absl::nullopt},
- {"0x38 starting an token", "8a", 2, absl::nullopt},
- {"0x39 starting an token", "9a", 2, absl::nullopt},
- {"0x3a starting an token", ":a", 2, absl::nullopt},
- {"0x3b starting an token", ";a", 2, absl::nullopt},
- {"0x3c starting an token", "<a", 2, absl::nullopt},
- {"0x3d starting an token", "=a", 2, absl::nullopt},
- {"0x3e starting an token", ">a", 2, absl::nullopt},
- {"0x3f starting an token", "?a", 2, absl::nullopt},
- {"0x40 starting an token", "@a", 2, absl::nullopt},
- {"0x41 starting an token", "Aa", 2, {{Item("Aa", Item::kTokenType), {}}}},
- {"0x42 starting an token", "Ba", 2, {{Item("Ba", Item::kTokenType), {}}}},
- {"0x43 starting an token", "Ca", 2, {{Item("Ca", Item::kTokenType), {}}}},
- {"0x44 starting an token", "Da", 2, {{Item("Da", Item::kTokenType), {}}}},
- {"0x45 starting an token", "Ea", 2, {{Item("Ea", Item::kTokenType), {}}}},
- {"0x46 starting an token", "Fa", 2, {{Item("Fa", Item::kTokenType), {}}}},
- {"0x47 starting an token", "Ga", 2, {{Item("Ga", Item::kTokenType), {}}}},
- {"0x48 starting an token", "Ha", 2, {{Item("Ha", Item::kTokenType), {}}}},
- {"0x49 starting an token", "Ia", 2, {{Item("Ia", Item::kTokenType), {}}}},
- {"0x4a starting an token", "Ja", 2, {{Item("Ja", Item::kTokenType), {}}}},
- {"0x4b starting an token", "Ka", 2, {{Item("Ka", Item::kTokenType), {}}}},
- {"0x4c starting an token", "La", 2, {{Item("La", Item::kTokenType), {}}}},
- {"0x4d starting an token", "Ma", 2, {{Item("Ma", Item::kTokenType), {}}}},
- {"0x4e starting an token", "Na", 2, {{Item("Na", Item::kTokenType), {}}}},
- {"0x4f starting an token", "Oa", 2, {{Item("Oa", Item::kTokenType), {}}}},
- {"0x50 starting an token", "Pa", 2, {{Item("Pa", Item::kTokenType), {}}}},
- {"0x51 starting an token", "Qa", 2, {{Item("Qa", Item::kTokenType), {}}}},
- {"0x52 starting an token", "Ra", 2, {{Item("Ra", Item::kTokenType), {}}}},
- {"0x53 starting an token", "Sa", 2, {{Item("Sa", Item::kTokenType), {}}}},
- {"0x54 starting an token", "Ta", 2, {{Item("Ta", Item::kTokenType), {}}}},
- {"0x55 starting an token", "Ua", 2, {{Item("Ua", Item::kTokenType), {}}}},
- {"0x56 starting an token", "Va", 2, {{Item("Va", Item::kTokenType), {}}}},
- {"0x57 starting an token", "Wa", 2, {{Item("Wa", Item::kTokenType), {}}}},
- {"0x58 starting an token", "Xa", 2, {{Item("Xa", Item::kTokenType), {}}}},
- {"0x59 starting an token", "Ya", 2, {{Item("Ya", Item::kTokenType), {}}}},
- {"0x5a starting an token", "Za", 2, {{Item("Za", Item::kTokenType), {}}}},
- {"0x5b starting an token", "[a", 2, absl::nullopt},
- {"0x5c starting an token", "\\a", 2, absl::nullopt},
- {"0x5d starting an token", "]a", 2, absl::nullopt},
- {"0x5e starting an token", "^a", 2, absl::nullopt},
- {"0x5f starting an token", "_a", 2, absl::nullopt},
- {"0x60 starting an token", "`a", 2, absl::nullopt},
- {"0x61 starting an token", "aa", 2, {{Item("aa", Item::kTokenType), {}}}},
- {"0x62 starting an token", "ba", 2, {{Item("ba", Item::kTokenType), {}}}},
- {"0x63 starting an token", "ca", 2, {{Item("ca", Item::kTokenType), {}}}},
- {"0x64 starting an token", "da", 2, {{Item("da", Item::kTokenType), {}}}},
- {"0x65 starting an token", "ea", 2, {{Item("ea", Item::kTokenType), {}}}},
- {"0x66 starting an token", "fa", 2, {{Item("fa", Item::kTokenType), {}}}},
- {"0x67 starting an token", "ga", 2, {{Item("ga", Item::kTokenType), {}}}},
- {"0x68 starting an token", "ha", 2, {{Item("ha", Item::kTokenType), {}}}},
- {"0x69 starting an token", "ia", 2, {{Item("ia", Item::kTokenType), {}}}},
- {"0x6a starting an token", "ja", 2, {{Item("ja", Item::kTokenType), {}}}},
- {"0x6b starting an token", "ka", 2, {{Item("ka", Item::kTokenType), {}}}},
- {"0x6c starting an token", "la", 2, {{Item("la", Item::kTokenType), {}}}},
- {"0x6d starting an token", "ma", 2, {{Item("ma", Item::kTokenType), {}}}},
- {"0x6e starting an token", "na", 2, {{Item("na", Item::kTokenType), {}}}},
- {"0x6f starting an token", "oa", 2, {{Item("oa", Item::kTokenType), {}}}},
- {"0x70 starting an token", "pa", 2, {{Item("pa", Item::kTokenType), {}}}},
- {"0x71 starting an token", "qa", 2, {{Item("qa", Item::kTokenType), {}}}},
- {"0x72 starting an token", "ra", 2, {{Item("ra", Item::kTokenType), {}}}},
- {"0x73 starting an token", "sa", 2, {{Item("sa", Item::kTokenType), {}}}},
- {"0x74 starting an token", "ta", 2, {{Item("ta", Item::kTokenType), {}}}},
- {"0x75 starting an token", "ua", 2, {{Item("ua", Item::kTokenType), {}}}},
- {"0x76 starting an token", "va", 2, {{Item("va", Item::kTokenType), {}}}},
- {"0x77 starting an token", "wa", 2, {{Item("wa", Item::kTokenType), {}}}},
- {"0x78 starting an token", "xa", 2, {{Item("xa", Item::kTokenType), {}}}},
- {"0x79 starting an token", "ya", 2, {{Item("ya", Item::kTokenType), {}}}},
- {"0x7a starting an token", "za", 2, {{Item("za", Item::kTokenType), {}}}},
- {"0x7b starting an token", "{a", 2, absl::nullopt},
- {"0x7c starting an token", "|a", 2, absl::nullopt},
- {"0x7d starting an token", "}a", 2, absl::nullopt},
- {"0x7e starting an token", "~a", 2, absl::nullopt},
- {"0x7f starting an token", "\177a", 2, absl::nullopt},
- // token.json
- {"basic token - item",
- "a_b-c.d3:f%00/*",
- 15,
- {{Item("a_b-c.d3:f%00/*", Item::kTokenType), {}}}},
- {"token with capitals - item",
- "fooBar",
- 6,
- {{Item("fooBar", Item::kTokenType), {}}}},
- {"token starting with capitals - item",
- "FooBar",
- 6,
- {{Item("FooBar", Item::kTokenType), {}}}},
-};
-
-const struct ListTestCase {
- const char* name;
- const char* raw;
- size_t raw_len;
- const absl::optional<List> expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} list_test_cases[] = {
-
- // examples.json
- {"Example-StrListHeader",
- "\"foo\", \"bar\", \"It was the best of times.\"",
- 41,
- {{{Item("foo"), {}},
- {Item("bar"), {}},
- {Item("It was the best of times."), {}}}}},
- {"Example-Hdr (list on one line)",
- "foo, bar",
- 8,
- {{{Item("foo", Item::kTokenType), {}},
- {Item("bar", Item::kTokenType), {}}}}},
- {"Example-Hdr (list on two lines)",
- "foo, bar",
- 8,
- {{{Item("foo", Item::kTokenType), {}},
- {Item("bar", Item::kTokenType), {}}}},
- "foo, bar"},
- {"Example-StrListListHeader",
- "(\"foo\" \"bar\"), (\"baz\"), (\"bat\" \"one\"), ()",
- 41,
- {{{{{Item("foo"), {}}, {Item("bar"), {}}}, {}},
- {{{Item("baz"), {}}}, {}},
- {{{Item("bat"), {}}, {Item("one"), {}}}, {}},
- {std::vector<ParameterizedItem>(), {}}}}},
- {"Example-ListListParam",
- "(\"foo\"; a=1;b=2);lvl=5, (\"bar\" \"baz\");lvl=1",
- 43,
- {{{{{Item("foo"), {Param("a", 1), Param("b", 2)}}}, {Param("lvl", 5)}},
- {{{Item("bar"), {}}, {Item("baz"), {}}}, {Param("lvl", 1)}}}},
- "(\"foo\";a=1;b=2);lvl=5, (\"bar\" \"baz\");lvl=1"},
- {"Example-ParamListHeader",
- "abc;a=1;b=2; cde_456, (ghi;jk=4 l);q=\"9\";r=w",
- 44,
- {{{Item("abc", Item::kTokenType),
- {Param("a", 1), Param("b", 2), BooleanParam("cde_456", true)}},
- {{{Item("ghi", Item::kTokenType), {Param("jk", 4)}},
- {Item("l", Item::kTokenType), {}}},
- {Param("q", "9"), TokenParam("r", "w")}}}},
- "abc;a=1;b=2;cde_456, (ghi;jk=4 l);q=\"9\";r=w"},
- // key-generated.json
- {"0x00 in parameterised list key", "foo; a\000a=1", 10, absl::nullopt},
- {"0x01 in parameterised list key", "foo; a\001a=1", 10, absl::nullopt},
- {"0x02 in parameterised list key", "foo; a\002a=1", 10, absl::nullopt},
- {"0x03 in parameterised list key", "foo; a\003a=1", 10, absl::nullopt},
- {"0x04 in parameterised list key", "foo; a\004a=1", 10, absl::nullopt},
- {"0x05 in parameterised list key", "foo; a\005a=1", 10, absl::nullopt},
- {"0x06 in parameterised list key", "foo; a\006a=1", 10, absl::nullopt},
- {"0x07 in parameterised list key", "foo; a\aa=1", 10, absl::nullopt},
- {"0x08 in parameterised list key", "foo; a\ba=1", 10, absl::nullopt},
- {"0x09 in parameterised list key", "foo; a\ta=1", 10, absl::nullopt},
- {"0x0a in parameterised list key", "foo; a\na=1", 10, absl::nullopt},
- {"0x0b in parameterised list key", "foo; a\va=1", 10, absl::nullopt},
- {"0x0c in parameterised list key", "foo; a\fa=1", 10, absl::nullopt},
- {"0x0d in parameterised list key", "foo; a\ra=1", 10, absl::nullopt},
- {"0x0e in parameterised list key", "foo; a\016a=1", 10, absl::nullopt},
- {"0x0f in parameterised list key", "foo; a\017a=1", 10, absl::nullopt},
- {"0x10 in parameterised list key", "foo; a\020a=1", 10, absl::nullopt},
- {"0x11 in parameterised list key", "foo; a\021a=1", 10, absl::nullopt},
- {"0x12 in parameterised list key", "foo; a\022a=1", 10, absl::nullopt},
- {"0x13 in parameterised list key", "foo; a\023a=1", 10, absl::nullopt},
- {"0x14 in parameterised list key", "foo; a\024a=1", 10, absl::nullopt},
- {"0x15 in parameterised list key", "foo; a\025a=1", 10, absl::nullopt},
- {"0x16 in parameterised list key", "foo; a\026a=1", 10, absl::nullopt},
- {"0x17 in parameterised list key", "foo; a\027a=1", 10, absl::nullopt},
- {"0x18 in parameterised list key", "foo; a\030a=1", 10, absl::nullopt},
- {"0x19 in parameterised list key", "foo; a\031a=1", 10, absl::nullopt},
- {"0x1a in parameterised list key", "foo; a\032a=1", 10, absl::nullopt},
- {"0x1b in parameterised list key", "foo; a\033a=1", 10, absl::nullopt},
- {"0x1c in parameterised list key", "foo; a\034a=1", 10, absl::nullopt},
- {"0x1d in parameterised list key", "foo; a\035a=1", 10, absl::nullopt},
- {"0x1e in parameterised list key", "foo; a\036a=1", 10, absl::nullopt},
- {"0x1f in parameterised list key", "foo; a\037a=1", 10, absl::nullopt},
- {"0x20 in parameterised list key", "foo; a a=1", 10, absl::nullopt},
- {"0x21 in parameterised list key", "foo; a!a=1", 10, absl::nullopt},
- {"0x22 in parameterised list key", "foo; a\"a=1", 10, absl::nullopt},
- {"0x23 in parameterised list key", "foo; a#a=1", 10, absl::nullopt},
- {"0x24 in parameterised list key", "foo; a$a=1", 10, absl::nullopt},
- {"0x25 in parameterised list key", "foo; a%a=1", 10, absl::nullopt},
- {"0x26 in parameterised list key", "foo; a&a=1", 10, absl::nullopt},
- {"0x27 in parameterised list key", "foo; a'a=1", 10, absl::nullopt},
- {"0x28 in parameterised list key", "foo; a(a=1", 10, absl::nullopt},
- {"0x29 in parameterised list key", "foo; a)a=1", 10, absl::nullopt},
- {"0x2a in parameterised list key",
- "foo; a*a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a*a", 1)}}}},
- "foo;a*a=1"},
- {"0x2b in parameterised list key", "foo; a+a=1", 10, absl::nullopt},
- {"0x2c in parameterised list key", "foo; a,a=1", 10, absl::nullopt},
- {"0x2d in parameterised list key",
- "foo; a-a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a-a", 1)}}}},
- "foo;a-a=1"},
- {"0x2e in parameterised list key",
- "foo; a.a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a.a", 1)}}}},
- "foo;a.a=1"},
- {"0x2f in parameterised list key", "foo; a/a=1", 10, absl::nullopt},
- {"0x30 in parameterised list key",
- "foo; a0a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a0a", 1)}}}},
- "foo;a0a=1"},
- {"0x31 in parameterised list key",
- "foo; a1a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a1a", 1)}}}},
- "foo;a1a=1"},
- {"0x32 in parameterised list key",
- "foo; a2a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a2a", 1)}}}},
- "foo;a2a=1"},
- {"0x33 in parameterised list key",
- "foo; a3a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a3a", 1)}}}},
- "foo;a3a=1"},
- {"0x34 in parameterised list key",
- "foo; a4a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a4a", 1)}}}},
- "foo;a4a=1"},
- {"0x35 in parameterised list key",
- "foo; a5a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a5a", 1)}}}},
- "foo;a5a=1"},
- {"0x36 in parameterised list key",
- "foo; a6a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a6a", 1)}}}},
- "foo;a6a=1"},
- {"0x37 in parameterised list key",
- "foo; a7a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a7a", 1)}}}},
- "foo;a7a=1"},
- {"0x38 in parameterised list key",
- "foo; a8a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a8a", 1)}}}},
- "foo;a8a=1"},
- {"0x39 in parameterised list key",
- "foo; a9a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a9a", 1)}}}},
- "foo;a9a=1"},
- {"0x3a in parameterised list key", "foo; a:a=1", 10, absl::nullopt},
- {"0x3b in parameterised list key",
- "foo; a;a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a", 1)}}}},
- "foo;a=1"},
- {"0x3c in parameterised list key", "foo; a<a=1", 10, absl::nullopt},
- {"0x3d in parameterised list key", "foo; a=a=1", 10, absl::nullopt},
- {"0x3e in parameterised list key", "foo; a>a=1", 10, absl::nullopt},
- {"0x3f in parameterised list key", "foo; a?a=1", 10, absl::nullopt},
- {"0x40 in parameterised list key", "foo; a@a=1", 10, absl::nullopt},
- {"0x41 in parameterised list key", "foo; aAa=1", 10, absl::nullopt},
- {"0x42 in parameterised list key", "foo; aBa=1", 10, absl::nullopt},
- {"0x43 in parameterised list key", "foo; aCa=1", 10, absl::nullopt},
- {"0x44 in parameterised list key", "foo; aDa=1", 10, absl::nullopt},
- {"0x45 in parameterised list key", "foo; aEa=1", 10, absl::nullopt},
- {"0x46 in parameterised list key", "foo; aFa=1", 10, absl::nullopt},
- {"0x47 in parameterised list key", "foo; aGa=1", 10, absl::nullopt},
- {"0x48 in parameterised list key", "foo; aHa=1", 10, absl::nullopt},
- {"0x49 in parameterised list key", "foo; aIa=1", 10, absl::nullopt},
- {"0x4a in parameterised list key", "foo; aJa=1", 10, absl::nullopt},
- {"0x4b in parameterised list key", "foo; aKa=1", 10, absl::nullopt},
- {"0x4c in parameterised list key", "foo; aLa=1", 10, absl::nullopt},
- {"0x4d in parameterised list key", "foo; aMa=1", 10, absl::nullopt},
- {"0x4e in parameterised list key", "foo; aNa=1", 10, absl::nullopt},
- {"0x4f in parameterised list key", "foo; aOa=1", 10, absl::nullopt},
- {"0x50 in parameterised list key", "foo; aPa=1", 10, absl::nullopt},
- {"0x51 in parameterised list key", "foo; aQa=1", 10, absl::nullopt},
- {"0x52 in parameterised list key", "foo; aRa=1", 10, absl::nullopt},
- {"0x53 in parameterised list key", "foo; aSa=1", 10, absl::nullopt},
- {"0x54 in parameterised list key", "foo; aTa=1", 10, absl::nullopt},
- {"0x55 in parameterised list key", "foo; aUa=1", 10, absl::nullopt},
- {"0x56 in parameterised list key", "foo; aVa=1", 10, absl::nullopt},
- {"0x57 in parameterised list key", "foo; aWa=1", 10, absl::nullopt},
- {"0x58 in parameterised list key", "foo; aXa=1", 10, absl::nullopt},
- {"0x59 in parameterised list key", "foo; aYa=1", 10, absl::nullopt},
- {"0x5a in parameterised list key", "foo; aZa=1", 10, absl::nullopt},
- {"0x5b in parameterised list key", "foo; a[a=1", 10, absl::nullopt},
- {"0x5c in parameterised list key", "foo; a\\a=1", 10, absl::nullopt},
- {"0x5d in parameterised list key", "foo; a]a=1", 10, absl::nullopt},
- {"0x5e in parameterised list key", "foo; a^a=1", 10, absl::nullopt},
- {"0x5f in parameterised list key",
- "foo; a_a=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("a_a", 1)}}}},
- "foo;a_a=1"},
- {"0x60 in parameterised list key", "foo; a`a=1", 10, absl::nullopt},
- {"0x61 in parameterised list key",
- "foo; aaa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aaa", 1)}}}},
- "foo;aaa=1"},
- {"0x62 in parameterised list key",
- "foo; aba=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aba", 1)}}}},
- "foo;aba=1"},
- {"0x63 in parameterised list key",
- "foo; aca=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aca", 1)}}}},
- "foo;aca=1"},
- {"0x64 in parameterised list key",
- "foo; ada=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ada", 1)}}}},
- "foo;ada=1"},
- {"0x65 in parameterised list key",
- "foo; aea=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aea", 1)}}}},
- "foo;aea=1"},
- {"0x66 in parameterised list key",
- "foo; afa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("afa", 1)}}}},
- "foo;afa=1"},
- {"0x67 in parameterised list key",
- "foo; aga=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aga", 1)}}}},
- "foo;aga=1"},
- {"0x68 in parameterised list key",
- "foo; aha=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aha", 1)}}}},
- "foo;aha=1"},
- {"0x69 in parameterised list key",
- "foo; aia=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aia", 1)}}}},
- "foo;aia=1"},
- {"0x6a in parameterised list key",
- "foo; aja=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aja", 1)}}}},
- "foo;aja=1"},
- {"0x6b in parameterised list key",
- "foo; aka=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aka", 1)}}}},
- "foo;aka=1"},
- {"0x6c in parameterised list key",
- "foo; ala=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ala", 1)}}}},
- "foo;ala=1"},
- {"0x6d in parameterised list key",
- "foo; ama=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ama", 1)}}}},
- "foo;ama=1"},
- {"0x6e in parameterised list key",
- "foo; ana=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ana", 1)}}}},
- "foo;ana=1"},
- {"0x6f in parameterised list key",
- "foo; aoa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aoa", 1)}}}},
- "foo;aoa=1"},
- {"0x70 in parameterised list key",
- "foo; apa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("apa", 1)}}}},
- "foo;apa=1"},
- {"0x71 in parameterised list key",
- "foo; aqa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aqa", 1)}}}},
- "foo;aqa=1"},
- {"0x72 in parameterised list key",
- "foo; ara=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ara", 1)}}}},
- "foo;ara=1"},
- {"0x73 in parameterised list key",
- "foo; asa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("asa", 1)}}}},
- "foo;asa=1"},
- {"0x74 in parameterised list key",
- "foo; ata=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ata", 1)}}}},
- "foo;ata=1"},
- {"0x75 in parameterised list key",
- "foo; aua=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aua", 1)}}}},
- "foo;aua=1"},
- {"0x76 in parameterised list key",
- "foo; ava=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("ava", 1)}}}},
- "foo;ava=1"},
- {"0x77 in parameterised list key",
- "foo; awa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("awa", 1)}}}},
- "foo;awa=1"},
- {"0x78 in parameterised list key",
- "foo; axa=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("axa", 1)}}}},
- "foo;axa=1"},
- {"0x79 in parameterised list key",
- "foo; aya=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aya", 1)}}}},
- "foo;aya=1"},
- {"0x7a in parameterised list key",
- "foo; aza=1",
- 10,
- {{{Item("foo", Item::kTokenType), {Param("aza", 1)}}}},
- "foo;aza=1"},
- {"0x7b in parameterised list key", "foo; a{a=1", 10, absl::nullopt},
- {"0x7c in parameterised list key", "foo; a|a=1", 10, absl::nullopt},
- {"0x7d in parameterised list key", "foo; a}a=1", 10, absl::nullopt},
- {"0x7e in parameterised list key", "foo; a~a=1", 10, absl::nullopt},
- {"0x7f in parameterised list key", "foo; a\177a=1", 10, absl::nullopt},
- {"0x00 starting a parameterised list key", "foo; \000a=1", 9,
- absl::nullopt},
- {"0x01 starting a parameterised list key", "foo; \001a=1", 9,
- absl::nullopt},
- {"0x02 starting a parameterised list key", "foo; \002a=1", 9,
- absl::nullopt},
- {"0x03 starting a parameterised list key", "foo; \003a=1", 9,
- absl::nullopt},
- {"0x04 starting a parameterised list key", "foo; \004a=1", 9,
- absl::nullopt},
- {"0x05 starting a parameterised list key", "foo; \005a=1", 9,
- absl::nullopt},
- {"0x06 starting a parameterised list key", "foo; \006a=1", 9,
- absl::nullopt},
- {"0x07 starting a parameterised list key", "foo; \aa=1", 9, absl::nullopt},
- {"0x08 starting a parameterised list key", "foo; \ba=1", 9, absl::nullopt},
- {"0x09 starting a parameterised list key", "foo; \ta=1", 9, absl::nullopt},
- {"0x0a starting a parameterised list key", "foo; \na=1", 9, absl::nullopt},
- {"0x0b starting a parameterised list key", "foo; \va=1", 9, absl::nullopt},
- {"0x0c starting a parameterised list key", "foo; \fa=1", 9, absl::nullopt},
- {"0x0d starting a parameterised list key", "foo; \ra=1", 9, absl::nullopt},
- {"0x0e starting a parameterised list key", "foo; \016a=1", 9,
- absl::nullopt},
- {"0x0f starting a parameterised list key", "foo; \017a=1", 9,
- absl::nullopt},
- {"0x10 starting a parameterised list key", "foo; \020a=1", 9,
- absl::nullopt},
- {"0x11 starting a parameterised list key", "foo; \021a=1", 9,
- absl::nullopt},
- {"0x12 starting a parameterised list key", "foo; \022a=1", 9,
- absl::nullopt},
- {"0x13 starting a parameterised list key", "foo; \023a=1", 9,
- absl::nullopt},
- {"0x14 starting a parameterised list key", "foo; \024a=1", 9,
- absl::nullopt},
- {"0x15 starting a parameterised list key", "foo; \025a=1", 9,
- absl::nullopt},
- {"0x16 starting a parameterised list key", "foo; \026a=1", 9,
- absl::nullopt},
- {"0x17 starting a parameterised list key", "foo; \027a=1", 9,
- absl::nullopt},
- {"0x18 starting a parameterised list key", "foo; \030a=1", 9,
- absl::nullopt},
- {"0x19 starting a parameterised list key", "foo; \031a=1", 9,
- absl::nullopt},
- {"0x1a starting a parameterised list key", "foo; \032a=1", 9,
- absl::nullopt},
- {"0x1b starting a parameterised list key", "foo; \033a=1", 9,
- absl::nullopt},
- {"0x1c starting a parameterised list key", "foo; \034a=1", 9,
- absl::nullopt},
- {"0x1d starting a parameterised list key", "foo; \035a=1", 9,
- absl::nullopt},
- {"0x1e starting a parameterised list key", "foo; \036a=1", 9,
- absl::nullopt},
- {"0x1f starting a parameterised list key", "foo; \037a=1", 9,
- absl::nullopt},
- {"0x20 starting a parameterised list key",
- "foo; a=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("a", 1)}}}},
- "foo;a=1"},
- {"0x21 starting a parameterised list key", "foo; !a=1", 9, absl::nullopt},
- {"0x22 starting a parameterised list key", "foo; \"a=1", 9, absl::nullopt},
- {"0x23 starting a parameterised list key", "foo; #a=1", 9, absl::nullopt},
- {"0x24 starting a parameterised list key", "foo; $a=1", 9, absl::nullopt},
- {"0x25 starting a parameterised list key", "foo; %a=1", 9, absl::nullopt},
- {"0x26 starting a parameterised list key", "foo; &a=1", 9, absl::nullopt},
- {"0x27 starting a parameterised list key", "foo; 'a=1", 9, absl::nullopt},
- {"0x28 starting a parameterised list key", "foo; (a=1", 9, absl::nullopt},
- {"0x29 starting a parameterised list key", "foo; )a=1", 9, absl::nullopt},
- {"0x2a starting a parameterised list key",
- "foo; *a=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("*a", 1)}}}},
- "foo;*a=1"},
- {"0x2b starting a parameterised list key", "foo; +a=1", 9, absl::nullopt},
- {"0x2c starting a parameterised list key", "foo; ,a=1", 9, absl::nullopt},
- {"0x2d starting a parameterised list key", "foo; -a=1", 9, absl::nullopt},
- {"0x2e starting a parameterised list key", "foo; .a=1", 9, absl::nullopt},
- {"0x2f starting a parameterised list key", "foo; /a=1", 9, absl::nullopt},
- {"0x30 starting a parameterised list key", "foo; 0a=1", 9, absl::nullopt},
- {"0x31 starting a parameterised list key", "foo; 1a=1", 9, absl::nullopt},
- {"0x32 starting a parameterised list key", "foo; 2a=1", 9, absl::nullopt},
- {"0x33 starting a parameterised list key", "foo; 3a=1", 9, absl::nullopt},
- {"0x34 starting a parameterised list key", "foo; 4a=1", 9, absl::nullopt},
- {"0x35 starting a parameterised list key", "foo; 5a=1", 9, absl::nullopt},
- {"0x36 starting a parameterised list key", "foo; 6a=1", 9, absl::nullopt},
- {"0x37 starting a parameterised list key", "foo; 7a=1", 9, absl::nullopt},
- {"0x38 starting a parameterised list key", "foo; 8a=1", 9, absl::nullopt},
- {"0x39 starting a parameterised list key", "foo; 9a=1", 9, absl::nullopt},
- {"0x3a starting a parameterised list key", "foo; :a=1", 9, absl::nullopt},
- {"0x3b starting a parameterised list key", "foo; ;a=1", 9, absl::nullopt},
- {"0x3c starting a parameterised list key", "foo; <a=1", 9, absl::nullopt},
- {"0x3d starting a parameterised list key", "foo; =a=1", 9, absl::nullopt},
- {"0x3e starting a parameterised list key", "foo; >a=1", 9, absl::nullopt},
- {"0x3f starting a parameterised list key", "foo; ?a=1", 9, absl::nullopt},
- {"0x40 starting a parameterised list key", "foo; @a=1", 9, absl::nullopt},
- {"0x41 starting a parameterised list key", "foo; Aa=1", 9, absl::nullopt},
- {"0x42 starting a parameterised list key", "foo; Ba=1", 9, absl::nullopt},
- {"0x43 starting a parameterised list key", "foo; Ca=1", 9, absl::nullopt},
- {"0x44 starting a parameterised list key", "foo; Da=1", 9, absl::nullopt},
- {"0x45 starting a parameterised list key", "foo; Ea=1", 9, absl::nullopt},
- {"0x46 starting a parameterised list key", "foo; Fa=1", 9, absl::nullopt},
- {"0x47 starting a parameterised list key", "foo; Ga=1", 9, absl::nullopt},
- {"0x48 starting a parameterised list key", "foo; Ha=1", 9, absl::nullopt},
- {"0x49 starting a parameterised list key", "foo; Ia=1", 9, absl::nullopt},
- {"0x4a starting a parameterised list key", "foo; Ja=1", 9, absl::nullopt},
- {"0x4b starting a parameterised list key", "foo; Ka=1", 9, absl::nullopt},
- {"0x4c starting a parameterised list key", "foo; La=1", 9, absl::nullopt},
- {"0x4d starting a parameterised list key", "foo; Ma=1", 9, absl::nullopt},
- {"0x4e starting a parameterised list key", "foo; Na=1", 9, absl::nullopt},
- {"0x4f starting a parameterised list key", "foo; Oa=1", 9, absl::nullopt},
- {"0x50 starting a parameterised list key", "foo; Pa=1", 9, absl::nullopt},
- {"0x51 starting a parameterised list key", "foo; Qa=1", 9, absl::nullopt},
- {"0x52 starting a parameterised list key", "foo; Ra=1", 9, absl::nullopt},
- {"0x53 starting a parameterised list key", "foo; Sa=1", 9, absl::nullopt},
- {"0x54 starting a parameterised list key", "foo; Ta=1", 9, absl::nullopt},
- {"0x55 starting a parameterised list key", "foo; Ua=1", 9, absl::nullopt},
- {"0x56 starting a parameterised list key", "foo; Va=1", 9, absl::nullopt},
- {"0x57 starting a parameterised list key", "foo; Wa=1", 9, absl::nullopt},
- {"0x58 starting a parameterised list key", "foo; Xa=1", 9, absl::nullopt},
- {"0x59 starting a parameterised list key", "foo; Ya=1", 9, absl::nullopt},
- {"0x5a starting a parameterised list key", "foo; Za=1", 9, absl::nullopt},
- {"0x5b starting a parameterised list key", "foo; [a=1", 9, absl::nullopt},
- {"0x5c starting a parameterised list key", "foo; \\a=1", 9, absl::nullopt},
- {"0x5d starting a parameterised list key", "foo; ]a=1", 9, absl::nullopt},
- {"0x5e starting a parameterised list key", "foo; ^a=1", 9, absl::nullopt},
- {"0x5f starting a parameterised list key", "foo; _a=1", 9, absl::nullopt},
- {"0x60 starting a parameterised list key", "foo; `a=1", 9, absl::nullopt},
- {"0x61 starting a parameterised list key",
- "foo; aa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("aa", 1)}}}},
- "foo;aa=1"},
- {"0x62 starting a parameterised list key",
- "foo; ba=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ba", 1)}}}},
- "foo;ba=1"},
- {"0x63 starting a parameterised list key",
- "foo; ca=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ca", 1)}}}},
- "foo;ca=1"},
- {"0x64 starting a parameterised list key",
- "foo; da=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("da", 1)}}}},
- "foo;da=1"},
- {"0x65 starting a parameterised list key",
- "foo; ea=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ea", 1)}}}},
- "foo;ea=1"},
- {"0x66 starting a parameterised list key",
- "foo; fa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("fa", 1)}}}},
- "foo;fa=1"},
- {"0x67 starting a parameterised list key",
- "foo; ga=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ga", 1)}}}},
- "foo;ga=1"},
- {"0x68 starting a parameterised list key",
- "foo; ha=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ha", 1)}}}},
- "foo;ha=1"},
- {"0x69 starting a parameterised list key",
- "foo; ia=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ia", 1)}}}},
- "foo;ia=1"},
- {"0x6a starting a parameterised list key",
- "foo; ja=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ja", 1)}}}},
- "foo;ja=1"},
- {"0x6b starting a parameterised list key",
- "foo; ka=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ka", 1)}}}},
- "foo;ka=1"},
- {"0x6c starting a parameterised list key",
- "foo; la=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("la", 1)}}}},
- "foo;la=1"},
- {"0x6d starting a parameterised list key",
- "foo; ma=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ma", 1)}}}},
- "foo;ma=1"},
- {"0x6e starting a parameterised list key",
- "foo; na=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("na", 1)}}}},
- "foo;na=1"},
- {"0x6f starting a parameterised list key",
- "foo; oa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("oa", 1)}}}},
- "foo;oa=1"},
- {"0x70 starting a parameterised list key",
- "foo; pa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("pa", 1)}}}},
- "foo;pa=1"},
- {"0x71 starting a parameterised list key",
- "foo; qa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("qa", 1)}}}},
- "foo;qa=1"},
- {"0x72 starting a parameterised list key",
- "foo; ra=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ra", 1)}}}},
- "foo;ra=1"},
- {"0x73 starting a parameterised list key",
- "foo; sa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("sa", 1)}}}},
- "foo;sa=1"},
- {"0x74 starting a parameterised list key",
- "foo; ta=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ta", 1)}}}},
- "foo;ta=1"},
- {"0x75 starting a parameterised list key",
- "foo; ua=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ua", 1)}}}},
- "foo;ua=1"},
- {"0x76 starting a parameterised list key",
- "foo; va=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("va", 1)}}}},
- "foo;va=1"},
- {"0x77 starting a parameterised list key",
- "foo; wa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("wa", 1)}}}},
- "foo;wa=1"},
- {"0x78 starting a parameterised list key",
- "foo; xa=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("xa", 1)}}}},
- "foo;xa=1"},
- {"0x79 starting a parameterised list key",
- "foo; ya=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("ya", 1)}}}},
- "foo;ya=1"},
- {"0x7a starting a parameterised list key",
- "foo; za=1",
- 9,
- {{{Item("foo", Item::kTokenType), {Param("za", 1)}}}},
- "foo;za=1"},
- {"0x7b starting a parameterised list key", "foo; {a=1", 9, absl::nullopt},
- {"0x7c starting a parameterised list key", "foo; |a=1", 9, absl::nullopt},
- {"0x7d starting a parameterised list key", "foo; }a=1", 9, absl::nullopt},
- {"0x7e starting a parameterised list key", "foo; ~a=1", 9, absl::nullopt},
- {"0x7f starting a parameterised list key", "foo; \177a=1", 9,
- absl::nullopt},
- // list.json
- {"basic list", "1, 42", 5, {{{Integer(1), {}}, {Integer(42), {}}}}},
- {"empty list", "", 0, {List()}},
- {"leading SP list",
- " 42, 43",
- 8,
- {{{Integer(42), {}}, {Integer(43), {}}}},
- "42, 43"},
- {"single item list", "42", 2, {{{Integer(42), {}}}}},
- {"no whitespace list",
- "1,42",
- 4,
- {{{Integer(1), {}}, {Integer(42), {}}}},
- "1, 42"},
- {"extra whitespace list",
- "1 , 42",
- 6,
- {{{Integer(1), {}}, {Integer(42), {}}}},
- "1, 42"},
- {"tab separated list",
- "1\t,\t42",
- 6,
- {{{Integer(1), {}}, {Integer(42), {}}}},
- "1, 42"},
- {"two line list",
- "1, 42",
- 5,
- {{{Integer(1), {}}, {Integer(42), {}}}},
- "1, 42"},
- {"trailing comma list", "1, 42,", 6, absl::nullopt},
- {"empty item list", "1,,42", 5, absl::nullopt},
- {"empty item list (multiple field lines)", "1, , 42", 7, absl::nullopt},
- // listlist.json
- {"basic list of lists",
- "(1 2), (42 43)",
- 14,
- {{{{{Integer(1), {}}, {Integer(2), {}}}, {}},
- {{{Integer(42), {}}, {Integer(43), {}}}, {}}}}},
- {"single item list of lists", "(42)", 4, {{{{{Integer(42), {}}}, {}}}}},
- {"empty item list of lists",
- "()",
- 2,
- {{{std::vector<ParameterizedItem>(), {}}}}},
- {"empty middle item list of lists",
- "(1),(),(42)",
- 11,
- {{{{{Integer(1), {}}}, {}},
- {std::vector<ParameterizedItem>(), {}},
- {{{Integer(42), {}}}, {}}}},
- "(1), (), (42)"},
- {"extra whitespace list of lists",
- "( 1 42 )",
- 11,
- {{{{{Integer(1), {}}, {Integer(42), {}}}, {}}}},
- "(1 42)"},
- {"wrong whitespace list of lists", "(1\t 42)", 7, absl::nullopt},
- {"no trailing parenthesis list of lists", "(1 42", 5, absl::nullopt},
- {"no trailing parenthesis middle list of lists", "(1 2, (42 43)", 13,
- absl::nullopt},
- {"no spaces in inner-list", "(abc\"def\"?0123*dXZ3*xyz)", 24,
- absl::nullopt},
- {"no closing parenthesis", "(", 1, absl::nullopt},
- // param-list.json
- {"basic parameterised list",
- "abc_123;a=1;b=2; cdef_456, ghi;q=9;r=\"+w\"",
- 41,
- {{{Item("abc_123", Item::kTokenType),
- {Param("a", 1), Param("b", 2), BooleanParam("cdef_456", true)}},
- {Item("ghi", Item::kTokenType), {Param("q", 9), Param("r", "+w")}}}},
- "abc_123;a=1;b=2;cdef_456, ghi;q=9;r=\"+w\""},
- {"single item parameterised list",
- "text/html;q=1.0",
- 15,
- {{{Item("text/html", Item::kTokenType), {DoubleParam("q", 1.000000)}}}}},
- {"missing parameter value parameterised list",
- "text/html;a;q=1.0",
- 17,
- {{{Item("text/html", Item::kTokenType),
- {BooleanParam("a", true), DoubleParam("q", 1.000000)}}}}},
- {"missing terminal parameter value parameterised list",
- "text/html;q=1.0;a",
- 17,
- {{{Item("text/html", Item::kTokenType),
- {DoubleParam("q", 1.000000), BooleanParam("a", true)}}}}},
- {"no whitespace parameterised list",
- "text/html,text/plain;q=0.5",
- 26,
- {{{Item("text/html", Item::kTokenType), {}},
- {Item("text/plain", Item::kTokenType), {DoubleParam("q", 0.500000)}}}},
- "text/html, text/plain;q=0.5"},
- {"whitespace before = parameterised list", "text/html, text/plain;q =0.5",
- 28, absl::nullopt},
- {"whitespace after = parameterised list", "text/html, text/plain;q= 0.5",
- 28, absl::nullopt},
- {"whitespace before ; parameterised list", "text/html, text/plain ;q=0.5",
- 28, absl::nullopt},
- {"whitespace after ; parameterised list",
- "text/html, text/plain; q=0.5",
- 28,
- {{{Item("text/html", Item::kTokenType), {}},
- {Item("text/plain", Item::kTokenType), {DoubleParam("q", 0.500000)}}}},
- "text/html, text/plain;q=0.5"},
- {"extra whitespace parameterised list",
- "text/html , text/plain; q=0.5; charset=utf-8",
- 48,
- {{{Item("text/html", Item::kTokenType), {}},
- {Item("text/plain", Item::kTokenType),
- {DoubleParam("q", 0.500000), TokenParam("charset", "utf-8")}}}},
- "text/html, text/plain;q=0.5;charset=utf-8"},
- {"two lines parameterised list",
- "text/html, text/plain;q=0.5",
- 27,
- {{{Item("text/html", Item::kTokenType), {}},
- {Item("text/plain", Item::kTokenType), {DoubleParam("q", 0.500000)}}}},
- "text/html, text/plain;q=0.5"},
- {"trailing comma parameterised list", "text/html,text/plain;q=0.5,", 27,
- absl::nullopt},
- {"empty item parameterised list", "text/html,,text/plain;q=0.5,", 28,
- absl::nullopt},
- // param-listlist.json
- {"parameterised inner list",
- "(abc_123);a=1;b=2, cdef_456",
- 27,
- {{{{{Item("abc_123", Item::kTokenType), {}}},
- {Param("a", 1), Param("b", 2)}},
- {Item("cdef_456", Item::kTokenType), {}}}}},
- {"parameterised inner list item",
- "(abc_123;a=1;b=2;cdef_456)",
- 26,
- {{{{{Item("abc_123", Item::kTokenType),
- {Param("a", 1), Param("b", 2), BooleanParam("cdef_456", true)}}},
- {}}}}},
- {"parameterised inner list with parameterised item",
- "(abc_123;a=1;b=2);cdef_456",
- 26,
- {{{{{Item("abc_123", Item::kTokenType), {Param("a", 1), Param("b", 2)}}},
- {BooleanParam("cdef_456", true)}}}}},
- // token.json
- {"basic token - list",
- "a_b-c3/*",
- 8,
- {{{Item("a_b-c3/*", Item::kTokenType), {}}}}},
- {"token with capitals - list",
- "fooBar",
- 6,
- {{{Item("fooBar", Item::kTokenType), {}}}}},
- {"token starting with capitals - list",
- "FooBar",
- 6,
- {{{Item("FooBar", Item::kTokenType), {}}}}},
-};
-
-const struct DictionaryTestCase {
- const char* name;
- const char* raw;
- size_t raw_len;
- const absl::optional<Dictionary>
- expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} dictionary_test_cases[] = {
-
- // dictionary.json
- {"basic dictionary",
- "en=\"Applepie\", da=:w4ZibGV0w6ZydGUK:",
- 36,
- {Dictionary{{{"en", {Item("Applepie"), {}}},
- {"da",
- {Item("\303\206blet\303\246rte\n", Item::kByteSequenceType),
- {}}}}}}},
- {"empty dictionary", "", 0, {Dictionary{{}}}},
- {"single item dictionary",
- "a=1",
- 3,
- {Dictionary{{{"a", {Integer(1), {}}}}}}},
- {"list item dictionary",
- "a=(1 2)",
- 7,
- {Dictionary{{{"a", {{{Integer(1), {}}, {Integer(2), {}}}, {}}}}}}},
- {"single list item dictionary",
- "a=(1)",
- 5,
- {Dictionary{{{"a", {{{Integer(1), {}}}, {}}}}}}},
- {"empty list item dictionary",
- "a=()",
- 4,
- {Dictionary{{{"a", {std::vector<ParameterizedItem>(), {}}}}}}},
- {"no whitespace dictionary",
- "a=1,b=2",
- 7,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Integer(2), {}}}}}},
- "a=1, b=2"},
- {"extra whitespace dictionary",
- "a=1 , b=2",
- 10,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Integer(2), {}}}}}},
- "a=1, b=2"},
- {"tab separated dictionary",
- "a=1\t,\tb=2",
- 9,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Integer(2), {}}}}}},
- "a=1, b=2"},
- {"leading whitespace dictionary",
- " a=1 , b=2",
- 15,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Integer(2), {}}}}}},
- "a=1, b=2"},
- {"whitespace before = dictionary", "a =1, b=2", 9, absl::nullopt},
- {"whitespace after = dictionary", "a=1, b= 2", 9, absl::nullopt},
- {"two lines dictionary",
- "a=1, b=2",
- 8,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Integer(2), {}}}}}},
- "a=1, b=2"},
- {"missing value dictionary",
- "a=1, b, c=3",
- 11,
- {Dictionary{{{"a", {Integer(1), {}}},
- {"b", {Item(true), {}}},
- {"c", {Integer(3), {}}}}}}},
- {"all missing value dictionary",
- "a, b, c",
- 7,
- {Dictionary{{{"a", {Item(true), {}}},
- {"b", {Item(true), {}}},
- {"c", {Item(true), {}}}}}}},
- {"start missing value dictionary",
- "a, b=2",
- 6,
- {Dictionary{{{"a", {Item(true), {}}}, {"b", {Integer(2), {}}}}}}},
- {"end missing value dictionary",
- "a=1, b",
- 6,
- {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Item(true), {}}}}}}},
- {"missing value with params dictionary",
- "a=1, b;foo=9, c=3",
- 17,
- {Dictionary{{{"a", {Integer(1), {}}},
- {"b", {Item(true), {Param("foo", 9)}}},
- {"c", {Integer(3), {}}}}}}},
- {"explicit true value with params dictionary",
- "a=1, b=?1;foo=9, c=3",
- 20,
- {Dictionary{{{"a", {Integer(1), {}}},
- {"b", {Item(true), {Param("foo", 9)}}},
- {"c", {Integer(3), {}}}}}},
- "a=1, b;foo=9, c=3"},
- {"trailing comma dictionary", "a=1, b=2,", 9, absl::nullopt},
- {"empty item dictionary", "a=1,,b=2,", 9, absl::nullopt},
- {"duplicate key dictionary",
- "a=1,b=2,a=3",
- 11,
- {Dictionary{{{"a", {Integer(3), {}}}, {"b", {Integer(2), {}}}}}},
- "a=3, b=2"},
- {"numeric key dictionary", "a=1,1b=2,a=1", 12, absl::nullopt},
- {"uppercase key dictionary", "a=1,B=2,a=1", 11, absl::nullopt},
- {"bad key dictionary", "a=1,b!=2,a=1", 12, absl::nullopt},
- // examples.json
- {"Example-DictHeader",
- "en=\"Applepie\", da=:w4ZibGV0w6ZydGU=:",
- 36,
- {Dictionary{
- {{"en", {Item("Applepie"), {}}},
- {"da",
- {Item("\303\206blet\303\246rte", Item::kByteSequenceType), {}}}}}}},
- {"Example-DictHeader",
- "a=?0, b, c; foo=bar",
- 19,
- {Dictionary{{{"a", {Item(false), {}}},
- {"b", {Item(true), {}}},
- {"c", {Item(true), {TokenParam("foo", "bar")}}}}}},
- "a=?0, b, c;foo=bar"},
- {"Example-DictListHeader",
- "rating=1.5, feelings=(joy sadness)",
- 34,
- {Dictionary{{{"rating", {Item(1.500000), {}}},
- {"feelings",
- {{{Item("joy", Item::kTokenType), {}},
- {Item("sadness", Item::kTokenType), {}}},
- {}}}}}}},
- {"Example-MixDict",
- "a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid",
- 38,
- {Dictionary{{{"a", {{{Integer(1), {}}, {Integer(2), {}}}, {}}},
- {"b", {Integer(3), {}}},
- {"c", {Integer(4), {TokenParam("aa", "bb")}}},
- {"d",
- {{{Integer(5), {}}, {Integer(6), {}}},
- {BooleanParam("valid", true)}}}}}},
- "a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid"},
- {"Example-Hdr (dictionary on one line)",
- "foo=1, bar=2",
- 12,
- {Dictionary{{{"foo", {Integer(1), {}}}, {"bar", {Integer(2), {}}}}}}},
- {"Example-Hdr (dictionary on two lines)",
- "foo=1, bar=2",
- 12,
- {Dictionary{{{"foo", {Integer(1), {}}}, {"bar", {Integer(2), {}}}}}},
- "foo=1, bar=2"},
- // key-generated.json
- {"0x00 as a single-character dictionary key", "\000=1", 3, absl::nullopt},
- {"0x01 as a single-character dictionary key", "\001=1", 3, absl::nullopt},
- {"0x02 as a single-character dictionary key", "\002=1", 3, absl::nullopt},
- {"0x03 as a single-character dictionary key", "\003=1", 3, absl::nullopt},
- {"0x04 as a single-character dictionary key", "\004=1", 3, absl::nullopt},
- {"0x05 as a single-character dictionary key", "\005=1", 3, absl::nullopt},
- {"0x06 as a single-character dictionary key", "\006=1", 3, absl::nullopt},
- {"0x07 as a single-character dictionary key", "\a=1", 3, absl::nullopt},
- {"0x08 as a single-character dictionary key", "\b=1", 3, absl::nullopt},
- {"0x09 as a single-character dictionary key", "\t=1", 3, absl::nullopt},
- {"0x0a as a single-character dictionary key", "\n=1", 3, absl::nullopt},
- {"0x0b as a single-character dictionary key", "\v=1", 3, absl::nullopt},
- {"0x0c as a single-character dictionary key", "\f=1", 3, absl::nullopt},
- {"0x0d as a single-character dictionary key", "\r=1", 3, absl::nullopt},
- {"0x0e as a single-character dictionary key", "\016=1", 3, absl::nullopt},
- {"0x0f as a single-character dictionary key", "\017=1", 3, absl::nullopt},
- {"0x10 as a single-character dictionary key", "\020=1", 3, absl::nullopt},
- {"0x11 as a single-character dictionary key", "\021=1", 3, absl::nullopt},
- {"0x12 as a single-character dictionary key", "\022=1", 3, absl::nullopt},
- {"0x13 as a single-character dictionary key", "\023=1", 3, absl::nullopt},
- {"0x14 as a single-character dictionary key", "\024=1", 3, absl::nullopt},
- {"0x15 as a single-character dictionary key", "\025=1", 3, absl::nullopt},
- {"0x16 as a single-character dictionary key", "\026=1", 3, absl::nullopt},
- {"0x17 as a single-character dictionary key", "\027=1", 3, absl::nullopt},
- {"0x18 as a single-character dictionary key", "\030=1", 3, absl::nullopt},
- {"0x19 as a single-character dictionary key", "\031=1", 3, absl::nullopt},
- {"0x1a as a single-character dictionary key", "\032=1", 3, absl::nullopt},
- {"0x1b as a single-character dictionary key", "\033=1", 3, absl::nullopt},
- {"0x1c as a single-character dictionary key", "\034=1", 3, absl::nullopt},
- {"0x1d as a single-character dictionary key", "\035=1", 3, absl::nullopt},
- {"0x1e as a single-character dictionary key", "\036=1", 3, absl::nullopt},
- {"0x1f as a single-character dictionary key", "\037=1", 3, absl::nullopt},
- {"0x20 as a single-character dictionary key", "=1", 2, absl::nullopt},
- {"0x21 as a single-character dictionary key", "!=1", 3, absl::nullopt},
- {"0x22 as a single-character dictionary key", "\"=1", 3, absl::nullopt},
- {"0x23 as a single-character dictionary key", "#=1", 3, absl::nullopt},
- {"0x24 as a single-character dictionary key", "$=1", 3, absl::nullopt},
- {"0x25 as a single-character dictionary key", "%=1", 3, absl::nullopt},
- {"0x26 as a single-character dictionary key", "&=1", 3, absl::nullopt},
- {"0x27 as a single-character dictionary key", "'=1", 3, absl::nullopt},
- {"0x28 as a single-character dictionary key", "(=1", 3, absl::nullopt},
- {"0x29 as a single-character dictionary key", ")=1", 3, absl::nullopt},
- {"0x2a as a single-character dictionary key",
- "*=1",
- 3,
- {Dictionary{{{"*", {Integer(1), {}}}}}}},
- {"0x2b as a single-character dictionary key", "+=1", 3, absl::nullopt},
- {"0x2c as a single-character dictionary key", ",=1", 3, absl::nullopt},
- {"0x2d as a single-character dictionary key", "-=1", 3, absl::nullopt},
- {"0x2e as a single-character dictionary key", ".=1", 3, absl::nullopt},
- {"0x2f as a single-character dictionary key", "/=1", 3, absl::nullopt},
- {"0x30 as a single-character dictionary key", "0=1", 3, absl::nullopt},
- {"0x31 as a single-character dictionary key", "1=1", 3, absl::nullopt},
- {"0x32 as a single-character dictionary key", "2=1", 3, absl::nullopt},
- {"0x33 as a single-character dictionary key", "3=1", 3, absl::nullopt},
- {"0x34 as a single-character dictionary key", "4=1", 3, absl::nullopt},
- {"0x35 as a single-character dictionary key", "5=1", 3, absl::nullopt},
- {"0x36 as a single-character dictionary key", "6=1", 3, absl::nullopt},
- {"0x37 as a single-character dictionary key", "7=1", 3, absl::nullopt},
- {"0x38 as a single-character dictionary key", "8=1", 3, absl::nullopt},
- {"0x39 as a single-character dictionary key", "9=1", 3, absl::nullopt},
- {"0x3a as a single-character dictionary key", ":=1", 3, absl::nullopt},
- {"0x3b as a single-character dictionary key", ";=1", 3, absl::nullopt},
- {"0x3c as a single-character dictionary key", "<=1", 3, absl::nullopt},
- {"0x3d as a single-character dictionary key", "==1", 3, absl::nullopt},
- {"0x3e as a single-character dictionary key", ">=1", 3, absl::nullopt},
- {"0x3f as a single-character dictionary key", "?=1", 3, absl::nullopt},
- {"0x40 as a single-character dictionary key", "@=1", 3, absl::nullopt},
- {"0x41 as a single-character dictionary key", "A=1", 3, absl::nullopt},
- {"0x42 as a single-character dictionary key", "B=1", 3, absl::nullopt},
- {"0x43 as a single-character dictionary key", "C=1", 3, absl::nullopt},
- {"0x44 as a single-character dictionary key", "D=1", 3, absl::nullopt},
- {"0x45 as a single-character dictionary key", "E=1", 3, absl::nullopt},
- {"0x46 as a single-character dictionary key", "F=1", 3, absl::nullopt},
- {"0x47 as a single-character dictionary key", "G=1", 3, absl::nullopt},
- {"0x48 as a single-character dictionary key", "H=1", 3, absl::nullopt},
- {"0x49 as a single-character dictionary key", "I=1", 3, absl::nullopt},
- {"0x4a as a single-character dictionary key", "J=1", 3, absl::nullopt},
- {"0x4b as a single-character dictionary key", "K=1", 3, absl::nullopt},
- {"0x4c as a single-character dictionary key", "L=1", 3, absl::nullopt},
- {"0x4d as a single-character dictionary key", "M=1", 3, absl::nullopt},
- {"0x4e as a single-character dictionary key", "N=1", 3, absl::nullopt},
- {"0x4f as a single-character dictionary key", "O=1", 3, absl::nullopt},
- {"0x50 as a single-character dictionary key", "P=1", 3, absl::nullopt},
- {"0x51 as a single-character dictionary key", "Q=1", 3, absl::nullopt},
- {"0x52 as a single-character dictionary key", "R=1", 3, absl::nullopt},
- {"0x53 as a single-character dictionary key", "S=1", 3, absl::nullopt},
- {"0x54 as a single-character dictionary key", "T=1", 3, absl::nullopt},
- {"0x55 as a single-character dictionary key", "U=1", 3, absl::nullopt},
- {"0x56 as a single-character dictionary key", "V=1", 3, absl::nullopt},
- {"0x57 as a single-character dictionary key", "W=1", 3, absl::nullopt},
- {"0x58 as a single-character dictionary key", "X=1", 3, absl::nullopt},
- {"0x59 as a single-character dictionary key", "Y=1", 3, absl::nullopt},
- {"0x5a as a single-character dictionary key", "Z=1", 3, absl::nullopt},
- {"0x5b as a single-character dictionary key", "[=1", 3, absl::nullopt},
- {"0x5c as a single-character dictionary key", "\\=1", 3, absl::nullopt},
- {"0x5d as a single-character dictionary key", "]=1", 3, absl::nullopt},
- {"0x5e as a single-character dictionary key", "^=1", 3, absl::nullopt},
- {"0x5f as a single-character dictionary key", "_=1", 3, absl::nullopt},
- {"0x60 as a single-character dictionary key", "`=1", 3, absl::nullopt},
- {"0x61 as a single-character dictionary key",
- "a=1",
- 3,
- {Dictionary{{{"a", {Integer(1), {}}}}}}},
- {"0x62 as a single-character dictionary key",
- "b=1",
- 3,
- {Dictionary{{{"b", {Integer(1), {}}}}}}},
- {"0x63 as a single-character dictionary key",
- "c=1",
- 3,
- {Dictionary{{{"c", {Integer(1), {}}}}}}},
- {"0x64 as a single-character dictionary key",
- "d=1",
- 3,
- {Dictionary{{{"d", {Integer(1), {}}}}}}},
- {"0x65 as a single-character dictionary key",
- "e=1",
- 3,
- {Dictionary{{{"e", {Integer(1), {}}}}}}},
- {"0x66 as a single-character dictionary key",
- "f=1",
- 3,
- {Dictionary{{{"f", {Integer(1), {}}}}}}},
- {"0x67 as a single-character dictionary key",
- "g=1",
- 3,
- {Dictionary{{{"g", {Integer(1), {}}}}}}},
- {"0x68 as a single-character dictionary key",
- "h=1",
- 3,
- {Dictionary{{{"h", {Integer(1), {}}}}}}},
- {"0x69 as a single-character dictionary key",
- "i=1",
- 3,
- {Dictionary{{{"i", {Integer(1), {}}}}}}},
- {"0x6a as a single-character dictionary key",
- "j=1",
- 3,
- {Dictionary{{{"j", {Integer(1), {}}}}}}},
- {"0x6b as a single-character dictionary key",
- "k=1",
- 3,
- {Dictionary{{{"k", {Integer(1), {}}}}}}},
- {"0x6c as a single-character dictionary key",
- "l=1",
- 3,
- {Dictionary{{{"l", {Integer(1), {}}}}}}},
- {"0x6d as a single-character dictionary key",
- "m=1",
- 3,
- {Dictionary{{{"m", {Integer(1), {}}}}}}},
- {"0x6e as a single-character dictionary key",
- "n=1",
- 3,
- {Dictionary{{{"n", {Integer(1), {}}}}}}},
- {"0x6f as a single-character dictionary key",
- "o=1",
- 3,
- {Dictionary{{{"o", {Integer(1), {}}}}}}},
- {"0x70 as a single-character dictionary key",
- "p=1",
- 3,
- {Dictionary{{{"p", {Integer(1), {}}}}}}},
- {"0x71 as a single-character dictionary key",
- "q=1",
- 3,
- {Dictionary{{{"q", {Integer(1), {}}}}}}},
- {"0x72 as a single-character dictionary key",
- "r=1",
- 3,
- {Dictionary{{{"r", {Integer(1), {}}}}}}},
- {"0x73 as a single-character dictionary key",
- "s=1",
- 3,
- {Dictionary{{{"s", {Integer(1), {}}}}}}},
- {"0x74 as a single-character dictionary key",
- "t=1",
- 3,
- {Dictionary{{{"t", {Integer(1), {}}}}}}},
- {"0x75 as a single-character dictionary key",
- "u=1",
- 3,
- {Dictionary{{{"u", {Integer(1), {}}}}}}},
- {"0x76 as a single-character dictionary key",
- "v=1",
- 3,
- {Dictionary{{{"v", {Integer(1), {}}}}}}},
- {"0x77 as a single-character dictionary key",
- "w=1",
- 3,
- {Dictionary{{{"w", {Integer(1), {}}}}}}},
- {"0x78 as a single-character dictionary key",
- "x=1",
- 3,
- {Dictionary{{{"x", {Integer(1), {}}}}}}},
- {"0x79 as a single-character dictionary key",
- "y=1",
- 3,
- {Dictionary{{{"y", {Integer(1), {}}}}}}},
- {"0x7a as a single-character dictionary key",
- "z=1",
- 3,
- {Dictionary{{{"z", {Integer(1), {}}}}}}},
- {"0x7b as a single-character dictionary key", "{=1", 3, absl::nullopt},
- {"0x7c as a single-character dictionary key", "|=1", 3, absl::nullopt},
- {"0x7d as a single-character dictionary key", "}=1", 3, absl::nullopt},
- {"0x7e as a single-character dictionary key", "~=1", 3, absl::nullopt},
- {"0x7f as a single-character dictionary key", "\177=1", 3, absl::nullopt},
- {"0x00 in dictionary key", "a\000a=1", 5, absl::nullopt},
- {"0x01 in dictionary key", "a\001a=1", 5, absl::nullopt},
- {"0x02 in dictionary key", "a\002a=1", 5, absl::nullopt},
- {"0x03 in dictionary key", "a\003a=1", 5, absl::nullopt},
- {"0x04 in dictionary key", "a\004a=1", 5, absl::nullopt},
- {"0x05 in dictionary key", "a\005a=1", 5, absl::nullopt},
- {"0x06 in dictionary key", "a\006a=1", 5, absl::nullopt},
- {"0x07 in dictionary key", "a\aa=1", 5, absl::nullopt},
- {"0x08 in dictionary key", "a\ba=1", 5, absl::nullopt},
- {"0x09 in dictionary key", "a\ta=1", 5, absl::nullopt},
- {"0x0a in dictionary key", "a\na=1", 5, absl::nullopt},
- {"0x0b in dictionary key", "a\va=1", 5, absl::nullopt},
- {"0x0c in dictionary key", "a\fa=1", 5, absl::nullopt},
- {"0x0d in dictionary key", "a\ra=1", 5, absl::nullopt},
- {"0x0e in dictionary key", "a\016a=1", 5, absl::nullopt},
- {"0x0f in dictionary key", "a\017a=1", 5, absl::nullopt},
- {"0x10 in dictionary key", "a\020a=1", 5, absl::nullopt},
- {"0x11 in dictionary key", "a\021a=1", 5, absl::nullopt},
- {"0x12 in dictionary key", "a\022a=1", 5, absl::nullopt},
- {"0x13 in dictionary key", "a\023a=1", 5, absl::nullopt},
- {"0x14 in dictionary key", "a\024a=1", 5, absl::nullopt},
- {"0x15 in dictionary key", "a\025a=1", 5, absl::nullopt},
- {"0x16 in dictionary key", "a\026a=1", 5, absl::nullopt},
- {"0x17 in dictionary key", "a\027a=1", 5, absl::nullopt},
- {"0x18 in dictionary key", "a\030a=1", 5, absl::nullopt},
- {"0x19 in dictionary key", "a\031a=1", 5, absl::nullopt},
- {"0x1a in dictionary key", "a\032a=1", 5, absl::nullopt},
- {"0x1b in dictionary key", "a\033a=1", 5, absl::nullopt},
- {"0x1c in dictionary key", "a\034a=1", 5, absl::nullopt},
- {"0x1d in dictionary key", "a\035a=1", 5, absl::nullopt},
- {"0x1e in dictionary key", "a\036a=1", 5, absl::nullopt},
- {"0x1f in dictionary key", "a\037a=1", 5, absl::nullopt},
- {"0x20 in dictionary key", "a a=1", 5, absl::nullopt},
- {"0x21 in dictionary key", "a!a=1", 5, absl::nullopt},
- {"0x22 in dictionary key", "a\"a=1", 5, absl::nullopt},
- {"0x23 in dictionary key", "a#a=1", 5, absl::nullopt},
- {"0x24 in dictionary key", "a$a=1", 5, absl::nullopt},
- {"0x25 in dictionary key", "a%a=1", 5, absl::nullopt},
- {"0x26 in dictionary key", "a&a=1", 5, absl::nullopt},
- {"0x27 in dictionary key", "a'a=1", 5, absl::nullopt},
- {"0x28 in dictionary key", "a(a=1", 5, absl::nullopt},
- {"0x29 in dictionary key", "a)a=1", 5, absl::nullopt},
- {"0x2a in dictionary key",
- "a*a=1",
- 5,
- {Dictionary{{{"a*a", {Integer(1), {}}}}}}},
- {"0x2b in dictionary key", "a+a=1", 5, absl::nullopt},
- {"0x2c in dictionary key",
- "a,a=1",
- 5,
- {Dictionary{{{"a", {Integer(1), {}}}}}},
- "a=1"},
- {"0x2d in dictionary key",
- "a-a=1",
- 5,
- {Dictionary{{{"a-a", {Integer(1), {}}}}}}},
- {"0x2e in dictionary key",
- "a.a=1",
- 5,
- {Dictionary{{{"a.a", {Integer(1), {}}}}}}},
- {"0x2f in dictionary key", "a/a=1", 5, absl::nullopt},
- {"0x30 in dictionary key",
- "a0a=1",
- 5,
- {Dictionary{{{"a0a", {Integer(1), {}}}}}}},
- {"0x31 in dictionary key",
- "a1a=1",
- 5,
- {Dictionary{{{"a1a", {Integer(1), {}}}}}}},
- {"0x32 in dictionary key",
- "a2a=1",
- 5,
- {Dictionary{{{"a2a", {Integer(1), {}}}}}}},
- {"0x33 in dictionary key",
- "a3a=1",
- 5,
- {Dictionary{{{"a3a", {Integer(1), {}}}}}}},
- {"0x34 in dictionary key",
- "a4a=1",
- 5,
- {Dictionary{{{"a4a", {Integer(1), {}}}}}}},
- {"0x35 in dictionary key",
- "a5a=1",
- 5,
- {Dictionary{{{"a5a", {Integer(1), {}}}}}}},
- {"0x36 in dictionary key",
- "a6a=1",
- 5,
- {Dictionary{{{"a6a", {Integer(1), {}}}}}}},
- {"0x37 in dictionary key",
- "a7a=1",
- 5,
- {Dictionary{{{"a7a", {Integer(1), {}}}}}}},
- {"0x38 in dictionary key",
- "a8a=1",
- 5,
- {Dictionary{{{"a8a", {Integer(1), {}}}}}}},
- {"0x39 in dictionary key",
- "a9a=1",
- 5,
- {Dictionary{{{"a9a", {Integer(1), {}}}}}}},
- {"0x3a in dictionary key", "a:a=1", 5, absl::nullopt},
- {"0x3b in dictionary key",
- "a;a=1",
- 5,
- {Dictionary{{{"a", {Item(true), {Param("a", 1)}}}}}}},
- {"0x3c in dictionary key", "a<a=1", 5, absl::nullopt},
- {"0x3d in dictionary key", "a=a=1", 5, absl::nullopt},
- {"0x3e in dictionary key", "a>a=1", 5, absl::nullopt},
- {"0x3f in dictionary key", "a?a=1", 5, absl::nullopt},
- {"0x40 in dictionary key", "a@a=1", 5, absl::nullopt},
- {"0x41 in dictionary key", "aAa=1", 5, absl::nullopt},
- {"0x42 in dictionary key", "aBa=1", 5, absl::nullopt},
- {"0x43 in dictionary key", "aCa=1", 5, absl::nullopt},
- {"0x44 in dictionary key", "aDa=1", 5, absl::nullopt},
- {"0x45 in dictionary key", "aEa=1", 5, absl::nullopt},
- {"0x46 in dictionary key", "aFa=1", 5, absl::nullopt},
- {"0x47 in dictionary key", "aGa=1", 5, absl::nullopt},
- {"0x48 in dictionary key", "aHa=1", 5, absl::nullopt},
- {"0x49 in dictionary key", "aIa=1", 5, absl::nullopt},
- {"0x4a in dictionary key", "aJa=1", 5, absl::nullopt},
- {"0x4b in dictionary key", "aKa=1", 5, absl::nullopt},
- {"0x4c in dictionary key", "aLa=1", 5, absl::nullopt},
- {"0x4d in dictionary key", "aMa=1", 5, absl::nullopt},
- {"0x4e in dictionary key", "aNa=1", 5, absl::nullopt},
- {"0x4f in dictionary key", "aOa=1", 5, absl::nullopt},
- {"0x50 in dictionary key", "aPa=1", 5, absl::nullopt},
- {"0x51 in dictionary key", "aQa=1", 5, absl::nullopt},
- {"0x52 in dictionary key", "aRa=1", 5, absl::nullopt},
- {"0x53 in dictionary key", "aSa=1", 5, absl::nullopt},
- {"0x54 in dictionary key", "aTa=1", 5, absl::nullopt},
- {"0x55 in dictionary key", "aUa=1", 5, absl::nullopt},
- {"0x56 in dictionary key", "aVa=1", 5, absl::nullopt},
- {"0x57 in dictionary key", "aWa=1", 5, absl::nullopt},
- {"0x58 in dictionary key", "aXa=1", 5, absl::nullopt},
- {"0x59 in dictionary key", "aYa=1", 5, absl::nullopt},
- {"0x5a in dictionary key", "aZa=1", 5, absl::nullopt},
- {"0x5b in dictionary key", "a[a=1", 5, absl::nullopt},
- {"0x5c in dictionary key", "a\\a=1", 5, absl::nullopt},
- {"0x5d in dictionary key", "a]a=1", 5, absl::nullopt},
- {"0x5e in dictionary key", "a^a=1", 5, absl::nullopt},
- {"0x5f in dictionary key",
- "a_a=1",
- 5,
- {Dictionary{{{"a_a", {Integer(1), {}}}}}}},
- {"0x60 in dictionary key", "a`a=1", 5, absl::nullopt},
- {"0x61 in dictionary key",
- "aaa=1",
- 5,
- {Dictionary{{{"aaa", {Integer(1), {}}}}}}},
- {"0x62 in dictionary key",
- "aba=1",
- 5,
- {Dictionary{{{"aba", {Integer(1), {}}}}}}},
- {"0x63 in dictionary key",
- "aca=1",
- 5,
- {Dictionary{{{"aca", {Integer(1), {}}}}}}},
- {"0x64 in dictionary key",
- "ada=1",
- 5,
- {Dictionary{{{"ada", {Integer(1), {}}}}}}},
- {"0x65 in dictionary key",
- "aea=1",
- 5,
- {Dictionary{{{"aea", {Integer(1), {}}}}}}},
- {"0x66 in dictionary key",
- "afa=1",
- 5,
- {Dictionary{{{"afa", {Integer(1), {}}}}}}},
- {"0x67 in dictionary key",
- "aga=1",
- 5,
- {Dictionary{{{"aga", {Integer(1), {}}}}}}},
- {"0x68 in dictionary key",
- "aha=1",
- 5,
- {Dictionary{{{"aha", {Integer(1), {}}}}}}},
- {"0x69 in dictionary key",
- "aia=1",
- 5,
- {Dictionary{{{"aia", {Integer(1), {}}}}}}},
- {"0x6a in dictionary key",
- "aja=1",
- 5,
- {Dictionary{{{"aja", {Integer(1), {}}}}}}},
- {"0x6b in dictionary key",
- "aka=1",
- 5,
- {Dictionary{{{"aka", {Integer(1), {}}}}}}},
- {"0x6c in dictionary key",
- "ala=1",
- 5,
- {Dictionary{{{"ala", {Integer(1), {}}}}}}},
- {"0x6d in dictionary key",
- "ama=1",
- 5,
- {Dictionary{{{"ama", {Integer(1), {}}}}}}},
- {"0x6e in dictionary key",
- "ana=1",
- 5,
- {Dictionary{{{"ana", {Integer(1), {}}}}}}},
- {"0x6f in dictionary key",
- "aoa=1",
- 5,
- {Dictionary{{{"aoa", {Integer(1), {}}}}}}},
- {"0x70 in dictionary key",
- "apa=1",
- 5,
- {Dictionary{{{"apa", {Integer(1), {}}}}}}},
- {"0x71 in dictionary key",
- "aqa=1",
- 5,
- {Dictionary{{{"aqa", {Integer(1), {}}}}}}},
- {"0x72 in dictionary key",
- "ara=1",
- 5,
- {Dictionary{{{"ara", {Integer(1), {}}}}}}},
- {"0x73 in dictionary key",
- "asa=1",
- 5,
- {Dictionary{{{"asa", {Integer(1), {}}}}}}},
- {"0x74 in dictionary key",
- "ata=1",
- 5,
- {Dictionary{{{"ata", {Integer(1), {}}}}}}},
- {"0x75 in dictionary key",
- "aua=1",
- 5,
- {Dictionary{{{"aua", {Integer(1), {}}}}}}},
- {"0x76 in dictionary key",
- "ava=1",
- 5,
- {Dictionary{{{"ava", {Integer(1), {}}}}}}},
- {"0x77 in dictionary key",
- "awa=1",
- 5,
- {Dictionary{{{"awa", {Integer(1), {}}}}}}},
- {"0x78 in dictionary key",
- "axa=1",
- 5,
- {Dictionary{{{"axa", {Integer(1), {}}}}}}},
- {"0x79 in dictionary key",
- "aya=1",
- 5,
- {Dictionary{{{"aya", {Integer(1), {}}}}}}},
- {"0x7a in dictionary key",
- "aza=1",
- 5,
- {Dictionary{{{"aza", {Integer(1), {}}}}}}},
- {"0x7b in dictionary key", "a{a=1", 5, absl::nullopt},
- {"0x7c in dictionary key", "a|a=1", 5, absl::nullopt},
- {"0x7d in dictionary key", "a}a=1", 5, absl::nullopt},
- {"0x7e in dictionary key", "a~a=1", 5, absl::nullopt},
- {"0x7f in dictionary key", "a\177a=1", 5, absl::nullopt},
- {"0x00 starting an dictionary key", "\000a=1", 4, absl::nullopt},
- {"0x01 starting an dictionary key", "\001a=1", 4, absl::nullopt},
- {"0x02 starting an dictionary key", "\002a=1", 4, absl::nullopt},
- {"0x03 starting an dictionary key", "\003a=1", 4, absl::nullopt},
- {"0x04 starting an dictionary key", "\004a=1", 4, absl::nullopt},
- {"0x05 starting an dictionary key", "\005a=1", 4, absl::nullopt},
- {"0x06 starting an dictionary key", "\006a=1", 4, absl::nullopt},
- {"0x07 starting an dictionary key", "\aa=1", 4, absl::nullopt},
- {"0x08 starting an dictionary key", "\ba=1", 4, absl::nullopt},
- {"0x09 starting an dictionary key", "\ta=1", 4, absl::nullopt},
- {"0x0a starting an dictionary key", "\na=1", 4, absl::nullopt},
- {"0x0b starting an dictionary key", "\va=1", 4, absl::nullopt},
- {"0x0c starting an dictionary key", "\fa=1", 4, absl::nullopt},
- {"0x0d starting an dictionary key", "\ra=1", 4, absl::nullopt},
- {"0x0e starting an dictionary key", "\016a=1", 4, absl::nullopt},
- {"0x0f starting an dictionary key", "\017a=1", 4, absl::nullopt},
- {"0x10 starting an dictionary key", "\020a=1", 4, absl::nullopt},
- {"0x11 starting an dictionary key", "\021a=1", 4, absl::nullopt},
- {"0x12 starting an dictionary key", "\022a=1", 4, absl::nullopt},
- {"0x13 starting an dictionary key", "\023a=1", 4, absl::nullopt},
- {"0x14 starting an dictionary key", "\024a=1", 4, absl::nullopt},
- {"0x15 starting an dictionary key", "\025a=1", 4, absl::nullopt},
- {"0x16 starting an dictionary key", "\026a=1", 4, absl::nullopt},
- {"0x17 starting an dictionary key", "\027a=1", 4, absl::nullopt},
- {"0x18 starting an dictionary key", "\030a=1", 4, absl::nullopt},
- {"0x19 starting an dictionary key", "\031a=1", 4, absl::nullopt},
- {"0x1a starting an dictionary key", "\032a=1", 4, absl::nullopt},
- {"0x1b starting an dictionary key", "\033a=1", 4, absl::nullopt},
- {"0x1c starting an dictionary key", "\034a=1", 4, absl::nullopt},
- {"0x1d starting an dictionary key", "\035a=1", 4, absl::nullopt},
- {"0x1e starting an dictionary key", "\036a=1", 4, absl::nullopt},
- {"0x1f starting an dictionary key", "\037a=1", 4, absl::nullopt},
- {"0x20 starting an dictionary key",
- " a=1",
- 4,
- {Dictionary{{{"a", {Integer(1), {}}}}}},
- "a=1"},
- {"0x21 starting an dictionary key", "!a=1", 4, absl::nullopt},
- {"0x22 starting an dictionary key", "\"a=1", 4, absl::nullopt},
- {"0x23 starting an dictionary key", "#a=1", 4, absl::nullopt},
- {"0x24 starting an dictionary key", "$a=1", 4, absl::nullopt},
- {"0x25 starting an dictionary key", "%a=1", 4, absl::nullopt},
- {"0x26 starting an dictionary key", "&a=1", 4, absl::nullopt},
- {"0x27 starting an dictionary key", "'a=1", 4, absl::nullopt},
- {"0x28 starting an dictionary key", "(a=1", 4, absl::nullopt},
- {"0x29 starting an dictionary key", ")a=1", 4, absl::nullopt},
- {"0x2a starting an dictionary key",
- "*a=1",
- 4,
- {Dictionary{{{"*a", {Integer(1), {}}}}}}},
- {"0x2b starting an dictionary key", "+a=1", 4, absl::nullopt},
- {"0x2c starting an dictionary key", ",a=1", 4, absl::nullopt},
- {"0x2d starting an dictionary key", "-a=1", 4, absl::nullopt},
- {"0x2e starting an dictionary key", ".a=1", 4, absl::nullopt},
- {"0x2f starting an dictionary key", "/a=1", 4, absl::nullopt},
- {"0x30 starting an dictionary key", "0a=1", 4, absl::nullopt},
- {"0x31 starting an dictionary key", "1a=1", 4, absl::nullopt},
- {"0x32 starting an dictionary key", "2a=1", 4, absl::nullopt},
- {"0x33 starting an dictionary key", "3a=1", 4, absl::nullopt},
- {"0x34 starting an dictionary key", "4a=1", 4, absl::nullopt},
- {"0x35 starting an dictionary key", "5a=1", 4, absl::nullopt},
- {"0x36 starting an dictionary key", "6a=1", 4, absl::nullopt},
- {"0x37 starting an dictionary key", "7a=1", 4, absl::nullopt},
- {"0x38 starting an dictionary key", "8a=1", 4, absl::nullopt},
- {"0x39 starting an dictionary key", "9a=1", 4, absl::nullopt},
- {"0x3a starting an dictionary key", ":a=1", 4, absl::nullopt},
- {"0x3b starting an dictionary key", ";a=1", 4, absl::nullopt},
- {"0x3c starting an dictionary key", "<a=1", 4, absl::nullopt},
- {"0x3d starting an dictionary key", "=a=1", 4, absl::nullopt},
- {"0x3e starting an dictionary key", ">a=1", 4, absl::nullopt},
- {"0x3f starting an dictionary key", "?a=1", 4, absl::nullopt},
- {"0x40 starting an dictionary key", "@a=1", 4, absl::nullopt},
- {"0x41 starting an dictionary key", "Aa=1", 4, absl::nullopt},
- {"0x42 starting an dictionary key", "Ba=1", 4, absl::nullopt},
- {"0x43 starting an dictionary key", "Ca=1", 4, absl::nullopt},
- {"0x44 starting an dictionary key", "Da=1", 4, absl::nullopt},
- {"0x45 starting an dictionary key", "Ea=1", 4, absl::nullopt},
- {"0x46 starting an dictionary key", "Fa=1", 4, absl::nullopt},
- {"0x47 starting an dictionary key", "Ga=1", 4, absl::nullopt},
- {"0x48 starting an dictionary key", "Ha=1", 4, absl::nullopt},
- {"0x49 starting an dictionary key", "Ia=1", 4, absl::nullopt},
- {"0x4a starting an dictionary key", "Ja=1", 4, absl::nullopt},
- {"0x4b starting an dictionary key", "Ka=1", 4, absl::nullopt},
- {"0x4c starting an dictionary key", "La=1", 4, absl::nullopt},
- {"0x4d starting an dictionary key", "Ma=1", 4, absl::nullopt},
- {"0x4e starting an dictionary key", "Na=1", 4, absl::nullopt},
- {"0x4f starting an dictionary key", "Oa=1", 4, absl::nullopt},
- {"0x50 starting an dictionary key", "Pa=1", 4, absl::nullopt},
- {"0x51 starting an dictionary key", "Qa=1", 4, absl::nullopt},
- {"0x52 starting an dictionary key", "Ra=1", 4, absl::nullopt},
- {"0x53 starting an dictionary key", "Sa=1", 4, absl::nullopt},
- {"0x54 starting an dictionary key", "Ta=1", 4, absl::nullopt},
- {"0x55 starting an dictionary key", "Ua=1", 4, absl::nullopt},
- {"0x56 starting an dictionary key", "Va=1", 4, absl::nullopt},
- {"0x57 starting an dictionary key", "Wa=1", 4, absl::nullopt},
- {"0x58 starting an dictionary key", "Xa=1", 4, absl::nullopt},
- {"0x59 starting an dictionary key", "Ya=1", 4, absl::nullopt},
- {"0x5a starting an dictionary key", "Za=1", 4, absl::nullopt},
- {"0x5b starting an dictionary key", "[a=1", 4, absl::nullopt},
- {"0x5c starting an dictionary key", "\\a=1", 4, absl::nullopt},
- {"0x5d starting an dictionary key", "]a=1", 4, absl::nullopt},
- {"0x5e starting an dictionary key", "^a=1", 4, absl::nullopt},
- {"0x5f starting an dictionary key", "_a=1", 4, absl::nullopt},
- {"0x60 starting an dictionary key", "`a=1", 4, absl::nullopt},
- {"0x61 starting an dictionary key",
- "aa=1",
- 4,
- {Dictionary{{{"aa", {Integer(1), {}}}}}}},
- {"0x62 starting an dictionary key",
- "ba=1",
- 4,
- {Dictionary{{{"ba", {Integer(1), {}}}}}}},
- {"0x63 starting an dictionary key",
- "ca=1",
- 4,
- {Dictionary{{{"ca", {Integer(1), {}}}}}}},
- {"0x64 starting an dictionary key",
- "da=1",
- 4,
- {Dictionary{{{"da", {Integer(1), {}}}}}}},
- {"0x65 starting an dictionary key",
- "ea=1",
- 4,
- {Dictionary{{{"ea", {Integer(1), {}}}}}}},
- {"0x66 starting an dictionary key",
- "fa=1",
- 4,
- {Dictionary{{{"fa", {Integer(1), {}}}}}}},
- {"0x67 starting an dictionary key",
- "ga=1",
- 4,
- {Dictionary{{{"ga", {Integer(1), {}}}}}}},
- {"0x68 starting an dictionary key",
- "ha=1",
- 4,
- {Dictionary{{{"ha", {Integer(1), {}}}}}}},
- {"0x69 starting an dictionary key",
- "ia=1",
- 4,
- {Dictionary{{{"ia", {Integer(1), {}}}}}}},
- {"0x6a starting an dictionary key",
- "ja=1",
- 4,
- {Dictionary{{{"ja", {Integer(1), {}}}}}}},
- {"0x6b starting an dictionary key",
- "ka=1",
- 4,
- {Dictionary{{{"ka", {Integer(1), {}}}}}}},
- {"0x6c starting an dictionary key",
- "la=1",
- 4,
- {Dictionary{{{"la", {Integer(1), {}}}}}}},
- {"0x6d starting an dictionary key",
- "ma=1",
- 4,
- {Dictionary{{{"ma", {Integer(1), {}}}}}}},
- {"0x6e starting an dictionary key",
- "na=1",
- 4,
- {Dictionary{{{"na", {Integer(1), {}}}}}}},
- {"0x6f starting an dictionary key",
- "oa=1",
- 4,
- {Dictionary{{{"oa", {Integer(1), {}}}}}}},
- {"0x70 starting an dictionary key",
- "pa=1",
- 4,
- {Dictionary{{{"pa", {Integer(1), {}}}}}}},
- {"0x71 starting an dictionary key",
- "qa=1",
- 4,
- {Dictionary{{{"qa", {Integer(1), {}}}}}}},
- {"0x72 starting an dictionary key",
- "ra=1",
- 4,
- {Dictionary{{{"ra", {Integer(1), {}}}}}}},
- {"0x73 starting an dictionary key",
- "sa=1",
- 4,
- {Dictionary{{{"sa", {Integer(1), {}}}}}}},
- {"0x74 starting an dictionary key",
- "ta=1",
- 4,
- {Dictionary{{{"ta", {Integer(1), {}}}}}}},
- {"0x75 starting an dictionary key",
- "ua=1",
- 4,
- {Dictionary{{{"ua", {Integer(1), {}}}}}}},
- {"0x76 starting an dictionary key",
- "va=1",
- 4,
- {Dictionary{{{"va", {Integer(1), {}}}}}}},
- {"0x77 starting an dictionary key",
- "wa=1",
- 4,
- {Dictionary{{{"wa", {Integer(1), {}}}}}}},
- {"0x78 starting an dictionary key",
- "xa=1",
- 4,
- {Dictionary{{{"xa", {Integer(1), {}}}}}}},
- {"0x79 starting an dictionary key",
- "ya=1",
- 4,
- {Dictionary{{{"ya", {Integer(1), {}}}}}}},
- {"0x7a starting an dictionary key",
- "za=1",
- 4,
- {Dictionary{{{"za", {Integer(1), {}}}}}}},
- {"0x7b starting an dictionary key", "{a=1", 4, absl::nullopt},
- {"0x7c starting an dictionary key", "|a=1", 4, absl::nullopt},
- {"0x7d starting an dictionary key", "}a=1", 4, absl::nullopt},
- {"0x7e starting an dictionary key", "~a=1", 4, absl::nullopt},
- {"0x7f starting an dictionary key", "\177a=1", 4, absl::nullopt},
- // param-dict.json
- {"basic parameterised dict",
- "abc=123;a=1;b=2, def=456, ghi=789;q=9;r=\"+w\"",
- 44,
- {Dictionary{
- {{"abc", {Integer(123), {Param("a", 1), Param("b", 2)}}},
- {"def", {Integer(456), {}}},
- {"ghi", {Integer(789), {Param("q", 9), Param("r", "+w")}}}}}}},
- {"single item parameterised dict",
- "a=b; q=1.0",
- 10,
- {Dictionary{
- {{"a", {Item("b", Item::kTokenType), {DoubleParam("q", 1.000000)}}}}}},
- "a=b;q=1.0"},
- {"list item parameterised dictionary",
- "a=(1 2); q=1.0",
- 14,
- {Dictionary{{{"a",
- {{{Integer(1), {}}, {Integer(2), {}}},
- {DoubleParam("q", 1.000000)}}}}}},
- "a=(1 2);q=1.0"},
- {"missing parameter value parameterised dict",
- "a=3;c;d=5",
- 9,
- {Dictionary{
- {{"a", {Integer(3), {BooleanParam("c", true), Param("d", 5)}}}}}}},
- {"terminal missing parameter value parameterised dict",
- "a=3;c=5;d",
- 9,
- {Dictionary{
- {{"a", {Integer(3), {Param("c", 5), BooleanParam("d", true)}}}}}}},
- {"no whitespace parameterised dict",
- "a=b;c=1,d=e;f=2",
- 15,
- {Dictionary{{{"a", {Item("b", Item::kTokenType), {Param("c", 1)}}},
- {"d", {Item("e", Item::kTokenType), {Param("f", 2)}}}}}},
- "a=b;c=1, d=e;f=2"},
- {"whitespace before = parameterised dict", "a=b;q =0.5", 10, absl::nullopt},
- {"whitespace after = parameterised dict", "a=b;q= 0.5", 10, absl::nullopt},
- {"whitespace before ; parameterised dict", "a=b ;q=0.5", 10, absl::nullopt},
- {"whitespace after ; parameterised dict",
- "a=b; q=0.5",
- 10,
- {Dictionary{
- {{"a", {Item("b", Item::kTokenType), {DoubleParam("q", 0.500000)}}}}}},
- "a=b;q=0.5"},
- {"extra whitespace parameterised dict",
- "a=b; c=1 , d=e; f=2; g=3",
- 27,
- {Dictionary{
- {{"a", {Item("b", Item::kTokenType), {Param("c", 1)}}},
- {"d",
- {Item("e", Item::kTokenType), {Param("f", 2), Param("g", 3)}}}}}},
- "a=b;c=1, d=e;f=2;g=3"},
- {"two lines parameterised list",
- "a=b;c=1, d=e;f=2",
- 16,
- {Dictionary{{{"a", {Item("b", Item::kTokenType), {Param("c", 1)}}},
- {"d", {Item("e", Item::kTokenType), {Param("f", 2)}}}}}},
- "a=b;c=1, d=e;f=2"},
- {"trailing comma parameterised list", "a=b; q=1.0,", 11, absl::nullopt},
- {"empty item parameterised list", "a=b; q=1.0,,c=d", 15, absl::nullopt},
-};
-} // namespace
-
-TEST(StructuredHeaderGeneratedTest, ParseItem) {
- for (const auto& c : parameterized_item_test_cases) {
- if (c.raw) {
- SCOPED_TRACE(c.name);
- std::string raw{c.raw, c.raw_len};
- absl::optional<ParameterizedItem> result = ParseItem(raw);
- EXPECT_EQ(result, c.expected);
- }
- }
-}
-
-TEST(StructuredHeaderGeneratedTest, ParseList) {
- for (const auto& c : list_test_cases) {
- if (c.raw) {
- SCOPED_TRACE(c.name);
- std::string raw{c.raw, c.raw_len};
- absl::optional<List> result = ParseList(raw);
- EXPECT_EQ(result, c.expected);
- }
- }
-}
-
-TEST(StructuredHeaderGeneratedTest, ParseDictionary) {
- for (const auto& c : dictionary_test_cases) {
- if (c.raw) {
- SCOPED_TRACE(c.name);
- std::string raw{c.raw, c.raw_len};
- absl::optional<Dictionary> result = ParseDictionary(raw);
- EXPECT_EQ(result, c.expected);
- }
- }
-}
-
-TEST(StructuredHeaderGeneratedTest, SerializeItem) {
- for (const auto& c : parameterized_item_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeItem(*c.expected);
- if (c.raw || c.canonical) {
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(),
- std::string(c.canonical ? c.canonical : c.raw));
- } else {
- EXPECT_FALSE(result.has_value());
- }
- }
- }
-}
-
-TEST(StructuredHeaderGeneratedTest, SerializeList) {
- for (const auto& c : list_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeList(*c.expected);
- if (c.raw || c.canonical) {
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(),
- std::string(c.canonical ? c.canonical : c.raw));
- } else {
- EXPECT_FALSE(result.has_value());
- }
- }
- }
-}
-
-TEST(StructuredHeaderGeneratedTest, SerializeDictionary) {
- for (const auto& c : dictionary_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeDictionary(*c.expected);
- if (c.raw || c.canonical) {
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(),
- std::string(c.canonical ? c.canonical : c.raw));
- } else {
- EXPECT_FALSE(result.has_value());
- }
- }
- }
-}
-
-} // namespace structured_headers
-} // namespace net
diff --git a/chromium/net/http/structured_headers_unittest.cc b/chromium/net/http/structured_headers_unittest.cc
deleted file mode 100644
index d2848b2b523..00000000000
--- a/chromium/net/http/structured_headers_unittest.cc
+++ /dev/null
@@ -1,748 +0,0 @@
-// Copyright 2019 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 "net/http/structured_headers.h"
-
-#include <math.h>
-
-#include <limits>
-#include <string>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace structured_headers {
-namespace {
-
-// Helpers to make test cases clearer
-
-Item Token(std::string value) {
- return Item(value, Item::kTokenType);
-}
-
-Item Integer(int64_t value) {
- return Item(value);
-}
-
-// Parameter with null value, only used in Structured Headers Draft 09
-std::pair<std::string, Item> NullParam(std::string key) {
- return std::make_pair(key, Item());
-}
-
-std::pair<std::string, Item> BooleanParam(std::string key, bool value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> DoubleParam(std::string key, double value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> Param(std::string key, int64_t value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> Param(std::string key, std::string value) {
- return std::make_pair(key, Item(value));
-}
-
-std::pair<std::string, Item> ByteSequenceParam(std::string key,
- std::string value) {
- return std::make_pair(key, Item(value, Item::kByteSequenceType));
-}
-
-std::pair<std::string, Item> TokenParam(std::string key, std::string value) {
- return std::make_pair(key, Token(value));
-}
-
-// Test cases taken from https://github.com/httpwg/structured-header-tests can
-// be found in structured_headers_generated_unittest.cc
-
-const struct ItemTestCase {
- const char* name;
- const char* raw;
- const absl::optional<Item> expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} item_test_cases[] = {
- // Token
- {"bad token - item", "abc$@%!", absl::nullopt},
- {"leading whitespace", " foo", Token("foo"), "foo"},
- {"trailing whitespace", "foo ", Token("foo"), "foo"},
- {"leading asterisk", "*foo", Token("*foo")},
- // Number
- {"long integer", "999999999999999", Integer(999999999999999L)},
- {"long negative integer", "-999999999999999", Integer(-999999999999999L)},
- {"too long integer", "1000000000000000", absl::nullopt},
- {"negative too long integer", "-1000000000000000", absl::nullopt},
- {"integral decimal", "1.0", Item(1.0)},
- // String
- {"basic string", "\"foo\"", Item("foo")},
- {"non-ascii string", "\"f\xC3\xBC\xC3\xBC\"", absl::nullopt},
- // Additional tests
- {"valid quoting containing \\n", "\"\\\\n\"", Item("\\n")},
- {"valid quoting containing \\t", "\"\\\\t\"", Item("\\t")},
- {"valid quoting containing \\x", "\"\\\\x61\"", Item("\\x61")},
- {"c-style hex escape in string", "\"\\x61\"", absl::nullopt},
- {"valid quoting containing \\u", "\"\\\\u0061\"", Item("\\u0061")},
- {"c-style unicode escape in string", "\"\\u0061\"", absl::nullopt},
-};
-
-const ItemTestCase sh09_item_test_cases[] = {
- // Integer
- {"large integer", "9223372036854775807", Integer(9223372036854775807L)},
- {"large negative integer", "-9223372036854775807",
- Integer(-9223372036854775807L)},
- {"too large integer", "9223372036854775808", absl::nullopt},
- {"too large negative integer", "-9223372036854775808", absl::nullopt},
- // Byte Sequence
- {"basic binary", "*aGVsbG8=*", Item("hello", Item::kByteSequenceType)},
- {"empty binary", "**", Item("", Item::kByteSequenceType)},
- {"bad paddding", "*aGVsbG8*", Item("hello", Item::kByteSequenceType),
- "*aGVsbG8=*"},
- {"bad end delimiter", "*aGVsbG8=", absl::nullopt},
- {"extra whitespace", "*aGVsb G8=*", absl::nullopt},
- {"extra chars", "*aGVsbG!8=*", absl::nullopt},
- {"suffix chars", "*aGVsbG8=!*", absl::nullopt},
- {"non-zero pad bits", "*iZ==*", Item("\x89", Item::kByteSequenceType),
- "*iQ==*"},
- {"non-ASCII binary", "*/+Ah*", Item("\xFF\xE0!", Item::kByteSequenceType)},
- {"base64url binary", "*_-Ah*", absl::nullopt},
- {"token with leading asterisk", "*foo", absl::nullopt},
-};
-
-// For Structured Headers Draft 15
-const struct ParameterizedItemTestCase {
- const char* name;
- const char* raw;
- const absl::optional<ParameterizedItem>
- expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} parameterized_item_test_cases[] = {
- {"single parameter item",
- "text/html;q=1.0",
- {{Token("text/html"), {DoubleParam("q", 1)}}}},
- {"missing parameter value item",
- "text/html;a;q=1.0",
- {{Token("text/html"), {BooleanParam("a", true), DoubleParam("q", 1)}}}},
- {"missing terminal parameter value item",
- "text/html;q=1.0;a",
- {{Token("text/html"), {DoubleParam("q", 1), BooleanParam("a", true)}}}},
- {"duplicate parameter keys with different value",
- "text/html;a=1;b=2;a=3.0",
- {{Token("text/html"), {DoubleParam("a", 3), Param("b", 2L)}}},
- "text/html;a=3.0;b=2"},
- {"multiple duplicate parameter keys at different position",
- "text/html;c=1;a=2;b;b=3.0;a",
- {{Token("text/html"),
- {Param("c", 1L), BooleanParam("a", true), DoubleParam("b", 3)}}},
- "text/html;c=1;a;b=3.0"},
- {"duplicate parameter keys with missing value",
- "text/html;a;a=1",
- {{Token("text/html"), {Param("a", 1L)}}},
- "text/html;a=1"},
- {"whitespace before = parameterised item", "text/html, text/plain;q =0.5",
- absl::nullopt},
- {"whitespace after = parameterised item", "text/html, text/plain;q= 0.5",
- absl::nullopt},
- {"whitespace before ; parameterised item", "text/html, text/plain ;q=0.5",
- absl::nullopt},
- {"whitespace after ; parameterised item",
- "text/plain; q=0.5",
- {{Token("text/plain"), {DoubleParam("q", 0.5)}}},
- "text/plain;q=0.5"},
- {"extra whitespace parameterised item",
- "text/plain; q=0.5; charset=utf-8",
- {{Token("text/plain"),
- {DoubleParam("q", 0.5), TokenParam("charset", "utf-8")}}},
- "text/plain;q=0.5;charset=utf-8"},
-};
-
-// For Structured Headers Draft 15
-const struct ListTestCase {
- const char* name;
- const char* raw;
- const absl::optional<List> expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} list_test_cases[] = {
- // Lists of lists
- {"extra whitespace list of lists",
- "(1 42)",
- {{{{{Integer(1L), {}}, {Integer(42L), {}}}, {}}}},
- "(1 42)"},
- // Parameterized Lists
- {"basic parameterised list",
- "abc_123;a=1;b=2; cdef_456, ghi;q=\"9\";r=\"+w\"",
- {{{Token("abc_123"),
- {Param("a", 1), Param("b", 2), BooleanParam("cdef_456", true)}},
- {Token("ghi"), {Param("q", "9"), Param("r", "+w")}}}},
- "abc_123;a=1;b=2;cdef_456, ghi;q=\"9\";r=\"+w\""},
- // Parameterized inner lists
- {"parameterised basic list of lists",
- "(1;a=1.0 2), (42 43)",
- {{{{{Integer(1L), {DoubleParam("a", 1.0)}}, {Integer(2L), {}}}, {}},
- {{{Integer(42L), {}}, {Integer(43L), {}}}, {}}}}},
- {"parameters on inner members",
- "(1;a=1.0 2;b=c), (42;d=?0 43;e=:Zmdo:)",
- {{{{{Integer(1L), {DoubleParam("a", 1.0)}},
- {Integer(2L), {TokenParam("b", "c")}}},
- {}},
- {{{Integer(42L), {BooleanParam("d", false)}},
- {Integer(43L), {ByteSequenceParam("e", "fgh")}}},
- {}}}}},
- {"parameters on inner lists",
- "(1 2);a=1.0, (42 43);b=?0",
- {{{{{Integer(1L), {}}, {Integer(2L), {}}}, {DoubleParam("a", 1.0)}},
- {{{Integer(42L), {}}, {Integer(43L), {}}},
- {BooleanParam("b", false)}}}}},
- {"default true values for parameters on inner list members",
- "(1;a 2), (42 43;b)",
- {{{{{Integer(1L), {BooleanParam("a", true)}}, {Integer(2L), {}}}, {}},
- {{{Integer(42L), {}}, {Integer(43L), {BooleanParam("b", true)}}}, {}}}}},
- {"default true values for parameters on inner lists",
- "(1 2);a, (42 43);b",
- {{{{{Integer(1L), {}}, {Integer(2L), {}}}, {BooleanParam("a", true)}},
- {{{Integer(42L), {}}, {Integer(43L), {}}}, {BooleanParam("b", true)}}}}},
- {"extra whitespace before semicolon in parameters on inner list member",
- "(a;b ;c b)", absl::nullopt},
- {"extra whitespace between parameters on inner list member",
- "(a;b; c b)",
- {{{{{Token("a"), {BooleanParam("b", true), BooleanParam("c", true)}},
- {Token("b"), {}}},
- {}}}},
- "(a;b;c b)"},
- {"extra whitespace before semicolon in parameters on inner list",
- "(a b);c ;d, (e)", absl::nullopt},
- {"extra whitespace between parameters on inner list",
- "(a b);c; d, (e)",
- {{{{{Token("a"), {}}, {Token("b"), {}}},
- {BooleanParam("c", true), BooleanParam("d", true)}},
- {{{Token("e"), {}}}, {}}}},
- "(a b);c;d, (e)"},
-};
-
-// For Structured Headers Draft 15
-const struct DictionaryTestCase {
- const char* name;
- const char* raw;
- const absl::optional<Dictionary>
- expected; // nullopt if parse error is expected.
- const char* canonical; // nullptr if parse error is expected, or if canonical
- // format is identical to raw.
-} dictionary_test_cases[] = {
- {"basic dictionary",
- "en=\"Applepie\", da=:aGVsbG8=:",
- {Dictionary{{{"en", {Item("Applepie"), {}}},
- {"da", {Item("hello", Item::kByteSequenceType), {}}}}}}},
- {"tab separated dictionary",
- "a=1\t,\tb=2",
- {Dictionary{{{"a", {Integer(1L), {}}}, {"b", {Integer(2L), {}}}}}},
- "a=1, b=2"},
- {"missing value with params dictionary",
- "a=1, b;foo=9, c=3",
- {Dictionary{{{"a", {Integer(1L), {}}},
- {"b", {Item(true), {Param("foo", 9)}}},
- {"c", {Integer(3L), {}}}}}}},
- // Parameterised dictionary tests
- {"parameterised inner list member dict",
- "a=(\"1\";b=1;c=?0 \"2\");d=\"e\"",
- {Dictionary{{{"a",
- {{{Item("1"), {Param("b", 1), BooleanParam("c", false)}},
- {Item("2"), {}}},
- {Param("d", "e")}}}}}}},
- {"explicit true value with parameter",
- "a=?1;b=1",
- {Dictionary{{{"a", {Item(true), {Param("b", 1)}}}}}},
- "a;b=1"},
- {"implicit true value with parameter",
- "a;b=1",
- {Dictionary{{{"a", {Item(true), {Param("b", 1)}}}}}}},
- {"implicit true value with implicitly-valued parameter",
- "a;b",
- {Dictionary{{{"a", {Item(true), {BooleanParam("b", true)}}}}}}},
-};
-} // namespace
-
-TEST(StructuredHeaderTest, ParseBareItem) {
- for (const auto& c : item_test_cases) {
- SCOPED_TRACE(c.name);
- absl::optional<Item> result = ParseBareItem(c.raw);
- EXPECT_EQ(result, c.expected);
- }
-}
-
-// For Structured Headers Draft 15, these tests include parameters on Items.
-TEST(StructuredHeaderTest, ParseItem) {
- for (const auto& c : parameterized_item_test_cases) {
- SCOPED_TRACE(c.name);
- absl::optional<ParameterizedItem> result = ParseItem(c.raw);
- EXPECT_EQ(result, c.expected);
- }
-}
-
-// Structured Headers Draft 9 parsing rules are different than Draft 15, and
-// some strings which are considered invalid in SH15 should parse in SH09.
-// The SH09 Item parser is not directly exposed, but can be used indirectly by
-// calling the parser for SH09-specific lists.
-TEST(StructuredHeaderTest, ParseSH09Item) {
- for (const auto& c : sh09_item_test_cases) {
- SCOPED_TRACE(c.name);
- absl::optional<ListOfLists> result = ParseListOfLists(c.raw);
- if (c.expected.has_value()) {
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result->size(), 1UL);
- EXPECT_EQ((*result)[0].size(), 1UL);
- EXPECT_EQ((*result)[0][0], c.expected);
- } else {
- EXPECT_FALSE(result.has_value());
- }
- }
-}
-
-// In Structured Headers Draft 9, floats can have more than three fractional
-// digits, and can be larger than 1e12. This behaviour is exposed in the parser
-// for SH09-specific lists, so test it through that interface.
-TEST(StructuredHeaderTest, SH09HighPrecisionFloats) {
- // These values are exactly representable in binary floating point, so no
- // accuracy issues are expected in this test.
- absl::optional<ListOfLists> result =
- ParseListOfLists("1.03125;-1.03125;12345678901234.5;-12345678901234.5");
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(*result,
- (ListOfLists{{Item(1.03125), Item(-1.03125), Item(12345678901234.5),
- Item(-12345678901234.5)}}));
-
- result = ParseListOfLists("123456789012345.0");
- EXPECT_FALSE(result.has_value());
-
- result = ParseListOfLists("-123456789012345.0");
- EXPECT_FALSE(result.has_value());
-}
-
-// For Structured Headers Draft 9
-TEST(StructuredHeaderTest, ParseListOfLists) {
- static const struct TestCase {
- const char* name;
- const char* raw;
- ListOfLists expected; // empty if parse error is expected
- } cases[] = {
- {"basic list of lists",
- "1;2, 42;43",
- {{Integer(1L), Integer(2L)}, {Integer(42L), Integer(43L)}}},
- {"empty list of lists", "", {}},
- {"single item list of lists", "42", {{Integer(42L)}}},
- {"no whitespace list of lists", "1,42", {{Integer(1L)}, {Integer(42L)}}},
- {"no inner whitespace list of lists",
- "1;2, 42;43",
- {{Integer(1L), Integer(2L)}, {Integer(42L), Integer(43L)}}},
- {"extra whitespace list of lists",
- "1 , 42",
- {{Integer(1L)}, {Integer(42L)}}},
- {"extra inner whitespace list of lists",
- "1 ; 2,42 ; 43",
- {{Integer(1L), Integer(2L)}, {Integer(42L), Integer(43L)}}},
- {"trailing comma list of lists", "1;2, 42,", {}},
- {"trailing semicolon list of lists", "1;2, 42;43;", {}},
- {"leading comma list of lists", ",1;2, 42", {}},
- {"leading semicolon list of lists", ";1;2, 42;43", {}},
- {"empty item list of lists", "1,,42", {}},
- {"empty inner item list of lists", "1;;2,42", {}},
- };
- for (const auto& c : cases) {
- SCOPED_TRACE(c.name);
- absl::optional<ListOfLists> result = ParseListOfLists(c.raw);
- if (!c.expected.empty()) {
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(*result, c.expected);
- } else {
- EXPECT_FALSE(result.has_value());
- }
- }
-}
-
-// For Structured Headers Draft 9
-TEST(StructuredHeaderTest, ParseParameterisedList) {
- static const struct TestCase {
- const char* name;
- const char* raw;
- ParameterisedList expected; // empty if parse error is expected
- } cases[] = {
- {"basic param-list",
- "abc_123;a=1;b=2; cdef_456, ghi;q=\"9\";r=\"w\"",
- {
- {Token("abc_123"),
- {Param("a", 1), Param("b", 2), NullParam("cdef_456")}},
- {Token("ghi"), {Param("q", "9"), Param("r", "w")}},
- }},
- {"empty param-list", "", {}},
- {"single item param-list",
- "text/html;q=1",
- {{Token("text/html"), {Param("q", 1)}}}},
- {"empty param-list", "", {}},
- {"no whitespace param-list",
- "text/html,text/plain;q=1",
- {{Token("text/html"), {}}, {Token("text/plain"), {Param("q", 1)}}}},
- {"whitespace before = param-list", "text/html, text/plain;q =1", {}},
- {"whitespace after = param-list", "text/html, text/plain;q= 1", {}},
- {"extra whitespace param-list",
- "text/html , text/plain ; q=1",
- {{Token("text/html"), {}}, {Token("text/plain"), {Param("q", 1)}}}},
- {"duplicate key", "abc;a=1;b=2;a=1", {}},
- {"numeric key", "abc;a=1;1b=2;c=1", {}},
- {"uppercase key", "abc;a=1;B=2;c=1", {}},
- {"bad key", "abc;a=1;b!=2;c=1", {}},
- {"another bad key", "abc;a=1;b==2;c=1", {}},
- {"empty key name", "abc;a=1;=2;c=1", {}},
- {"empty parameter", "abc;a=1;;c=1", {}},
- {"empty list item", "abc;a=1,,def;b=1", {}},
- {"extra semicolon", "abc;a=1;b=1;", {}},
- {"extra comma", "abc;a=1,def;b=1,", {}},
- {"leading semicolon", ";abc;a=1", {}},
- {"leading comma", ",abc;a=1", {}},
- };
- for (const auto& c : cases) {
- SCOPED_TRACE(c.name);
- absl::optional<ParameterisedList> result = ParseParameterisedList(c.raw);
- if (c.expected.empty()) {
- EXPECT_FALSE(result.has_value());
- continue;
- }
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result->size(), c.expected.size());
- if (result->size() == c.expected.size()) {
- for (size_t i = 0; i < c.expected.size(); ++i)
- EXPECT_EQ((*result)[i], c.expected[i]);
- }
- }
-}
-
-// For Structured Headers Draft 15
-TEST(StructuredHeaderTest, ParseList) {
- for (const auto& c : list_test_cases) {
- SCOPED_TRACE(c.name);
- absl::optional<List> result = ParseList(c.raw);
- EXPECT_EQ(result, c.expected);
- }
-}
-
-// For Structured Headers Draft 15
-TEST(StructuredHeaderTest, ParseDictionary) {
- for (const auto& c : dictionary_test_cases) {
- SCOPED_TRACE(c.name);
- absl::optional<Dictionary> result = ParseDictionary(c.raw);
- EXPECT_EQ(result, c.expected);
- }
-}
-
-// Serializer tests are all exclusively for Structured Headers Draft 15
-
-TEST(StructuredHeaderTest, SerializeItem) {
- for (const auto& c : item_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeItem(*c.expected);
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(), std::string(c.canonical ? c.canonical : c.raw));
- }
- }
-}
-
-TEST(StructuredHeaderTest, SerializeParameterizedItem) {
- for (const auto& c : parameterized_item_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeItem(*c.expected);
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(), std::string(c.canonical ? c.canonical : c.raw));
- }
- }
-}
-
-TEST(StructuredHeaderTest, UnserializableItems) {
- // Test that items with unknown type are not serialized.
- EXPECT_FALSE(SerializeItem(Item()).has_value());
-}
-
-TEST(StructuredHeaderTest, UnserializableTokens) {
- static const struct UnserializableString {
- const char* name;
- const char* value;
- } bad_tokens[] = {
- {"empty token", ""},
- {"contains high ascii", "a\xff"},
- {"contains nonprintable character", "a\x7f"},
- {"contains C0", "a\x01"},
- {"UTF-8 encoded", "a\xc3\xa9"},
- {"contains TAB", "a\t"},
- {"contains LF", "a\n"},
- {"contains CR", "a\r"},
- {"contains SP", "a "},
- {"begins with digit", "9token"},
- {"begins with hyphen", "-token"},
- {"begins with LF", "\ntoken"},
- {"begins with SP", " token"},
- {"begins with colon", ":token"},
- {"begins with percent", "%token"},
- {"begins with period", ".token"},
- {"begins with slash", "/token"},
- };
- for (const auto& bad_token : bad_tokens) {
- SCOPED_TRACE(bad_token.name);
- absl::optional<std::string> serialization =
- SerializeItem(Token(bad_token.value));
- EXPECT_FALSE(serialization.has_value()) << *serialization;
- }
-}
-
-TEST(StructuredHeaderTest, UnserializableKeys) {
- static const struct UnserializableString {
- const char* name;
- const char* value;
- } bad_keys[] = {
- {"empty key", ""},
- {"contains high ascii", "a\xff"},
- {"contains nonprintable character", "a\x7f"},
- {"contains C0", "a\x01"},
- {"UTF-8 encoded", "a\xc3\xa9"},
- {"contains TAB", "a\t"},
- {"contains LF", "a\n"},
- {"contains CR", "a\r"},
- {"contains SP", "a "},
- {"begins with uppercase", "Atoken"},
- {"begins with digit", "9token"},
- {"begins with hyphen", "-token"},
- {"begins with LF", "\ntoken"},
- {"begins with SP", " token"},
- {"begins with colon", ":token"},
- {"begins with percent", "%token"},
- {"begins with period", ".token"},
- {"begins with slash", "/token"},
- };
- for (const auto& bad_key : bad_keys) {
- SCOPED_TRACE(bad_key.name);
- absl::optional<std::string> serialization =
- SerializeItem(ParameterizedItem("a", {{bad_key.value, "a"}}));
- EXPECT_FALSE(serialization.has_value()) << *serialization;
- }
-}
-
-TEST(StructuredHeaderTest, UnserializableStrings) {
- static const struct UnserializableString {
- const char* name;
- const char* value;
- } bad_strings[] = {
- {"contains high ascii", "a\xff"},
- {"contains nonprintable character", "a\x7f"},
- {"UTF-8 encoded", "a\xc3\xa9"},
- {"contains TAB", "a\t"},
- {"contains LF", "a\n"},
- {"contains CR", "a\r"},
- {"contains C0", "a\x01"},
- };
- for (const auto& bad_string : bad_strings) {
- SCOPED_TRACE(bad_string.name);
- absl::optional<std::string> serialization =
- SerializeItem(Item(bad_string.value));
- EXPECT_FALSE(serialization.has_value()) << *serialization;
- }
-}
-
-TEST(StructuredHeaderTest, UnserializableIntegers) {
- EXPECT_FALSE(SerializeItem(Integer(1e15L)).has_value());
- EXPECT_FALSE(SerializeItem(Integer(-1e15L)).has_value());
-}
-
-TEST(StructuredHeaderTest, UnserializableDecimals) {
- for (double value :
- {std::numeric_limits<double>::quiet_NaN(),
- std::numeric_limits<double>::infinity(),
- -std::numeric_limits<double>::infinity(), 1e12, 1e12 - 0.0001,
- 1e12 - 0.0005, -1e12, -1e12 + 0.0001, -1e12 + 0.0005}) {
- auto x = SerializeItem(Item(value));
- EXPECT_FALSE(SerializeItem(Item(value)).has_value());
- }
-}
-
-// These values cannot be directly parsed from headers, but are valid doubles
-// which can be serialized as sh-floats (though rounding is expected.)
-TEST(StructuredHeaderTest, SerializeUnparseableDecimals) {
- struct UnparseableDecimal {
- const char* name;
- double value;
- const char* canonical;
- } float_test_cases[] = {
- {"negative 0", -0.0, "0.0"},
- {"0.0001", 0.0001, "0.0"},
- {"0.0000001", 0.0000001, "0.0"},
- {"1.0001", 1.0001, "1.0"},
- {"1.0009", 1.0009, "1.001"},
- {"round positive odd decimal", 0.0015, "0.002"},
- {"round positive even decimal", 0.0025, "0.002"},
- {"round negative odd decimal", -0.0015, "-0.002"},
- {"round negative even decimal", -0.0025, "-0.002"},
- {"round decimal up to integer part", 9.9995, "10.0"},
- {"subnormal numbers", std::numeric_limits<double>::denorm_min(), "0.0"},
- {"round up to 10 digits", 1e9 - 0.0000001, "1000000000.0"},
- {"round up to 11 digits", 1e10 - 0.000001, "10000000000.0"},
- {"round up to 12 digits", 1e11 - 0.00001, "100000000000.0"},
- {"largest serializable float", nextafter(1e12 - 0.0005, 0),
- "999999999999.999"},
- {"largest serializable negative float", -nextafter(1e12 - 0.0005, 0),
- "-999999999999.999"},
- // This will fail if we simply truncate the fractional portion.
- {"float rounds up to next int", 3.9999999, "4.0"},
- // This will fail if we first round to >3 digits, and then round again to
- // 3 digits.
- {"don't double round", 3.99949, "3.999"},
- // This will fail if we first round to 3 digits, and then round again to
- // max_avail_digits.
- {"don't double round", 123456789.99949, "123456789.999"},
- };
- for (const auto& test_case : float_test_cases) {
- SCOPED_TRACE(test_case.name);
- absl::optional<std::string> serialization =
- SerializeItem(Item(test_case.value));
- EXPECT_TRUE(serialization.has_value());
- EXPECT_EQ(*serialization, test_case.canonical);
- }
-}
-
-TEST(StructuredHeaderTest, SerializeList) {
- for (const auto& c : list_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeList(*c.expected);
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(), std::string(c.canonical ? c.canonical : c.raw));
- }
- }
-}
-
-TEST(StructuredHeaderTest, UnserializableLists) {
- static const struct UnserializableList {
- const char* name;
- const List value;
- } bad_lists[] = {
- {"Null item as member", {{Item(), {}}}},
- {"Unserializable item as member", {{Token("\n"), {}}}},
- {"Key is empty", {{Token("abc"), {Param("", 1)}}}},
- {"Key contains whitespace", {{Token("abc"), {Param("a\n", 1)}}}},
- {"Key contains UTF8", {{Token("abc"), {Param("a\xc3\xa9", 1)}}}},
- {"Key contains unprintable characters",
- {{Token("abc"), {Param("a\x7f", 1)}}}},
- {"Key contains disallowed characters",
- {{Token("abc"), {Param("a:", 1)}}}},
- {"Param value is unserializable", {{Token("abc"), {{"a", Token("\n")}}}}},
- {"Inner list contains unserializable item",
- {{std::vector<ParameterizedItem>{{Token("\n"), {}}}, {}}}},
- };
- for (const auto& bad_list : bad_lists) {
- SCOPED_TRACE(bad_list.name);
- absl::optional<std::string> serialization = SerializeList(bad_list.value);
- EXPECT_FALSE(serialization.has_value()) << *serialization;
- }
-}
-
-TEST(StructuredHeaderTest, SerializeDictionary) {
- for (const auto& c : dictionary_test_cases) {
- SCOPED_TRACE(c.name);
- if (c.expected) {
- absl::optional<std::string> result = SerializeDictionary(*c.expected);
- EXPECT_TRUE(result.has_value());
- EXPECT_EQ(result.value(), std::string(c.canonical ? c.canonical : c.raw));
- }
- }
-}
-
-TEST(StructuredHeaderTest, DictionaryConstructors) {
- const std::string key0 = "key0";
- const std::string key1 = "key1";
- const ParameterizedMember member0{Item("Applepie"), {}};
- const ParameterizedMember member1{Item("hello", Item::kByteSequenceType), {}};
-
- Dictionary dict;
- EXPECT_TRUE(dict.empty());
- EXPECT_EQ(0U, dict.size());
- dict[key0] = member0;
- EXPECT_FALSE(dict.empty());
- EXPECT_EQ(1U, dict.size());
-
- const Dictionary dict_copy = dict;
- EXPECT_FALSE(dict_copy.empty());
- EXPECT_EQ(1U, dict_copy.size());
- EXPECT_EQ(dict, dict_copy);
-
- const Dictionary dict_init{{{key0, member0}, {key1, member1}}};
- EXPECT_FALSE(dict_init.empty());
- EXPECT_EQ(2U, dict_init.size());
- EXPECT_EQ(member0, dict_init.at(key0));
- EXPECT_EQ(member1, dict_init.at(key1));
-}
-
-TEST(StructuredHeaderTest, DictionaryAccessors) {
- const std::string key0 = "key0";
- const std::string key1 = "key1";
-
- const ParameterizedMember nonempty_member0{Item("Applepie"), {}};
- const ParameterizedMember nonempty_member1{
- Item("hello", Item::kByteSequenceType), {}};
- const ParameterizedMember empty_member;
-
- Dictionary dict{{{key0, nonempty_member0}}};
- EXPECT_TRUE(dict.contains(key0));
- EXPECT_EQ(nonempty_member0, dict[key0]);
- EXPECT_EQ(&dict[key0], &dict.at(key0));
- EXPECT_EQ(&dict[key0], &dict[0]);
- EXPECT_EQ(&dict[key0], &dict.at(0));
-
- // Even if the key does not yet exist in |dict|, operator[]() should
- // automatically create an empty entry.
- ASSERT_FALSE(dict.contains(key1));
- ParameterizedMember& member1 = dict[key1];
- EXPECT_TRUE(dict.contains(key1));
- EXPECT_EQ(empty_member, member1);
- EXPECT_EQ(&member1, &dict[key1]);
- EXPECT_EQ(&member1, &dict.at(key1));
- EXPECT_EQ(&member1, &dict[1]);
- EXPECT_EQ(&member1, &dict.at(1));
-
- member1 = nonempty_member1;
- EXPECT_EQ(nonempty_member1, dict[key1]);
- EXPECT_EQ(&dict[key1], &dict.at(key1));
- EXPECT_EQ(&dict[key1], &dict[1]);
- EXPECT_EQ(&dict[key1], &dict.at(1));
-
- // at(StringPiece) and indexed accessors have const overloads.
- const Dictionary& dict_ref = dict;
- EXPECT_EQ(&member1, &dict_ref.at(key1));
- EXPECT_EQ(&member1, &dict_ref[1]);
- EXPECT_EQ(&member1, &dict_ref.at(1));
-}
-
-TEST(StructuredHeaderTest, UnserializableDictionary) {
- static const struct UnserializableDictionary {
- const char* name;
- const Dictionary value;
- } bad_dictionaries[] = {
- {"Unserializable dict key", Dictionary{{{"ABC", {Token("abc"), {}}}}}},
- {"Dictionary item is unserializable",
- Dictionary{{{"abc", {Token("abc="), {}}}}}},
- {"Param value is unserializable",
- Dictionary{{{"abc", {Token("abc"), {{"a", Token("\n")}}}}}}},
- {"Dictionary inner-list contains unserializable item",
- Dictionary{
- {{"abc",
- {std::vector<ParameterizedItem>{{Token("abc="), {}}}, {}}}}}},
- };
- for (const auto& bad_dictionary : bad_dictionaries) {
- SCOPED_TRACE(bad_dictionary.name);
- absl::optional<std::string> serialization =
- SerializeDictionary(bad_dictionary.value);
- EXPECT_FALSE(serialization.has_value()) << *serialization;
- }
-}
-
-} // namespace structured_headers
-} // namespace net
diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc
index 340b2e49df2..25c3764df23 100644
--- a/chromium/net/http/transport_security_state.cc
+++ b/chromium/net/http/transport_security_state.cc
@@ -404,17 +404,13 @@ TransportSecurityState::TransportSecurityState()
TransportSecurityState::TransportSecurityState(
std::vector<std::string> hsts_host_bypass_list)
- : enable_static_pins_(true),
- enable_static_expect_ct_(true),
- enable_pkp_bypass_for_local_trust_anchors_(true),
- sent_hpkp_reports_cache_(kMaxReportCacheEntries),
+ : sent_hpkp_reports_cache_(kMaxReportCacheEntries),
sent_expect_ct_reports_cache_(kMaxReportCacheEntries),
key_expect_ct_by_nik_(base::FeatureList::IsEnabled(
features::kPartitionExpectCTStateByNetworkIsolationKey)) {
// Static pinning is only enabled for official builds to make sure that
// others don't end up with pins that cannot be easily updated.
-#if !BUILDFLAG(GOOGLE_CHROME_BRANDING) || BUILDFLAG(IS_ANDROID) || \
- BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING) || BUILDFLAG(IS_IOS)
enable_static_pins_ = false;
enable_static_expect_ct_ = false;
#endif
@@ -1179,8 +1175,10 @@ bool TransportSecurityState::GetStaticPKPState(const std::string& host,
PKPState* pkp_result) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!enable_static_pins_ || !IsStaticPKPListTimely())
+ if (!enable_static_pins_ || !IsStaticPKPListTimely() ||
+ !base::FeatureList::IsEnabled(features::kStaticKeyPinningEnforcement)) {
return false;
+ }
PreloadResult result;
if (host_pins_.has_value()) {
@@ -1387,9 +1385,7 @@ void TransportSecurityState::AddOrUpdateEnabledExpectCTHosts(
hashed_host, network_isolation_key)] = state;
}
-TransportSecurityState::STSState::STSState()
- : upgrade_mode(MODE_DEFAULT), include_subdomains(false) {
-}
+TransportSecurityState::STSState::STSState() = default;
TransportSecurityState::STSState::~STSState() = default;
@@ -1405,14 +1401,13 @@ TransportSecurityState::STSStateIterator::STSStateIterator(
TransportSecurityState::STSStateIterator::~STSStateIterator() = default;
-TransportSecurityState::PKPState::PKPState() : include_subdomains(false) {
-}
+TransportSecurityState::PKPState::PKPState() = default;
TransportSecurityState::PKPState::PKPState(const PKPState& other) = default;
TransportSecurityState::PKPState::~PKPState() = default;
-TransportSecurityState::ExpectCTState::ExpectCTState() : enforce(false) {}
+TransportSecurityState::ExpectCTState::ExpectCTState() = default;
TransportSecurityState::ExpectCTState::~ExpectCTState() = default;
@@ -1641,10 +1636,18 @@ bool TransportSecurityState::IsCTLogListTimely() const {
}
bool TransportSecurityState::IsStaticPKPListTimely() const {
+ if (pins_list_always_timely_for_testing_) {
+ return true;
+ }
+
// If the list has not been updated via component updater, freshness depends
- // on build freshness.
+ // on the compiled-in list freshness.
if (!host_pins_.has_value()) {
- return IsBuildTimely();
+#if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+ return (base::Time::Now() - kPinsListTimestamp).InDays() < 70;
+#else
+ return false;
+#endif
}
DCHECK(!key_pins_list_last_update_time_.is_null());
// Else, we use the last update time.
diff --git a/chromium/net/http/transport_security_state.h b/chromium/net/http/transport_security_state.h
index e8d50dbf23a..f8b68821c48 100644
--- a/chromium/net/http/transport_security_state.h
+++ b/chromium/net/http/transport_security_state.h
@@ -125,10 +125,10 @@ class NET_EXPORT TransportSecurityState {
// expires.
base::Time expiry;
- UpgradeMode upgrade_mode;
+ UpgradeMode upgrade_mode = MODE_DEFAULT;
// Are subdomains subject to this policy state?
- bool include_subdomains;
+ bool include_subdomains = false;
// The domain which matched during a search for this STSState entry.
// Updated by |GetDynamicSTSState| and |GetStaticDomainState|.
@@ -191,7 +191,7 @@ class NET_EXPORT TransportSecurityState {
HashValueVector bad_spki_hashes;
// Are subdomains subject to this policy state?
- bool include_subdomains;
+ bool include_subdomains = false;
// The domain which matched during a search for this DomainState entry.
// Updated by |GetDynamicPKPState| and |GetStaticDomainState|.
@@ -239,7 +239,7 @@ class NET_EXPORT TransportSecurityState {
// True if connections should be closed if they do not comply with the CT
// policy. If false, noncompliant connections will be allowed but reports
// will be sent about the violation.
- bool enforce;
+ bool enforce = false;
// The absolute time (UTC) when the Expect-CT state was last observed.
base::Time last_observed;
// The absolute time (UTC) when the Expect-CT state expires.
@@ -642,6 +642,12 @@ class NET_EXPORT TransportSecurityState {
// The number of cached ExpectCTState entries.
size_t num_expect_ct_entries_for_testing() const;
+ // Sets whether pinning list timestamp freshness should be ignored for
+ // testing.
+ void SetPinningListAlwaysTimelyForTesting(bool always_timely) {
+ pins_list_always_timely_for_testing_ = always_timely;
+ }
+
// The number of cached STSState entries.
size_t num_sts_entries() const;
@@ -773,13 +779,13 @@ class NET_EXPORT TransportSecurityState {
raw_ptr<ReportSenderInterface> report_sender_ = nullptr;
// True if static pins should be used.
- bool enable_static_pins_;
+ bool enable_static_pins_ = true;
// True if static expect-CT state should be used.
- bool enable_static_expect_ct_;
+ bool enable_static_expect_ct_ = true;
// True if public key pinning bypass is enabled for local trust anchors.
- bool enable_pkp_bypass_for_local_trust_anchors_;
+ bool enable_pkp_bypass_for_local_trust_anchors_ = true;
raw_ptr<ExpectCTReporter> expect_ct_reporter_ = nullptr;
@@ -813,6 +819,8 @@ class NET_EXPORT TransportSecurityState {
base::Time key_pins_list_last_update_time_;
std::vector<PinSet> pinsets_;
+ bool pins_list_always_timely_for_testing_ = false;
+
THREAD_CHECKER(thread_checker_);
};
diff --git a/chromium/net/http/transport_security_state_static.json.gz b/chromium/net/http/transport_security_state_static.json.gz
index 4aadbc25d28..67961946223 100644
--- a/chromium/net/http/transport_security_state_static.json.gz
+++ b/chromium/net/http/transport_security_state_static.json.gz
Binary files differ
diff --git a/chromium/net/http/transport_security_state_static.pins b/chromium/net/http/transport_security_state_static.pins
index 27610e1a6a2..42af336fbf1 100644
--- a/chromium/net/http/transport_security_state_static.pins
+++ b/chromium/net/http/transport_security_state_static.pins
@@ -43,6 +43,10 @@
# hash function for preloaded entries again (we have already done so once).
#
+# Last updated: 2022-08-31 12:54 UTC
+PinsListTimestamp
+1661950496
+
TestSPKI
sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -1571,23 +1575,6 @@ aFE/tQpQ/YVB8aQ9+2vGoBDv9bFF+bxMmQyFtST3SUvKLhgeRqLraEd8OPfEizYl
PwIDAQAB
-----END PUBLIC KEY-----
-YahooBackup1
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1vZXDjNejqvtVvyYcP0
-7ubiG0RW1sar002td1qI7Zo9Lz8kZtrAUJrBXGh6bbpovsIwWkUjirUQk2b3M7Ob
-bgQWVGGeQlrVUUjTMth4Cg5p2Xj8b5Z5Nt7H4G9yS1boxQyh23yxpS6vB4E8LNhY
-xUBdL20j24UeRjMC+KcgKLdz0cnXpu/icfLNs9NRuYGFQZzdM7hlCKJKFLZfpNOw
-xW38ArbbJfvCZ7KhenRphlnCTCxUglp3hgGMc9pBb2xKhIh1bABn12/DB/ZuOP4d
-hYeg5UhYKhS7Z5q3Yg+mBLgQQrdat82yTU677iY38IXNzud9kvxRYb5mZrc5va6N
-SQIDAQAB
------END PUBLIC KEY-----
-
-YahooBackup2
------BEGIN PUBLIC KEY-----
-MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEY26fFxATbUDuPe7tEeZx7uGLIycMrm20
-/opCiPXC5oAcyOu0pLmiGWBKD8CRK+Po/pYsyIsHotll0aZ6V3BbQg==
------END PUBLIC KEY-----
-
# From https://letsencrypt.org/certificates/
# The key is shared by Let's Encrypt Authority X1 and X3.
LetsEncryptAuthorityPrimary_X1_X3
diff --git a/chromium/net/http/transport_security_state_static.template b/chromium/net/http/transport_security_state_static.template
index ba40b5bfefc..58d1f8af822 100644
--- a/chromium/net/http/transport_security_state_static.template
+++ b/chromium/net/http/transport_security_state_static.template
@@ -11,8 +11,12 @@
#include <iterator>
+#include "base/time/time.h"
#include "net/http/transport_security_state_source.h"
+// This is the time at which the key pins list was last updated.
+const base::Time kPinsListTimestamp = base::Time::FromTimeT([[PINS_LIST_TIMESTAMP]]);
+
// These are SubjectPublicKeyInfo hashes for public key pinning. The
// hashes are SHA256 digests.
[[SPKI_HASHES]]
diff --git a/chromium/net/http/transport_security_state_static_unittest.pins b/chromium/net/http/transport_security_state_static_unittest.pins
index 36ef2f10e7f..fc583a79637 100644
--- a/chromium/net/http/transport_security_state_static_unittest.pins
+++ b/chromium/net/http/transport_security_state_static_unittest.pins
@@ -5,6 +5,12 @@
# This is a HSTS pins file used by the unittests. For more information on the
# content and format see the comments in transport_security_state_static.pins.
+# Having a timestamp is required by the parser, but this timestamp is not
+# otherwise used by tests (since they override the behavior by setting
+# pins_list_always_timely_for_testing_
+PinsListTimestamp
+0
+
TestSPKI1
sha256/AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=
diff --git a/chromium/net/http/transport_security_state_static_unittest_default.pins b/chromium/net/http/transport_security_state_static_unittest_default.pins
index 900b7fd7333..486dc8bb9ce 100644
--- a/chromium/net/http/transport_security_state_static_unittest_default.pins
+++ b/chromium/net/http/transport_security_state_static_unittest_default.pins
@@ -5,6 +5,12 @@
# For use with transport_security_state_static_unittest_default.json.
# The format of this file is identical to transport_security_state_static.pins.
+# Having a timestamp is required by the parser, but this timestamp is not
+# otherwise used by tests (since they override the behavior by setting
+# pins_list_always_timely_for_testing_
+PinsListTimestamp
+0
+
TestSPKI1
sha256/w3y7Yg3RzkAyhCeBoLHm71YRnuuUW87AAR/DVpLMTw4=
diff --git a/chromium/net/http/transport_security_state_unittest.cc b/chromium/net/http/transport_security_state_unittest.cc
index ba3b4e3c3b2..72ea47ef65b 100644
--- a/chromium/net/http/transport_security_state_unittest.cc
+++ b/chromium/net/http/transport_security_state_unittest.cc
@@ -164,7 +164,7 @@ class MockCertificateReportSender
class MockFailingCertificateReportSender
: public TransportSecurityState::ReportSenderInterface {
public:
- MockFailingCertificateReportSender() : net_error_(ERR_CONNECTION_FAILED) {}
+ MockFailingCertificateReportSender() = default;
~MockFailingCertificateReportSender() override = default;
int net_error() { return net_error_; }
@@ -182,14 +182,14 @@ class MockFailingCertificateReportSender
}
private:
- const int net_error_;
+ const int net_error_ = ERR_CONNECTION_FAILED;
};
// A mock ExpectCTReporter that remembers the latest violation that was
// reported and the number of violations reported.
class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter {
public:
- MockExpectCTReporter() : num_failures_(0) {}
+ MockExpectCTReporter() = default;
~MockExpectCTReporter() override = default;
void OnExpectCTFailed(
@@ -233,7 +233,7 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter {
HostPortPair host_port_pair_;
GURL report_uri_;
base::Time expiration_;
- uint32_t num_failures_;
+ uint32_t num_failures_ = 0;
raw_ptr<const X509Certificate> served_certificate_chain_;
raw_ptr<const X509Certificate> validated_certificate_chain_;
SignedCertificateTimestampAndStatusList signed_certificate_timestamps_;
@@ -381,6 +381,7 @@ class TransportSecurityStateTest : public ::testing::Test,
static void EnableStaticPins(TransportSecurityState* state) {
state->enable_static_pins_ = true;
+ state->SetPinningListAlwaysTimelyForTesting(true);
}
static void EnableStaticExpectCT(TransportSecurityState* state) {
@@ -884,6 +885,7 @@ TEST_F(TransportSecurityStateTest, DeleteDynamicDataForHost) {
TEST_F(TransportSecurityStateTest, LongNames) {
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
const char kLongName[] =
"lookupByWaveIdHashAndWaveIdIdAndWaveIdDomainAndWaveletIdIdAnd"
"WaveletIdDomainAndBlipBlipid";
@@ -906,6 +908,9 @@ static bool AddHash(const std::string& type_and_base64, HashValueVector* out) {
}
TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HashValueVector good_hashes, bad_hashes;
for (size_t i = 0; kGoodPath[i]; i++) {
@@ -916,6 +921,7 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
}
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
EnableStaticPins(&state);
TransportSecurityState::PKPState pkp_state;
@@ -931,12 +937,16 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
// Tests that pinning violations on preloaded pins trigger reports when
// the preloaded pin contains a report URI.
TEST_F(TransportSecurityStateTest, PreloadedPKPReportUri) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
const char kPreloadedPinDomain[] = "with-report-uri-pkp.preloaded.test";
HostPortPair host_port_pair(kPreloadedPinDomain, kPort);
net::NetworkIsolationKey network_isolation_key =
NetworkIsolationKey::CreateTransient();
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
MockCertificateReportSender mock_report_sender;
state.SetReportSender(&mock_report_sender);
@@ -1372,6 +1382,9 @@ TEST_F(TransportSecurityStateTest, RepeatedExpectCTReportsForStaticExpectCT) {
// the lookup methods can find the entry and correctly decode the different
// preloaded states (HSTS, HPKP, and Expect-CT).
TEST_F(TransportSecurityStateTest, DecodePreloadedSingle) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
SetTransportSecurityStateSourceForTesting(&test1::kHSTSSource);
TransportSecurityState state;
@@ -1402,6 +1415,9 @@ TEST_F(TransportSecurityStateTest, DecodePreloadedSingle) {
// entries and correctly decode the different preloaded states (HSTS, HPKP,
// and Expect-CT) for each entry.
TEST_F(TransportSecurityStateTest, DecodePreloadedMultiplePrefix) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
SetTransportSecurityStateSourceForTesting(&test2::kHSTSSource);
TransportSecurityState state;
@@ -1471,6 +1487,9 @@ TEST_F(TransportSecurityStateTest, DecodePreloadedMultiplePrefix) {
// all entries and correctly decode the different preloaded states (HSTS, HPKP,
// and Expect-CT) for each entry.
TEST_F(TransportSecurityStateTest, DecodePreloadedMultipleMix) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
SetTransportSecurityStateSourceForTesting(&test3::kHSTSSource);
TransportSecurityState state;
@@ -2703,6 +2722,7 @@ static bool StaticShouldRedirect(const char* hostname) {
static bool HasStaticState(const char* hostname) {
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
return state.GetStaticSTSState(hostname, &sts_state) ||
@@ -2711,6 +2731,7 @@ static bool HasStaticState(const char* hostname) {
static bool HasStaticPublicKeyPins(const char* hostname) {
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
TransportSecurityStateTest::EnableStaticPins(&state);
TransportSecurityState::PKPState pkp_state;
if (!state.GetStaticPKPState(hostname, &pkp_state))
@@ -2728,7 +2749,11 @@ static bool OnlyPinningInStaticState(const char* hostname) {
}
TEST_F(TransportSecurityStateStaticTest, EnableStaticPins) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
TransportSecurityState::PKPState pkp_state;
EnableStaticPins(&state);
@@ -2739,6 +2764,7 @@ TEST_F(TransportSecurityStateStaticTest, EnableStaticPins) {
TEST_F(TransportSecurityStateStaticTest, DisableStaticPins) {
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
TransportSecurityState::PKPState pkp_state;
DisableStaticPins(&state);
@@ -2783,6 +2809,9 @@ TEST_F(TransportSecurityStateStaticTest, IsPreloaded) {
}
TEST_F(TransportSecurityStateStaticTest, PreloadedDomainSet) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
@@ -2801,6 +2830,9 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedDomainSet) {
}
TEST_F(TransportSecurityStateStaticTest, Preloaded) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
@@ -3017,6 +3049,9 @@ TEST_F(TransportSecurityStateStaticTest, Preloaded) {
}
TEST_F(TransportSecurityStateStaticTest, PreloadedPins) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
@@ -3083,6 +3118,9 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedPins) {
}
TEST_F(TransportSecurityStateStaticTest, BuiltinCertPins) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
EnableStaticPins(&state);
TransportSecurityState::PKPState pkp_state;
@@ -3139,6 +3177,9 @@ TEST_F(TransportSecurityStateStaticTest, BuiltinCertPins) {
}
TEST_F(TransportSecurityStateStaticTest, OptionalHSTSCertPins) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
TransportSecurityState state;
EnableStaticPins(&state);
@@ -3162,11 +3203,16 @@ TEST_F(TransportSecurityStateStaticTest, OptionalHSTSCertPins) {
}
TEST_F(TransportSecurityStateStaticTest, OverrideBuiltins) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
EXPECT_TRUE(HasStaticPublicKeyPins("google.com"));
EXPECT_FALSE(StaticShouldRedirect("google.com"));
EXPECT_FALSE(StaticShouldRedirect("www.google.com"));
TransportSecurityState state;
+ state.SetPinningListAlwaysTimelyForTesting(true);
+
const base::Time current_time(base::Time::Now());
const base::Time expiry = current_time + base::Seconds(1000);
state.AddHSTS("www.google.com", expiry, true);
@@ -3176,6 +3222,9 @@ TEST_F(TransportSecurityStateStaticTest, OverrideBuiltins) {
// Tests that redundant reports are rate-limited.
TEST_F(TransportSecurityStateStaticTest, HPKPReportRateLimiting) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
HostPortPair subdomain_host_port_pair(kSubdomain, kPort);
GURL report_uri(kReportUri);
@@ -3238,6 +3287,9 @@ TEST_F(TransportSecurityStateStaticTest, HPKPReportRateLimiting) {
}
TEST_F(TransportSecurityStateStaticTest, HPKPReporting) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
HostPortPair subdomain_host_port_pair(kSubdomain, kPort);
GURL report_uri(kReportUri);
@@ -3882,6 +3934,9 @@ TEST_F(TransportSecurityStateTest, PruneExpectCTNetworkIsolationKeyLimit) {
}
TEST_F(TransportSecurityStateTest, UpdateKeyPinsListValidPin) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
GURL report_uri(kReportUri);
NetworkIsolationKey network_isolation_key =
@@ -3938,6 +3993,9 @@ TEST_F(TransportSecurityStateTest, UpdateKeyPinsListValidPin) {
}
TEST_F(TransportSecurityStateTest, UpdateKeyPinsListNotValidPin) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
GURL report_uri(kReportUri);
NetworkIsolationKey network_isolation_key =
@@ -3994,6 +4052,9 @@ TEST_F(TransportSecurityStateTest, UpdateKeyPinsListNotValidPin) {
}
TEST_F(TransportSecurityStateTest, UpdateKeyPinsEmptyList) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
GURL report_uri(kReportUri);
NetworkIsolationKey network_isolation_key =
@@ -4035,6 +4096,9 @@ TEST_F(TransportSecurityStateTest, UpdateKeyPinsEmptyList) {
}
TEST_F(TransportSecurityStateTest, UpdateKeyPinsListTimestamp) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kStaticKeyPinningEnforcement);
HostPortPair host_port_pair(kHost, kPort);
GURL report_uri(kReportUri);
NetworkIsolationKey network_isolation_key =
@@ -4064,6 +4128,12 @@ TEST_F(TransportSecurityStateTest, UpdateKeyPinsListTimestamp) {
TransportSecurityState::ENABLE_PIN_REPORTS,
network_isolation_key, &unused_failure_log));
+ // TransportSecurityStateTest sets a flag when EnableStaticPins is called that
+ // results in TransportSecurityState considering the pins list as always
+ // timely. We need to disable it so we can test that the timestamp has the
+ // required effect.
+ state.SetPinningListAlwaysTimelyForTesting(false);
+
// Update the pins list, with bad hashes as rejected, but a timestamp >70 days
// old.
std::vector<std::vector<uint8_t>> rejected_hashes;
@@ -4102,4 +4172,48 @@ TEST_F(TransportSecurityStateTest, UpdateKeyPinsListTimestamp) {
network_isolation_key, &unused_failure_log));
}
+class TransportSecurityStatePinningKillswitchTest
+ : public TransportSecurityStateTest {
+ public:
+ void SetUp() override {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kStaticKeyPinningEnforcement);
+ TransportSecurityStateTest::SetUp();
+ }
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(TransportSecurityStatePinningKillswitchTest, PinningKillswitchSet) {
+ HostPortPair host_port_pair(kHost, kPort);
+ GURL report_uri(kReportUri);
+ NetworkIsolationKey network_isolation_key =
+ NetworkIsolationKey::CreateTransient();
+ // Two dummy certs to use as the server-sent and validated chains. The
+ // contents don't matter.
+ scoped_refptr<X509Certificate> cert1 =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+ ASSERT_TRUE(cert1);
+ scoped_refptr<X509Certificate> cert2 =
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+ ASSERT_TRUE(cert2);
+
+ HashValueVector bad_hashes;
+
+ for (size_t i = 0; kBadPath[i]; i++)
+ EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes));
+
+ TransportSecurityState state;
+ EnableStaticPins(&state);
+ std::string unused_failure_log;
+
+ // Hashes should be accepted since pinning enforcement is disabled.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::OK,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+}
+
} // namespace net