summaryrefslogtreecommitdiff
path: root/chromium/net/http
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-05-17 17:24:03 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-06-22 07:51:41 +0000
commit774f54339e5db91f785733232d3950366db65d07 (patch)
tree068e1b47bd1af94d77094ed12b604a6b83d9c22a /chromium/net/http
parentf7eaed5286974984ba5f9e3189d8f49d03e99f81 (diff)
downloadqtwebengine-chromium-774f54339e5db91f785733232d3950366db65d07.tar.gz
BASELINE: Update Chromium to 102.0.5005.57
Change-Id: I885f714bb40ee724c28f94ca6bd8dbdb39915158 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/http')
-rw-r--r--chromium/net/http/alternative_service.cc2
-rw-r--r--chromium/net/http/alternative_service.h4
-rw-r--r--chromium/net/http/bidirectional_stream.cc4
-rw-r--r--chromium/net/http/bidirectional_stream.h2
-rw-r--r--chromium/net/http/bidirectional_stream_impl.h2
-rw-r--r--chromium/net/http/bidirectional_stream_unittest.cc17
-rw-r--r--chromium/net/http/broken_alternative_services.cc69
-rw-r--r--chromium/net/http/broken_alternative_services.h16
-rw-r--r--chromium/net/http/broken_alternative_services_unittest.cc85
-rw-r--r--chromium/net/http/http_auth.cc5
-rw-r--r--chromium/net/http/http_auth_cache_unittest.cc1
-rw-r--r--chromium/net/http/http_auth_controller.cc2
-rw-r--r--chromium/net/http/http_auth_filter_unittest.cc3
-rw-r--r--chromium/net/http/http_auth_gssapi_posix.cc3
-rw-r--r--chromium/net/http/http_auth_gssapi_posix_unittest.cc7
-rw-r--r--chromium/net/http/http_auth_handler_basic_unittest.cc7
-rw-r--r--chromium/net/http/http_auth_handler_digest_unittest.cc8
-rw-r--r--chromium/net/http/http_auth_handler_factory.cc1
-rw-r--r--chromium/net/http/http_auth_handler_factory.h1
-rw-r--r--chromium/net/http/http_auth_handler_negotiate_unittest.cc3
-rw-r--r--chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc3
-rw-r--r--chromium/net/http/http_auth_unittest.cc3
-rw-r--r--chromium/net/http/http_basic_state.cc3
-rw-r--r--chromium/net/http/http_basic_stream.cc18
-rw-r--r--chromium/net/http/http_basic_stream.h11
-rw-r--r--chromium/net/http/http_byte_range_unittest.cc8
-rw-r--r--chromium/net/http/http_cache.cc12
-rw-r--r--chromium/net/http/http_cache_transaction.cc303
-rw-r--r--chromium/net/http/http_cache_transaction.h23
-rw-r--r--chromium/net/http/http_cache_unittest.cc520
-rw-r--r--chromium/net/http/http_chunked_decoder_unittest.cc61
-rw-r--r--chromium/net/http/http_content_disposition_unittest.cc7
-rw-r--r--chromium/net/http/http_network_layer.cc2
-rw-r--r--chromium/net/http/http_network_session.cc23
-rw-r--r--chromium/net/http/http_network_session.h2
-rw-r--r--chromium/net/http/http_network_transaction.cc67
-rw-r--r--chromium/net/http/http_network_transaction.h9
-rw-r--r--chromium/net/http/http_network_transaction_unittest.cc139
-rw-r--r--chromium/net/http/http_proxy_connect_job_unittest.cc27
-rw-r--r--chromium/net/http/http_response_body_drainer_unittest.cc7
-rw-r--r--chromium/net/http/http_response_headers.cc13
-rw-r--r--chromium/net/http/http_response_info.cc2
-rw-r--r--chromium/net/http/http_security_headers_unittest.cc3
-rw-r--r--chromium/net/http/http_server_properties.cc42
-rw-r--r--chromium/net/http/http_server_properties.h17
-rw-r--r--chromium/net/http/http_server_properties_manager.cc24
-rw-r--r--chromium/net/http/http_server_properties_manager_unittest.cc2
-rw-r--r--chromium/net/http/http_server_properties_unittest.cc62
-rw-r--r--chromium/net/http/http_stream.h24
-rw-r--r--chromium/net/http/http_stream_factory.cc6
-rw-r--r--chromium/net/http/http_stream_factory_job.cc3
-rw-r--r--chromium/net/http/http_stream_factory_job_controller.cc8
-rw-r--r--chromium/net/http/http_stream_factory_job_controller.h1
-rw-r--r--chromium/net/http/http_stream_factory_job_controller_unittest.cc3
-rw-r--r--chromium/net/http/http_stream_factory_unittest.cc64
-rw-r--r--chromium/net/http/http_stream_parser.cc26
-rw-r--r--chromium/net/http/http_stream_parser.h1
-rw-r--r--chromium/net/http/http_stream_parser_unittest.cc23
-rw-r--r--chromium/net/http/http_transaction.h2
-rw-r--r--chromium/net/http/http_transaction_test_util.cc8
-rw-r--r--chromium/net/http/http_transaction_test_util.h3
-rw-r--r--chromium/net/http/http_util.cc18
-rw-r--r--chromium/net/http/http_util.h8
-rw-r--r--chromium/net/http/http_util_unittest.cc25
-rw-r--r--chromium/net/http/http_vary_data_unittest.cc39
-rw-r--r--chromium/net/http/mock_http_cache.cc1
-rw-r--r--chromium/net/http/mock_sspi_library_win.cc1
-rw-r--r--chromium/net/http/structured_headers.cc144
-rw-r--r--chromium/net/http/structured_headers.h19
-rw-r--r--chromium/net/http/structured_headers_generated_unittest.cc513
-rw-r--r--chromium/net/http/structured_headers_unittest.cc5
-rw-r--r--chromium/net/http/transport_security_persister.cc1
-rw-r--r--chromium/net/http/transport_security_state.cc123
-rw-r--r--chromium/net/http/transport_security_state.h73
-rw-r--r--chromium/net/http/transport_security_state_static.json.gzbin1329924 -> 1353766 bytes
-rw-r--r--chromium/net/http/transport_security_state_static.template5
-rw-r--r--chromium/net/http/transport_security_state_static_fuzzer.cc3
-rw-r--r--chromium/net/http/transport_security_state_static_unittest.template6
-rw-r--r--chromium/net/http/transport_security_state_test_util.cc2
-rw-r--r--chromium/net/http/transport_security_state_unittest.cc390
-rw-r--r--chromium/net/http/url_security_manager_unittest.cc7
81 files changed, 2378 insertions, 832 deletions
diff --git a/chromium/net/http/alternative_service.cc b/chromium/net/http/alternative_service.cc
index 457ab2dd12b..f713303c2af 100644
--- a/chromium/net/http/alternative_service.cc
+++ b/chromium/net/http/alternative_service.cc
@@ -10,7 +10,7 @@
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "net/base/port_util.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
namespace net {
diff --git a/chromium/net/http/alternative_service.h b/chromium/net/http/alternative_service.h
index 473292ad0ad..91dbc76a7b1 100644
--- a/chromium/net/http/alternative_service.h
+++ b/chromium/net/http/alternative_service.h
@@ -16,8 +16,8 @@
#include "net/base/net_export.h"
#include "net/quic/quic_http_utils.h"
#include "net/socket/next_proto.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
namespace net {
diff --git a/chromium/net/http/bidirectional_stream.cc b/chromium/net/http/bidirectional_stream.cc
index b009fa6227d..cdd0aa3586e 100644
--- a/chromium/net/http/bidirectional_stream.cc
+++ b/chromium/net/http/bidirectional_stream.cc
@@ -29,7 +29,7 @@
#include "net/spdy/spdy_log_util.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_config.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_header_block.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "url/gurl.h"
@@ -237,7 +237,7 @@ void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
void BidirectionalStream::OnHeadersReceived(
const spdy::Http2HeaderBlock& response_headers) {
HttpResponseInfo response_info;
- if (!SpdyHeadersToHttpResponse(response_headers, &response_info)) {
+ if (SpdyHeadersToHttpResponse(response_headers, &response_info) != OK) {
DLOG(WARNING) << "Invalid headers";
NotifyFailed(ERR_FAILED);
return;
diff --git a/chromium/net/http/bidirectional_stream.h b/chromium/net/http/bidirectional_stream.h
index 84e394deb7c..17413441445 100644
--- a/chromium/net/http/bidirectional_stream.h
+++ b/chromium/net/http/bidirectional_stream.h
@@ -21,7 +21,7 @@
#include "net/http/http_stream_factory.h"
#include "net/http/http_stream_request.h"
#include "net/log/net_log_with_source.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_header_block.h"
namespace base {
class OneShotTimer;
diff --git a/chromium/net/http/bidirectional_stream_impl.h b/chromium/net/http/bidirectional_stream_impl.h
index 28d7dc2eb72..51a068741db 100644
--- a/chromium/net/http/bidirectional_stream_impl.h
+++ b/chromium/net/http/bidirectional_stream_impl.h
@@ -14,7 +14,7 @@
#include "net/base/load_timing_info.h"
#include "net/base/net_export.h"
#include "net/socket/next_proto.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_header_block.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace base {
diff --git a/chromium/net/http/bidirectional_stream_unittest.cc b/chromium/net/http/bidirectional_stream_unittest.cc
index 6fc29ca45f0..60c45dd446a 100644
--- a/chromium/net/http/bidirectional_stream_unittest.cc
+++ b/chromium/net/http/bidirectional_stream_unittest.cc
@@ -10,7 +10,6 @@
#include <vector>
#include "base/containers/span.h"
-#include "base/cxx17_backports.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
@@ -55,7 +54,7 @@ namespace net {
namespace {
const char kBodyData[] = "Body data";
-const size_t kBodyDataSize = base::size(kBodyData);
+const size_t kBodyDataSize = std::size(kBodyData);
const std::string kBodyDataString(kBodyData, kBodyDataSize);
// Size of the buffer to be allocated for each read.
const size_t kReadBufferSize = 4096;
@@ -1351,7 +1350,7 @@ TEST_F(BidirectionalStreamTest, DeleteStreamAfterSendData) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
}
@@ -1411,11 +1410,11 @@ TEST_F(BidirectionalStreamTest, DeleteStreamDuringReadData) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
// Response body frame isn't read becase stream is deleted once read returns
// ERR_IO_PENDING.
- EXPECT_EQ(CountReadBytes(base::make_span(reads).first(base::size(reads) - 2)),
+ EXPECT_EQ(CountReadBytes(base::make_span(reads).first(std::size(reads) - 2)),
delegate->GetTotalReceivedBytes());
}
@@ -1530,7 +1529,7 @@ TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnHeadersReceived) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
}
@@ -1585,7 +1584,7 @@ TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnDataRead) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
}
@@ -1645,7 +1644,7 @@ TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnTrailersReceived) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
}
@@ -1696,7 +1695,7 @@ TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnFailed) {
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
// Bytes sent excludes the RST frame.
EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(base::size(writes) - 1)),
+ CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
delegate->GetTotalSentBytes());
EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
}
diff --git a/chromium/net/http/broken_alternative_services.cc b/chromium/net/http/broken_alternative_services.cc
index d938b4b7fff..9bde04df272 100644
--- a/chromium/net/http/broken_alternative_services.cc
+++ b/chromium/net/http/broken_alternative_services.cc
@@ -5,6 +5,7 @@
#include "net/http/broken_alternative_services.h"
#include "base/bind.h"
+#include "base/containers/adapters.h"
#include "base/memory/singleton.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
@@ -14,19 +15,44 @@ namespace net {
namespace {
-// Initial delay for broken alternative services.
-const uint64_t kBrokenAlternativeProtocolDelaySecs = 300;
+// Default broken alternative services, which is used when
+// exponential_backoff_on_initial_delay is false.
+constexpr base::TimeDelta kDefaultBrokenAlternativeProtocolDelay =
+ base::Seconds(300);
// Subsequent failures result in exponential (base 2) backoff.
-// Limit binary shift to limit delay to approximately 2 days.
-const int kBrokenDelayMaxShift = 9;
+// Given the shortest broken delay is 1s, limit binary shift to limit delay to
+// approximately 2 days.
+const int kBrokenDelayMaxShift = 18;
+// Lower and upper limits of broken alternative service delay.
+constexpr base::TimeDelta kMinBrokenAlternativeProtocolDelay = base::Seconds(1);
+constexpr base::TimeDelta kMaxBrokenAlternativeProtocolDelay = base::Days(2);
base::TimeDelta ComputeBrokenAlternativeServiceExpirationDelay(
- int broken_count) {
+ int broken_count,
+ base::TimeDelta initial_delay,
+ bool exponential_backoff_on_initial_delay) {
DCHECK_GE(broken_count, 0);
- if (broken_count > kBrokenDelayMaxShift)
+ // Make sure initial delay is within [1s, 300s].
+ if (initial_delay < kMinBrokenAlternativeProtocolDelay) {
+ initial_delay = kMinBrokenAlternativeProtocolDelay;
+ }
+ if (initial_delay > kDefaultBrokenAlternativeProtocolDelay) {
+ initial_delay = kDefaultBrokenAlternativeProtocolDelay;
+ }
+ if (broken_count == 0) {
+ return initial_delay;
+ }
+ // Limit broken_count to avoid overflow.
+ if (broken_count > kBrokenDelayMaxShift) {
broken_count = kBrokenDelayMaxShift;
- return base::Seconds(kBrokenAlternativeProtocolDelaySecs) *
- (1 << broken_count);
+ }
+ base::TimeDelta delay;
+ if (exponential_backoff_on_initial_delay) {
+ delay = initial_delay * (1 << broken_count);
+ } else {
+ delay = kDefaultBrokenAlternativeProtocolDelay * (1 << (broken_count - 1));
+ }
+ return std::min(delay, kMaxBrokenAlternativeProtocolDelay);
}
} // namespace
@@ -55,7 +81,9 @@ BrokenAlternativeServices::BrokenAlternativeServices(
: delegate_(delegate),
clock_(clock),
recently_broken_alternative_services_(
- max_recently_broken_alternative_service_entries) {
+ max_recently_broken_alternative_service_entries),
+ initial_delay_(kDefaultBrokenAlternativeProtocolDelay),
+ exponential_backoff_on_initial_delay_(true) {
DCHECK(delegate_);
DCHECK(clock_);
}
@@ -108,7 +136,8 @@ void BrokenAlternativeServices::MarkBrokenImpl(
}
base::TimeTicks expiration =
clock_->NowTicks() +
- ComputeBrokenAlternativeServiceExpirationDelay(broken_count);
+ ComputeBrokenAlternativeServiceExpirationDelay(
+ broken_count, initial_delay_, exponential_backoff_on_initial_delay_);
// Return if alternative service is already in expiration queue.
BrokenAlternativeServiceList::iterator list_it;
if (!AddToBrokenListAndMap(broken_alternative_service, expiration,
@@ -223,11 +252,11 @@ void BrokenAlternativeServices::SetBrokenAndRecentlyBrokenAlternativeServices(
*recently_broken_alternative_services);
// Add back all existing recently broken alt svcs to cache so they're at
// front of recency list (LRUCache::Get() does this automatically).
- for (auto it = recently_broken_alternative_services->rbegin();
- it != recently_broken_alternative_services->rend(); ++it) {
- if (recently_broken_alternative_services_.Get(it->first) ==
+ for (const auto& [service, broken_count] :
+ base::Reversed(*recently_broken_alternative_services)) {
+ if (recently_broken_alternative_services_.Get(service) ==
recently_broken_alternative_services_.end()) {
- recently_broken_alternative_services_.Put(it->first, it->second);
+ recently_broken_alternative_services_.Put(service, broken_count);
}
}
@@ -286,6 +315,18 @@ void BrokenAlternativeServices::SetBrokenAndRecentlyBrokenAlternativeServices(
ScheduleBrokenAlternateProtocolMappingsExpiration();
}
+void BrokenAlternativeServices::SetDelayParams(
+ absl::optional<base::TimeDelta> initial_delay,
+ absl::optional<bool> exponential_backoff_on_initial_delay) {
+ if (initial_delay.has_value()) {
+ initial_delay_ = initial_delay.value();
+ }
+ if (exponential_backoff_on_initial_delay.has_value()) {
+ exponential_backoff_on_initial_delay_ =
+ exponential_backoff_on_initial_delay.value();
+ }
+}
+
const BrokenAlternativeServiceList&
BrokenAlternativeServices::broken_alternative_service_list() const {
return broken_alternative_service_list_;
diff --git a/chromium/net/http/broken_alternative_services.h b/chromium/net/http/broken_alternative_services.h
index c4fd7317317..56c8dfd6b74 100644
--- a/chromium/net/http/broken_alternative_services.h
+++ b/chromium/net/http/broken_alternative_services.h
@@ -155,6 +155,13 @@ class NET_EXPORT_PRIVATE BrokenAlternativeServices {
std::unique_ptr<RecentlyBrokenAlternativeServices>
recently_broken_alternative_services);
+ // If values are present, sets initial_delay_ and
+ // exponential_backoff_on_initial_delay_ which are used to calculate delay of
+ // broken alternative services.
+ void SetDelayParams(
+ absl::optional<base::TimeDelta> initial_delay,
+ absl::optional<bool> exponential_backoff_on_initial_delay);
+
const BrokenAlternativeServiceList& broken_alternative_service_list() const;
const RecentlyBrokenAlternativeServices&
@@ -215,6 +222,15 @@ class NET_EXPORT_PRIVATE BrokenAlternativeServices {
// services.
base::OneShotTimer expiration_timer_;
+ // Delay for the 1st time alternative service is marked broken.
+ base::TimeDelta initial_delay_;
+
+ // If true, the delay for broken alternative service =
+ // 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_;
+
base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_{this};
};
diff --git a/chromium/net/http/broken_alternative_services_unittest.cc b/chromium/net/http/broken_alternative_services_unittest.cc
index 66e99013f69..1f331acfe6d 100644
--- a/chromium/net/http/broken_alternative_services_unittest.cc
+++ b/chromium/net/http/broken_alternative_services_unittest.cc
@@ -10,6 +10,7 @@
#include "base/memory/raw_ptr.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/tick_clock.h"
+#include "base/time/time.h"
#include "net/base/network_isolation_key.h"
#include "net/base/schemeful_site.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,6 +47,9 @@ class BrokenAlternativeServicesTest
true /* use_network_isolation_key */));
}
+ void TestExponentialBackoff(base::TimeDelta initial_delay,
+ bool exponential_backoff_on_initial_delay);
+
// All tests will run inside the scope of |test_task_runner_context_|, which
// means any task posted to the main message loop will run on
// |test_task_runner_|.
@@ -640,10 +644,89 @@ TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff) {
// Max expiration delay has been reached; subsequent expiration delays from
// this point forward should not increase further.
broken_services_.MarkBroken(alternative_service);
- test_task_runner_->FastForwardBy(base::Minutes(2560) - base::Seconds(1));
+ test_task_runner_->FastForwardBy(base::Minutes(2880) - base::Seconds(1));
+ EXPECT_TRUE(broken_services_.IsBroken(alternative_service));
+ test_task_runner_->FastForwardBy(base::Seconds(1));
+ EXPECT_FALSE(broken_services_.IsBroken(alternative_service));
+
+ broken_services_.MarkBroken(alternative_service);
+ test_task_runner_->FastForwardBy(base::Minutes(2880) - base::Seconds(1));
+ EXPECT_TRUE(broken_services_.IsBroken(alternative_service));
+ test_task_runner_->FastForwardBy(base::Seconds(1));
+ EXPECT_FALSE(broken_services_.IsBroken(alternative_service));
+}
+
+void BrokenAlternativeServicesTest::TestExponentialBackoff(
+ base::TimeDelta initial_delay,
+ bool exponential_backoff_on_initial_delay) {
+ // Tests the exponential backoff of the computed expiration delay when an
+ // alt svc is marked broken. After being marked broken 10 times, the max
+ // expiration delay will have been reached and exponential backoff will no
+ // longer apply.
+ broken_services_.SetDelayParams(initial_delay,
+ exponential_backoff_on_initial_delay);
+
+ BrokenAlternativeService alternative_service(
+ AlternativeService(kProtoQUIC, "foo", 443), NetworkIsolationKey(),
+ true /* use_network_isolation_key */);
+
+ broken_services_.MarkBroken(alternative_service);
+ test_task_runner_->FastForwardBy(initial_delay - base::Seconds(1));
EXPECT_TRUE(broken_services_.IsBroken(alternative_service));
test_task_runner_->FastForwardBy(base::Seconds(1));
EXPECT_FALSE(broken_services_.IsBroken(alternative_service));
+
+ for (size_t broken_count = 1; broken_count < 20; ++broken_count) {
+ broken_services_.MarkBroken(alternative_service);
+ base::TimeDelta broken_delay;
+ if (exponential_backoff_on_initial_delay) {
+ broken_delay = initial_delay * (1 << broken_count);
+ } else {
+ broken_delay = base::Seconds(kBrokenAlternativeProtocolDelaySecs) *
+ (1 << (broken_count - 1));
+ }
+ if (broken_delay > base::Days(2)) {
+ broken_delay = base::Days(2);
+ }
+ test_task_runner_->FastForwardBy(broken_delay - base::Seconds(1));
+ EXPECT_TRUE(broken_services_.IsBroken(alternative_service));
+ test_task_runner_->FastForwardBy(base::Seconds(1));
+ EXPECT_FALSE(broken_services_.IsBroken(alternative_service));
+ }
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_OneSecond_True) {
+ TestExponentialBackoff(base::Seconds(1), true);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_OneSecond_False) {
+ TestExponentialBackoff(base::Seconds(1), false);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_FiveSeconds_True) {
+ TestExponentialBackoff(base::Seconds(5), true);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_FiveSeconds_False) {
+ TestExponentialBackoff(base::Seconds(5), false);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_TenSeconds_True) {
+ TestExponentialBackoff(base::Seconds(10), true);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_TenSeconds_False) {
+ TestExponentialBackoff(base::Seconds(10), false);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_FiveMinutes_True) {
+ TestExponentialBackoff(base::Seconds(kBrokenAlternativeProtocolDelaySecs),
+ true);
+}
+
+TEST_F(BrokenAlternativeServicesTest, ExponentialBackoff_FiveMinutes_False) {
+ TestExponentialBackoff(base::Seconds(kBrokenAlternativeProtocolDelaySecs),
+ false);
}
TEST_F(BrokenAlternativeServicesTest, RemoveExpiredBrokenAltSvc) {
diff --git a/chromium/net/http/http_auth.cc b/chromium/net/http/http_auth.cc
index be1cda1b53f..bd9cbc1e57e 100644
--- a/chromium/net/http/http_auth.cc
+++ b/chromium/net/http/http_auth.cc
@@ -6,7 +6,6 @@
#include <algorithm>
-#include "base/cxx17_backports.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/values.h"
@@ -145,7 +144,7 @@ std::string HttpAuth::GetAuthTargetString(Target target) {
// static
const char* HttpAuth::SchemeToString(Scheme scheme) {
- static_assert(base::size(kSchemeNames) == AUTH_SCHEME_MAX,
+ static_assert(std::size(kSchemeNames) == AUTH_SCHEME_MAX,
"http auth scheme names incorrect size");
if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) {
NOTREACHED();
@@ -156,7 +155,7 @@ const char* HttpAuth::SchemeToString(Scheme scheme) {
// static
HttpAuth::Scheme HttpAuth::StringToScheme(const std::string& str) {
- for (uint8_t i = 0; i < base::size(kSchemeNames); i++) {
+ for (uint8_t i = 0; i < std::size(kSchemeNames); i++) {
if (str == kSchemeNames[i])
return static_cast<Scheme>(i);
}
diff --git a/chromium/net/http/http_auth_cache_unittest.cc b/chromium/net/http/http_auth_cache_unittest.cc
index 600b3d91afb..c2f2ce7c6e4 100644
--- a/chromium/net/http/http_auth_cache_unittest.cc
+++ b/chromium/net/http/http_auth_cache_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
#include "net/base/net_errors.h"
#include "net/base/network_isolation_key.h"
#include "net/base/schemeful_site.h"
diff --git a/chromium/net/http/http_auth_controller.cc b/chromium/net/http/http_auth_controller.cc
index 40e13b0388e..90509517519 100644
--- a/chromium/net/http/http_auth_controller.cc
+++ b/chromium/net/http/http_auth_controller.cc
@@ -558,7 +558,7 @@ void HttpAuthController::PopulateAuthChallenge() {
auth_info_ = AuthChallengeInfo();
auth_info_->is_proxy = (target_ == HttpAuth::AUTH_PROXY);
- auth_info_->challenger = url::Origin::Create(auth_scheme_host_port_.GetURL());
+ auth_info_->challenger = auth_scheme_host_port_;
auth_info_->scheme = HttpAuth::SchemeToString(handler_->auth_scheme());
auth_info_->realm = handler_->realm();
auth_info_->path = auth_path_;
diff --git a/chromium/net/http/http_auth_filter_unittest.cc b/chromium/net/http/http_auth_filter_unittest.cc
index 625ac69f30d..5ac316358d0 100644
--- a/chromium/net/http/http_auth_filter_unittest.cc
+++ b/chromium/net/http/http_auth_filter_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include <ostream>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
@@ -68,7 +67,7 @@ TEST(HttpAuthFilterTest, EmptyFilter) {
TEST(HttpAuthFilterTest, NonEmptyFilter) {
// Create an non-empty filter
std::string server_allowlist_filter_string;
- for (size_t i = 0; i < base::size(server_allowlist_array); ++i) {
+ for (size_t i = 0; i < std::size(server_allowlist_array); ++i) {
if (!server_allowlist_filter_string.empty())
server_allowlist_filter_string += ",";
server_allowlist_filter_string += "*";
diff --git a/chromium/net/http/http_auth_gssapi_posix.cc b/chromium/net/http/http_auth_gssapi_posix.cc
index 3d649e59b27..e4c25d2b923 100644
--- a/chromium/net/http/http_auth_gssapi_posix.cc
+++ b/chromium/net/http/http_auth_gssapi_posix.cc
@@ -9,7 +9,6 @@
#include "base/base64.h"
#include "base/compiler_specific.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/format_macros.h"
#include "base/logging.h"
@@ -380,7 +379,7 @@ base::NativeLibrary GSSAPISharedLibrary::LoadSharedLibrary(
#endif
};
library_names = kDefaultLibraryNames;
- num_lib_names = base::size(kDefaultLibraryNames);
+ num_lib_names = std::size(kDefaultLibraryNames);
}
net_log.BeginEvent(NetLogEventType::AUTH_LIBRARY_LOAD);
diff --git a/chromium/net/http/http_auth_gssapi_posix_unittest.cc b/chromium/net/http/http_auth_gssapi_posix_unittest.cc
index 4820b7e3d8a..92a9cd7945c 100644
--- a/chromium/net/http/http_auth_gssapi_posix_unittest.cc
+++ b/chromium/net/http/http_auth_gssapi_posix_unittest.cc
@@ -9,7 +9,6 @@
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/check.h"
-#include "base/cxx17_backports.h"
#include "base/json/json_reader.h"
#include "base/native_library.h"
#include "base/path_service.h"
@@ -69,7 +68,7 @@ void EstablishInitialContext(test::MockGSSAPILibrary* library) {
1, // Locally initiated
0); // Open
gss_buffer_desc in_buffer = {0, nullptr};
- gss_buffer_desc out_buffer = {base::size(kInitialAuthResponse),
+ gss_buffer_desc out_buffer = {std::size(kInitialAuthResponse),
const_cast<char*>(kInitialAuthResponse)};
library->ExpectSecurityContext(
"Negotiate",
@@ -221,7 +220,7 @@ TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
kAuthResponse) // Output token
};
- for (size_t i = 0; i < base::size(queries); ++i) {
+ for (size_t i = 0; i < std::size(queries); ++i) {
mock_library->ExpectSecurityContext(queries[i].expected_package,
queries[i].response_code,
queries[i].minor_response_code,
@@ -244,7 +243,7 @@ TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
gss_buffer_desc output_token = {0, nullptr};
OM_uint32 ret_flags = 0;
OM_uint32 time_rec = 0;
- for (size_t i = 0; i < base::size(queries); ++i) {
+ for (size_t i = 0; i < std::size(queries); ++i) {
major_status = mock_library->init_sec_context(&minor_status,
initiator_cred_handle,
&context_handle,
diff --git a/chromium/net/http/http_auth_handler_basic_unittest.cc b/chromium/net/http/http_auth_handler_basic_unittest.cc
index ce3064abf19..e87b89b3ee1 100644
--- a/chromium/net/http/http_auth_handler_basic_unittest.cc
+++ b/chromium/net/http/http_auth_handler_basic_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include <string>
-#include "base/cxx17_backports.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/net_errors.h"
@@ -45,7 +44,7 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
};
url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
HttpAuthHandlerBasic::Factory factory;
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string challenge = "Basic realm=\"Atlantis\"";
SSLInfo null_ssl_info;
auto host_resolver = std::make_unique<MockHostResolver>();
@@ -111,7 +110,7 @@ TEST(HttpAuthHandlerBasicTest, HandleAnotherChallenge) {
NetworkIsolationKey(), scheme_host_port, NetLogWithSource(),
host_resolver.get(), &basic));
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string challenge(tests[i].challenge);
HttpAuthChallengeTokenizer tok(challenge.begin(),
challenge.end());
@@ -204,7 +203,7 @@ TEST(HttpAuthHandlerBasicTest, InitFromChallenge) {
};
HttpAuthHandlerBasic::Factory factory;
url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string challenge = tests[i].challenge;
SSLInfo null_ssl_info;
auto host_resolver = std::make_unique<MockHostResolver>();
diff --git a/chromium/net/http/http_auth_handler_digest_unittest.cc b/chromium/net/http/http_auth_handler_digest_unittest.cc
index 1fd6c275d64..de6b127775f 100644
--- a/chromium/net/http/http_auth_handler_digest_unittest.cc
+++ b/chromium/net/http/http_auth_handler_digest_unittest.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/http/http_auth_handler_digest.h"
+
#include <string>
-#include "base/cxx17_backports.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/net_errors.h"
@@ -12,7 +13,6 @@
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_auth_challenge_tokenizer.h"
-#include "net/http/http_auth_handler_digest.h"
#include "net/http/http_request_info.h"
#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
@@ -364,7 +364,7 @@ TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
std::unique_ptr<HttpAuthHandlerDigest::Factory> factory(
new HttpAuthHandlerDigest::Factory());
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
SSLInfo null_ssl_info;
auto host_resolver = std::make_unique<MockHostResolver>();
std::unique_ptr<HttpAuthHandler> handler;
@@ -530,7 +530,7 @@ TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
std::unique_ptr<HttpAuthHandlerDigest::Factory> factory(
new HttpAuthHandlerDigest::Factory());
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
SSLInfo null_ssl_info;
auto host_resolver = std::make_unique<MockHostResolver>();
std::unique_ptr<HttpAuthHandler> handler;
diff --git a/chromium/net/http/http_auth_handler_factory.cc b/chromium/net/http/http_auth_handler_factory.cc
index f5cc9aea404..05e0a4416aa 100644
--- a/chromium/net/http/http_auth_handler_factory.cc
+++ b/chromium/net/http/http_auth_handler_factory.cc
@@ -22,6 +22,7 @@
#include "net/log/net_log_values.h"
#include "net/net_buildflags.h"
#include "net/ssl/ssl_info.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/scheme_host_port.h"
#if BUILDFLAG(USE_KERBEROS)
diff --git a/chromium/net/http/http_auth_handler_factory.h b/chromium/net/http/http_auth_handler_factory.h
index 5a41e68d273..683b63f3f26 100644
--- a/chromium/net/http/http_auth_handler_factory.h
+++ b/chromium/net/http/http_auth_handler_factory.h
@@ -19,6 +19,7 @@
#include "net/http/http_auth_scheme.h"
#include "net/http/url_security_manager.h"
#include "net/net_buildflags.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace url {
class SchemeHostPort;
diff --git a/chromium/net/http/http_auth_handler_negotiate_unittest.cc b/chromium/net/http/http_auth_handler_negotiate_unittest.cc
index 5178a119440..80b03874963 100644
--- a/chromium/net/http/http_auth_handler_negotiate_unittest.cc
+++ b/chromium/net/http/http_auth_handler_negotiate_unittest.cc
@@ -8,7 +8,6 @@
#include <string>
#include "base/bind.h"
-#include "base/cxx17_backports.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_util.h"
@@ -179,7 +178,7 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest,
kAuthResponse) // Output token
};
- for (size_t i = 0; i < base::size(queries); ++i) {
+ for (size_t i = 0; i < std::size(queries); ++i) {
mock_library->ExpectSecurityContext(queries[i].expected_package,
queries[i].response_code,
queries[i].minor_response_code,
diff --git a/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc b/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc
index f34a02a28b4..19175390090 100644
--- a/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc
+++ b/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc
@@ -7,7 +7,6 @@
#include "base/base64.h"
#include "base/containers/span.h"
-#include "base/cxx17_backports.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -235,7 +234,7 @@ TEST_F(HttpAuthHandlerNtlmPortableTest, NtlmV1AuthenticationSuccess) {
// Validate the authenticate message
std::string decoded;
ASSERT_TRUE(DecodeChallenge(token, &decoded));
- ASSERT_EQ(base::size(ntlm::test::kExpectedAuthenticateMsgSpecResponseV1),
+ ASSERT_EQ(std::size(ntlm::test::kExpectedAuthenticateMsgSpecResponseV1),
decoded.size());
ASSERT_EQ(0, memcmp(decoded.data(),
ntlm::test::kExpectedAuthenticateMsgSpecResponseV1,
diff --git a/chromium/net/http/http_auth_unittest.cc b/chromium/net/http/http_auth_unittest.cc
index c8e37c12c72..5bdc7fb2997 100644
--- a/chromium/net/http/http_auth_unittest.cc
+++ b/chromium/net/http/http_auth_unittest.cc
@@ -8,7 +8,6 @@
#include <set>
#include <string>
-#include "base/cxx17_backports.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
@@ -139,7 +138,7 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
http_auth_handler_factory->SetHttpAuthPreferences(kNegotiateAuthScheme,
&http_auth_preferences);
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
// Make a HttpResponseHeaders object.
std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
headers_with_status_line += tests[i].headers;
diff --git a/chromium/net/http/http_basic_state.cc b/chromium/net/http/http_basic_state.cc
index b3212b319ef..fe5233bab8d 100644
--- a/chromium/net/http/http_basic_state.cc
+++ b/chromium/net/http/http_basic_state.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
#include "base/no_destructor.h"
#include "net/base/io_buffer.h"
#include "net/http/http_request_info.h"
@@ -55,7 +54,7 @@ void HttpBasicState::DeleteParser() { parser_.reset(); }
std::string HttpBasicState::GenerateRequestLine() const {
static const char kSuffix[] = " HTTP/1.1\r\n";
- const size_t kSuffixLen = base::size(kSuffix) - 1;
+ const size_t kSuffixLen = std::size(kSuffix) - 1;
const std::string path =
using_proxy_ ? HttpUtil::SpecForRequest(url_) : url_.PathForRequest();
// Don't use StringPrintf for concatenation because it is very inefficient.
diff --git a/chromium/net/http/http_basic_stream.cc b/chromium/net/http/http_basic_stream.cc
index 03b443c360b..d82e153e47e 100644
--- a/chromium/net/http/http_basic_stream.cc
+++ b/chromium/net/http/http_basic_stream.cc
@@ -24,13 +24,18 @@ HttpBasicStream::HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection,
HttpBasicStream::~HttpBasicStream() = default;
-int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
- bool can_send_early,
+void HttpBasicStream::RegisterRequest(const HttpRequestInfo* request_info) {
+ DCHECK(request_info);
+ DCHECK(request_info->traffic_annotation.is_valid());
+ request_info_ = request_info;
+}
+
+int HttpBasicStream::InitializeStream(bool can_send_early,
RequestPriority priority,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) {
- DCHECK(request_info->traffic_annotation.is_valid());
- state_.Initialize(request_info, priority, net_log);
+ DCHECK(request_info_);
+ state_.Initialize(request_info_, priority, net_log);
int ret = OK;
if (!can_send_early) {
// parser() cannot outlive |this|, so we can use base::Unretained().
@@ -38,6 +43,8 @@ int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
base::BindOnce(&HttpBasicStream::OnHandshakeConfirmed,
base::Unretained(this), std::move(callback)));
}
+ // RequestInfo is no longer needed after this point.
+ request_info_ = nullptr;
return ret;
}
@@ -107,7 +114,8 @@ void HttpBasicStream::SetConnectionReused() {
}
bool HttpBasicStream::CanReuseConnection() const {
- return state_.connection()->socket() && parser()->CanReuseConnection();
+ return parser() && state_.connection()->socket() &&
+ parser()->CanReuseConnection();
}
int64_t HttpBasicStream::GetTotalReceivedBytes() const {
diff --git a/chromium/net/http/http_basic_stream.h b/chromium/net/http/http_basic_stream.h
index cd3c8d003c8..8c765a8e13c 100644
--- a/chromium/net/http/http_basic_stream.h
+++ b/chromium/net/http/http_basic_stream.h
@@ -45,8 +45,9 @@ class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream {
~HttpBasicStream() override;
// HttpStream methods:
- int InitializeStream(const HttpRequestInfo* request_info,
- bool can_send_early,
+ void RegisterRequest(const HttpRequestInfo* request_info) override;
+
+ int InitializeStream(bool can_send_early,
RequestPriority priority,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override;
@@ -108,6 +109,12 @@ class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream {
HttpBasicState state_;
base::TimeTicks confirm_handshake_end_;
RequestHeadersCallback request_headers_callback_;
+ // The request to send.
+ // Set to null before the response body is read. This is to allow |this| to
+ // be shared for reading and to possibly outlive request_info_'s owner.
+ // Setting to null happens after headers are completely read or upload data
+ // stream is uploaded, whichever is later.
+ raw_ptr<const HttpRequestInfo> request_info_;
};
} // namespace net
diff --git a/chromium/net/http/http_byte_range_unittest.cc b/chromium/net/http/http_byte_range_unittest.cc
index 10fc28d4c93..4e17e45fffc 100644
--- a/chromium/net/http/http_byte_range_unittest.cc
+++ b/chromium/net/http/http_byte_range_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "net/http/http_byte_range.h"
-#include "base/cxx17_backports.h"
+
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -28,7 +28,7 @@ TEST(HttpByteRangeTest, ValidRanges) {
{ -1, -1, 100000, true },
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
HttpByteRange range;
range.set_first_byte_position(tests[i].first_byte_position);
range.set_last_byte_position(tests[i].last_byte_position);
@@ -60,7 +60,7 @@ TEST(HttpByteRangeTest, SetInstanceSize) {
{ 10, 10000, -1, 1000000, true, 10, 10000 },
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
HttpByteRange range;
range.set_first_byte_position(tests[i].first_byte_position);
range.set_last_byte_position(tests[i].last_byte_position);
@@ -93,7 +93,7 @@ TEST(HttpByteRangeTest, GetHeaderValue) {
{HttpByteRange::RightUnbounded(100), "bytes=100-"},
{HttpByteRange::Suffix(100), "bytes=-100"},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
EXPECT_EQ(tests[i].expected, tests[i].range.GetHeaderValue());
}
}
diff --git a/chromium/net/http/http_cache.cc b/chromium/net/http/http_cache.cc
index 6918f291d72..5aed1148698 100644
--- a/chromium/net/http/http_cache.cc
+++ b/chromium/net/http/http_cache.cc
@@ -28,7 +28,6 @@
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
-#include "base/time/time.h"
#include "build/build_config.h"
#include "net/base/cache_type.h"
#include "net/base/features.h"
@@ -101,13 +100,14 @@ int HttpCache::DefaultBackend::CreateBackend(
#if BUILDFLAG(IS_ANDROID)
if (app_status_listener_) {
return disk_cache::CreateCacheBackend(
- type_, backend_type_, path_, max_bytes_, reset_handling, net_log,
- backend, std::move(callback), app_status_listener_);
+ type_, backend_type_, /*file_operations=*/nullptr, path_, max_bytes_,
+ reset_handling, net_log, backend, std::move(callback),
+ app_status_listener_);
}
#endif
- return disk_cache::CreateCacheBackend(type_, backend_type_, path_, max_bytes_,
- reset_handling, net_log, backend,
- std::move(callback));
+ return disk_cache::CreateCacheBackend(
+ type_, backend_type_, /*file_operations=*/nullptr, path_, max_bytes_,
+ reset_handling, net_log, backend, std::move(callback));
}
#if BUILDFLAG(IS_ANDROID)
diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc
index b2729058b00..6bb6deaafdb 100644
--- a/chromium/net/http/http_cache_transaction.cc
+++ b/chromium/net/http/http_cache_transaction.cc
@@ -31,6 +31,7 @@
#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 "net/base/auth.h"
@@ -39,6 +40,7 @@
#include "net/base/load_flags.h"
#include "net/base/load_timing_info.h"
#include "net/base/trace_constants.h"
+#include "net/base/transport_info.h"
#include "net/base/upload_data_stream.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
@@ -72,15 +74,6 @@ bool NonErrorResponse(int status_code) {
return status_code_range == 2 || status_code_range == 3;
}
-void RecordNoStoreHeaderHistogram(int load_flags,
- const HttpResponseInfo* response) {
- if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) {
- UMA_HISTOGRAM_BOOLEAN(
- "Net.MainFrameNoStore",
- response->headers->HasHeaderValue("cache-control", "no-store"));
- }
-}
-
bool IsOnBatteryPower() {
if (base::PowerMonitor::IsInitialized())
return base::PowerMonitor::IsOnBatteryPower();
@@ -158,8 +151,7 @@ static bool HeaderMatches(const HttpRequestHeaders& headers,
//-----------------------------------------------------------------------------
HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
- : next_state_(STATE_NONE),
- initial_request_(nullptr),
+ : initial_request_(nullptr),
request_(nullptr),
priority_(priority),
cache_(cache->GetWeakPtr()),
@@ -195,7 +187,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
TRACE_EVENT1("io", "HttpCacheTransaction::Transaction", "priority",
RequestPriorityToString(priority));
static_assert(HttpCache::Transaction::kNumValidationHeaders ==
- base::size(kValidationHeaders),
+ std::size(kValidationHeaders),
"invalid number of validation headers");
io_callback_ = base::BindRepeating(&Transaction::OnIOComplete,
@@ -241,7 +233,9 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
const NetLogWithSource& net_log) {
DCHECK(request);
DCHECK(!callback.is_null());
- TRACE_EVENT1("io", "HttpCacheTransaction::Start", "url", request->url);
+ TRACE_EVENT_WITH_FLOW1("io", "HttpCacheTransaction::Start",
+ net_log.source().id, TRACE_EVENT_FLAG_FLOW_OUT, "url",
+ request->url);
// Ensure that we only have one asynchronous call at a time.
DCHECK(callback_.is_null());
@@ -608,17 +602,16 @@ int HttpCache::Transaction::ResumeNetworkStart() {
return ERR_UNEXPECTED;
}
-void HttpCache::Transaction::GetConnectionAttempts(
- ConnectionAttempts* out) const {
- ConnectionAttempts new_connection_attempts;
+ConnectionAttempts HttpCache::Transaction::GetConnectionAttempts() const {
+ ConnectionAttempts attempts;
const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
if (transaction)
- transaction->GetConnectionAttempts(&new_connection_attempts);
+ attempts = transaction->GetConnectionAttempts();
- out->swap(new_connection_attempts);
- out->insert(out->begin(),
- network_transaction_info_.old_connection_attempts.begin(),
- network_transaction_info_.old_connection_attempts.end());
+ attempts.insert(attempts.begin(),
+ network_transaction_info_.old_connection_attempts.begin(),
+ network_transaction_info_.old_connection_attempts.end());
+ return attempts;
}
void HttpCache::Transaction::CloseConnectionOnDestruction() {
@@ -693,7 +686,7 @@ void HttpCache::Transaction::MaybeSetParallelWritingPatternForMetrics(
// GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
// CacheReadResponse* -> CacheDispatchValidation ->
// BeginPartialCacheValidation() -> BeginCacheValidation() ->
-// SetupEntryForRead() -> FinishHeaders*
+// ConnectedCallback* -> SetupEntryForRead() -> FinishHeaders*
//
// Read():
// CacheReadData*
@@ -738,7 +731,7 @@ void HttpCache::Transaction::MaybeSetParallelWritingPatternForMetrics(
//
// Read() 2:
// NetworkReadCacheWrite* -> StartPartialCacheValidation ->
-// CompletePartialCacheValidation -> CacheReadData* ->
+// CompletePartialCacheValidation -> ConnectedCallback* -> CacheReadData*
//
// Read() 3:
// CacheReadData* -> StartPartialCacheValidation ->
@@ -797,7 +790,8 @@ void HttpCache::Transaction::MaybeSetParallelWritingPatternForMetrics(
// GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
// CacheReadResponse* -> CacheToggleUnusedSincePrefetch* ->
// CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// BeginCacheValidation() -> SetupEntryForRead() -> FinishHeaders*
+// BeginCacheValidation() -> ConnectedCallback* -> SetupEntryForRead() ->
+// FinishHeaders*
//
// Read():
// CacheReadData*
@@ -899,6 +893,12 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT_COMPLETE:
rv = DoCacheUpdateStaleWhileRevalidateTimeoutComplete(rv);
break;
+ case STATE_CONNECTED_CALLBACK:
+ rv = DoConnectedCallback();
+ break;
+ case STATE_CONNECTED_CALLBACK_COMPLETE:
+ rv = DoConnectedCallbackComplete(rv);
+ break;
case STATE_SETUP_ENTRY_FOR_READ:
DCHECK_EQ(OK, rv);
rv = DoSetupEntryForRead();
@@ -1086,7 +1086,9 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) {
}
int HttpCache::Transaction::DoInitEntry() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoInitEntry");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoInitEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
if (!cache_.get()) {
@@ -1104,7 +1106,9 @@ int HttpCache::Transaction::DoInitEntry() {
}
int HttpCache::Transaction::DoOpenOrCreateEntry() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenOrCreateEntry");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoOpenOrCreateEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
TransitionToState(STATE_OPEN_OR_CREATE_ENTRY_COMPLETE);
cache_pending_ = true;
@@ -1155,7 +1159,10 @@ int HttpCache::Transaction::DoOpenOrCreateEntry() {
}
int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenOrCreateEntryComplete");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoOpenOrCreateEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
// 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.
@@ -1223,7 +1230,9 @@ int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
}
int HttpCache::Transaction::DoDoomEntry() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoDoomEntry");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoDoomEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_DOOM_ENTRY_COMPLETE);
cache_pending_ = true;
if (first_cache_access_since_.is_null())
@@ -1233,7 +1242,9 @@ int HttpCache::Transaction::DoDoomEntry() {
}
int HttpCache::Transaction::DoDoomEntryComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoDoomEntryComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoDoomEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
result);
cache_pending_ = false;
@@ -1244,7 +1255,9 @@ int HttpCache::Transaction::DoDoomEntryComplete(int result) {
}
int HttpCache::Transaction::DoCreateEntry() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCreateEntry");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCreateEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!new_entry_);
TransitionToState(STATE_CREATE_ENTRY_COMPLETE);
cache_pending_ = true;
@@ -1253,7 +1266,9 @@ int HttpCache::Transaction::DoCreateEntry() {
}
int HttpCache::Transaction::DoCreateEntryComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCreateEntryComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCreateEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
// 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.
@@ -1293,7 +1308,9 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) {
}
int HttpCache::Transaction::DoAddToEntry() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoAddToEntry",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(new_entry_);
cache_pending_ = true;
net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY);
@@ -1367,7 +1384,9 @@ void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) {
}
int HttpCache::Transaction::DoAddToEntryComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoAddToEntryComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY,
result);
const base::TimeDelta entry_lock_wait =
@@ -1459,7 +1478,9 @@ int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
}
int HttpCache::Transaction::DoCacheReadResponse() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(entry_);
TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE);
@@ -1472,7 +1493,10 @@ int HttpCache::Transaction::DoCacheReadResponse() {
}
int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponseComplete");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoCacheReadResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_INFO,
result);
@@ -1550,8 +1574,10 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
}
int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {
- TRACE_EVENT0(NetTracingCategory(),
- "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponse");
+ TRACE_EVENT_WITH_FLOW0(
+ "io", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(updated_prefetch_response_);
// TODO(jkarlin): If DoUpdateCachedResponse is also called for this
// transaction then metadata will be written to cache twice. If prefetching
@@ -1562,16 +1588,20 @@ int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {
int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponseComplete(
int result) {
- TRACE_EVENT0(
- NetTracingCategory(),
- "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponseComplete");
+ TRACE_EVENT_WITH_FLOW0(
+ "io", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
updated_prefetch_response_.reset();
TransitionToState(STATE_CACHE_DISPATCH_VALIDATION);
return OnWriteResponseInfoToEntryComplete(result);
}
int HttpCache::Transaction::DoCacheDispatchValidation() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheDispatchValidation");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoCacheDispatchValidation",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (!entry_) {
// Entry got destroyed when twiddling unused-since-prefetch bit.
TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
@@ -1653,7 +1683,9 @@ int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
&custom_request_->extra_headers);
if (reading_ && partial_->IsCurrentRangeCached()) {
- TransitionToState(STATE_CACHE_READ_DATA);
+ // We're about to read a range of bytes from the cache. Signal it to the
+ // consumer through the "connected" callback.
+ TransitionToState(STATE_CONNECTED_CALLBACK);
return OK;
}
@@ -1661,8 +1693,10 @@ int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
}
int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {
- TRACE_EVENT0(
- "io", "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeout");
+ TRACE_EVENT_WITH_FLOW0(
+ "io", "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeout",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
response_.stale_revalidate_timeout =
cache_->clock_->Now() + kStaleRevalidateTimeout;
TransitionToState(STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT_COMPLETE);
@@ -1671,15 +1705,20 @@ int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {
int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete(
int result) {
- TRACE_EVENT0(
+ TRACE_EVENT_WITH_FLOW0(
"io",
- "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete");
- TransitionToState(STATE_SETUP_ENTRY_FOR_READ);
+ "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ DCHECK(!reading_);
+ TransitionToState(STATE_CONNECTED_CALLBACK);
return OnWriteResponseInfoToEntryComplete(result);
}
int HttpCache::Transaction::DoSendRequest() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoSendRequest");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoSendRequest",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(mode_ & WRITE || mode_ == NONE);
DCHECK(!network_trans_.get());
@@ -1716,7 +1755,9 @@ int HttpCache::Transaction::DoSendRequest() {
}
int HttpCache::Transaction::DoSendRequestComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoSendRequestComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoSendRequestComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (!cache_.get()) {
TransitionToState(STATE_FINISH_HEADERS);
return ERR_UNEXPECTED;
@@ -1749,8 +1790,10 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
} else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
DCHECK(response);
response_.cert_request_info = response->cert_request_info;
+ } else if (result == ERR_INCONSISTENT_IP_ADDRESS_SPACE) {
+ DoomInconsistentEntry();
} else if (response_.was_cached) {
- DoneWithEntry(true);
+ DoneWithEntry(/*entry_is_complete=*/true);
}
TransitionToState(STATE_FINISH_HEADERS);
@@ -1759,7 +1802,9 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
// We received the response headers and there is no error.
int HttpCache::Transaction::DoSuccessfulSendRequest() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoSuccessfulSendRequest");
+ TRACE_EVENT_WITH_FLOW0("io", "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();
@@ -1845,8 +1890,6 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
request_->is_subframe_document_resource);
}
- RecordNoStoreHeaderHistogram(request_->load_flags, new_response_);
-
if (new_response_->headers->response_code() == 416 &&
(method_ == "GET" || method_ == "POST")) {
// If there is an active entry it may be destroyed with this transaction.
@@ -1872,7 +1915,9 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// We received 304 or 206 and we want to update the cached response headers.
int HttpCache::Transaction::DoUpdateCachedResponse() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoUpdateCachedResponse");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoUpdateCachedResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
int rv = OK;
// Update the cached response based on the headers and properties of
// new_response_.
@@ -1916,20 +1961,28 @@ int HttpCache::Transaction::DoUpdateCachedResponse() {
}
int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteUpdatedResponse");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoCacheWriteUpdatedResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE);
return WriteResponseInfoToEntry(response_, false);
}
int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {
- TRACE_EVENT0("io",
- "HttpCacheTransaction::DoCacheWriteUpdatedResponseComplete");
+ TRACE_EVENT_WITH_FLOW0(
+ "io", "HttpCacheTransaction::DoCacheWriteUpdatedResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
return OnWriteResponseInfoToEntryComplete(result);
}
int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoUpdateCachedResponseComplete");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoUpdateCachedResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (mode_ == UPDATE) {
DCHECK(!handling_206_);
// We got a "not modified" response and already updated the corresponding
@@ -1937,6 +1990,7 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
//
// By stopping to write to the cache now, we make sure that the 304 rather
// than the cached 200 response, is what will be returned to the user.
+ UpdateSecurityHeadersBeforeForwarding();
DoneWithEntry(true);
} else if (entry_ && !handling_206_) {
DCHECK_EQ(READ_WRITE, mode_);
@@ -1964,7 +2018,10 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
}
int HttpCache::Transaction::DoOverwriteCachedResponse() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoOverwriteCachedResponse");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoOverwriteCachedResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (mode_ & READ) {
TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
return OK;
@@ -1999,8 +2056,9 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() {
}
int HttpCache::Transaction::DoCacheWriteResponse() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse");
-
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheWriteResponse",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
// 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.
@@ -2027,13 +2085,18 @@ int HttpCache::Transaction::DoCacheWriteResponse() {
}
int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoCacheWriteResponseComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_TRUNCATE_CACHED_DATA);
return OnWriteResponseInfoToEntryComplete(result);
}
int HttpCache::Transaction::DoTruncateCachedData() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoTruncateCachedData");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoTruncateCachedData",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_TRUNCATE_CACHED_DATA_COMPLETE);
if (!entry_)
return OK;
@@ -2043,7 +2106,10 @@ int HttpCache::Transaction::DoTruncateCachedData() {
}
int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoInitEntry");
+ TRACE_EVENT_WITH_FLOW0("io",
+ "HttpCacheTransaction::DoTruncateCachedDataComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (entry_) {
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_DATA,
result);
@@ -2148,14 +2214,19 @@ int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
}
int HttpCache::Transaction::DoNetworkReadCacheWrite() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoNetworkReadCacheWrite");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkReadCacheWrite",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
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_EVENT0("io", "HttpCacheTransaction::DoNetworkReadCacheWriteComplete");
+ TRACE_EVENT_WITH_FLOW0(
+ "io", "HttpCacheTransaction::DoNetworkReadCacheWriteComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (!cache_.get()) {
TransitionToState(STATE_NONE);
return ERR_UNEXPECTED;
@@ -2222,13 +2293,17 @@ int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
}
int HttpCache::Transaction::DoNetworkRead() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoNetworkRead");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkRead",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
TransitionToState(STATE_NETWORK_READ_COMPLETE);
return network_trans_->Read(read_buf_.get(), read_buf_len_, io_callback_);
}
int HttpCache::Transaction::DoNetworkReadComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoNetworkReadComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoNetworkReadComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (!cache_.get()) {
TransitionToState(STATE_NONE);
@@ -2243,7 +2318,9 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) {
}
int HttpCache::Transaction::DoCacheReadData() {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadData");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadData",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (method_ == "HEAD") {
TransitionToState(STATE_NONE);
@@ -2265,7 +2342,9 @@ int HttpCache::Transaction::DoCacheReadData() {
}
int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
- TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadDataComplete");
+ TRACE_EVENT_WITH_FLOW0("io", "HttpCacheTransaction::DoCacheReadDataComplete",
+ net_log().source().id,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_DATA,
result);
@@ -2339,7 +2418,7 @@ void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {
if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange))
range_found = true;
- for (size_t i = 0; i < base::size(kSpecialHeaders); ++i) {
+ for (size_t i = 0; i < std::size(kSpecialHeaders); ++i) {
if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) {
effective_load_flags_ |= kSpecialHeaders[i].load_flag;
special_headers = true;
@@ -2349,7 +2428,7 @@ void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {
// Check for conditionalization headers which may correspond with a
// cache validation request.
- for (size_t i = 0; i < base::size(kValidationHeaders); ++i) {
+ for (size_t i = 0; i < std::size(kValidationHeaders); ++i) {
const ValidationHeaderInfo& info = kValidationHeaders[i];
std::string validation_value;
if (request_->extra_headers.GetHeader(
@@ -2498,7 +2577,8 @@ int HttpCache::Transaction::BeginCacheValidation() {
(truncated_ || response_.headers->response_code() == 206)) {
DCHECK(!partial_);
if (skip_validation) {
- TransitionToState(STATE_SETUP_ENTRY_FOR_READ);
+ DCHECK(!reading_);
+ TransitionToState(STATE_CONNECTED_CALLBACK);
return OK;
}
@@ -2540,9 +2620,10 @@ int HttpCache::Transaction::BeginCacheValidation() {
if (skip_validation) {
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
+ DCHECK(!reading_);
TransitionToState(needs_stale_while_revalidate_cache_update
? STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT
- : STATE_SETUP_ENTRY_FOR_READ);
+ : STATE_CONNECTED_CALLBACK);
return OK;
} else {
// Make the network request conditional, to see if we may reuse our cached
@@ -2616,7 +2697,7 @@ bool HttpCache::Transaction::
ExternallyConditionalizedValidationHeadersMatchEntry() const {
DCHECK(external_validation_.initialized);
- for (size_t i = 0; i < base::size(kValidationHeaders); i++) {
+ for (size_t i = 0; i < std::size(kValidationHeaders); i++) {
if (external_validation_.values[i].empty())
continue;
@@ -3027,6 +3108,62 @@ void HttpCache::Transaction::IgnoreRangeRequest() {
partial_.reset(nullptr);
}
+// Called to signal to the consumer that we are about to read headers from a
+// cached entry originally read from a given IP endpoint.
+int HttpCache::Transaction::DoConnectedCallback() {
+ TransitionToState(STATE_CONNECTED_CALLBACK_COMPLETE);
+ if (connected_callback_.is_null()) {
+ return OK;
+ }
+
+ return connected_callback_.Run(
+ TransportInfo(TransportType::kCached, response_.remote_endpoint, ""),
+ io_callback_);
+}
+
+int HttpCache::Transaction::DoConnectedCallbackComplete(int result) {
+ if (result != OK) {
+ if (result == ERR_INCONSISTENT_IP_ADDRESS_SPACE) {
+ DoomInconsistentEntry();
+ } else {
+ // Release the entry for further use - we are done using it.
+ DoneWithEntry(/*entry_is_complete=*/true);
+ }
+
+ TransitionToState(STATE_NONE);
+ return result;
+ }
+
+ if (reading_) {
+ // We can only get here if we're reading a partial range of bytes from the
+ // cache. In that case, proceed to read the bytes themselves.
+ DCHECK(partial_);
+ TransitionToState(STATE_CACHE_READ_DATA);
+ } else {
+ // Otherwise, we have just read headers from the cache.
+ TransitionToState(STATE_SETUP_ENTRY_FOR_READ);
+ }
+ return OK;
+}
+
+void HttpCache::Transaction::DoomInconsistentEntry() {
+ // Explicitly call `DoomActiveEntry()` ourselves before calling
+ // `DoneWithEntry()` because we cannot rely on the latter doing it for us.
+ // Indeed, `DoneWithEntry(false)` does not call `DoomActiveEntry()` if either
+ // of the following conditions hold:
+ //
+ // - the transaction uses the cache in read-only mode
+ // - the transaction has passed the headers phase and is reading
+ //
+ // Inconsistent cache entries can cause deterministic failures even in
+ // read-only mode, so they should be doomed anyway. They can also be detected
+ // during the reading phase in the case of split range requests, since those
+ // requests can result in multiple connections being obtained to different
+ // remote endpoints.
+ cache_->DoomActiveEntry(cache_key_);
+ DoneWithEntry(/*entry_is_complete=*/false);
+}
+
void HttpCache::Transaction::FixHeadersForHead() {
if (response_.headers->response_code() == 206) {
response_.headers->RemoveHeader("Content-Range");
@@ -3564,8 +3701,7 @@ void HttpCache::Transaction::SaveNetworkTransactionInfo(
transaction.GetTotalReceivedBytes();
network_transaction_info_.total_sent_bytes += transaction.GetTotalSentBytes();
- ConnectionAttempts attempts;
- transaction.GetConnectionAttempts(&attempts);
+ ConnectionAttempts attempts = transaction.GetConnectionAttempts();
for (const auto& attempt : attempts)
network_transaction_info_.old_connection_attempts.push_back(attempt);
network_transaction_info_.old_remote_endpoint = IPEndPoint();
@@ -3620,4 +3756,17 @@ bool HttpCache::Transaction::ShouldDisableCaching(
return disable_caching;
}
+void HttpCache::Transaction::UpdateSecurityHeadersBeforeForwarding() {
+ // Because of COEP, we need to add CORP to the 304 of resources that set it
+ // previously. It will be blocked in the network service otherwise.
+ std::string stored_corp_header;
+ response_.headers->GetNormalizedHeader("Cross-Origin-Resource-Policy",
+ &stored_corp_header);
+ if (!stored_corp_header.empty()) {
+ new_response_->headers->SetHeader("Cross-Origin-Resource-Policy",
+ stored_corp_header);
+ }
+ return;
+}
+
} // namespace net
diff --git a/chromium/net/http/http_cache_transaction.h b/chromium/net/http/http_cache_transaction.h
index d790eb9b869..cc359647d7c 100644
--- a/chromium/net/http/http_cache_transaction.h
+++ b/chromium/net/http/http_cache_transaction.h
@@ -165,7 +165,7 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
void SetEarlyResponseHeadersCallback(
ResponseHeadersCallback callback) override;
int ResumeNetworkStart() override;
- void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ ConnectionAttempts GetConnectionAttempts() const override;
void CloseConnectionOnDestruction() override;
// Invoked when parallel validation cannot proceed due to response failure
@@ -256,6 +256,8 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
STATE_COMPLETE_PARTIAL_CACHE_VALIDATION,
STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT,
STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT_COMPLETE,
+ STATE_CONNECTED_CALLBACK,
+ STATE_CONNECTED_CALLBACK_COMPLETE,
STATE_SETUP_ENTRY_FOR_READ,
STATE_SEND_REQUEST,
STATE_SEND_REQUEST_COMPLETE,
@@ -334,6 +336,8 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
int DoCacheQueryDataComplete(int result);
int DoCacheUpdateStaleWhileRevalidateTimeout();
int DoCacheUpdateStaleWhileRevalidateTimeoutComplete(int result);
+ int DoConnectedCallback();
+ int DoConnectedCallbackComplete(int result);
int DoSetupEntryForRead();
int DoStartPartialCacheValidation();
int DoCompletePartialCacheValidation(int result);
@@ -486,7 +490,16 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// to/from the entry. If |entry_is_complete| is false the result may be either
// a truncated or a doomed entry based on whether the stored response can be
// resumed or not.
- void DoneWithEntry(bool did_finish);
+ void DoneWithEntry(bool entry_is_complete);
+
+ // Dooms the given entry so that it will not be re-used for other requests,
+ // then calls `DoneWithEntry()`.
+ //
+ // This happens when network conditions have changed since the entry was
+ // cached, which results in deterministic failures when trying to use the
+ // cache entry. In order to let future requests succeed, the cache entry
+ // should be doomed.
+ void DoomInconsistentEntry();
// Returns an error to signal the caller that the current read failed. The
// current operation |result| is also logged. If |restart| is true, the
@@ -576,7 +589,11 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction {
// headers.
bool ShouldDisableCaching(const HttpResponseHeaders& headers) const;
- State next_state_;
+ // 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();
+
+ State next_state_{STATE_NONE};
// Initial request with which Start() was invoked.
raw_ptr<const HttpRequestInfo> initial_request_;
diff --git a/chromium/net/http/http_cache_unittest.cc b/chromium/net/http/http_cache_unittest.cc
index 8448f792971..ec0d6f2589c 100644
--- a/chromium/net/http/http_cache_unittest.cc
+++ b/chromium/net/http/http_cache_unittest.cc
@@ -27,6 +27,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/process_memory_dump.h"
@@ -741,10 +742,22 @@ bool LogContainsEventType(const RecordingNetLogObserver& net_log_observer,
return !net_log_observer.GetEntriesWithType(expected).empty();
}
+// Returns a TransportInfo distinct from the default for mock transactions,
+// with the given port number.
+TransportInfo TestTransportInfoWithPort(uint16_t port) {
+ TransportInfo result;
+ result.endpoint = IPEndPoint(IPAddress(42, 0, 1, 2), port);
+ return result;
+}
+
// Returns a TransportInfo distinct from the default for mock transactions.
TransportInfo TestTransportInfo() {
- TransportInfo result;
- result.endpoint = IPEndPoint(IPAddress(42, 0, 1, 2), 1337);
+ return TestTransportInfoWithPort(1337);
+}
+
+TransportInfo CachedTestTransportInfo() {
+ TransportInfo result = TestTransportInfo();
+ result.type = TransportType::kCached;
return result;
}
@@ -857,12 +870,12 @@ TEST_F(HttpCacheTest, SimpleGET) {
TEST_F(HttpCacheTest, SimpleGET_ConnectedCallback) {
MockHttpCache cache;
- ConnectedHandler connected_handler;
-
ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
mock_transaction.transport_info = TestTransportInfo();
MockHttpRequest request(mock_transaction);
+ ConnectedHandler connected_handler;
+
std::unique_ptr<HttpTransaction> transaction;
EXPECT_THAT(cache.CreateTransaction(&transaction), IsOk());
ASSERT_THAT(transaction, NotNull());
@@ -882,18 +895,16 @@ TEST_F(HttpCacheTest, SimpleGET_ConnectedCallback) {
// returns an error, the transaction fails with that error.
TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackReturnError) {
MockHttpCache cache;
-
- ConnectedHandler connected_handler;
- // The exact error code does not matter. We only care that it is passed to
- // the transaction's completion callback unmodified.
- connected_handler.set_result(ERR_NOT_IMPLEMENTED);
-
MockHttpRequest request(kSimpleGET_Transaction);
+ ConnectedHandler connected_handler;
std::unique_ptr<HttpTransaction> transaction;
EXPECT_THAT(cache.CreateTransaction(&transaction), IsOk());
ASSERT_THAT(transaction, NotNull());
+ // The exact error code does not matter. We only care that it is passed to
+ // the transaction's completion callback unmodified.
+ connected_handler.set_result(ERR_NOT_IMPLEMENTED);
transaction->SetConnectedCallback(connected_handler.Callback());
TestCompletionCallback callback;
@@ -905,13 +916,15 @@ TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackReturnError) {
// This test verifies that the callback passed to SetConnectedCallback() is
// called once for requests that hit the cache.
-// TODO(crbug.com/986744): This is not yet the case, but this test serves to
-// document the intent.
TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHit) {
MockHttpCache cache;
- // Populate the cache.
- RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
+ {
+ // Populate the cache.
+ ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
+ mock_transaction.transport_info = TestTransportInfo();
+ RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
+ }
// Establish a baseline.
EXPECT_EQ(1, cache.network_layer()->transaction_count());
@@ -919,7 +932,6 @@ TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHit) {
// Load from the cache (only), observe the callback being called.
ConnectedHandler connected_handler;
-
MockHttpRequest request(kSimpleGET_Transaction);
std::unique_ptr<HttpTransaction> transaction;
@@ -938,10 +950,129 @@ TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHit) {
// was not called by a second network transaction.
EXPECT_EQ(1, cache.network_layer()->transaction_count());
- // TODO(crbug.com/986744): Expect 1 call once HttpCache::Transaction is
- // modified to call the callback on cache hits, expect that the endpoint is
- // the one from which the cached data was downloaded.
- EXPECT_THAT(connected_handler.transports(), IsEmpty());
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+}
+
+// This test verifies that when the callback passed to SetConnectedCallback()
+// is called for a request that hit the cache and returns an error, the cache
+// entry is reusable.
+TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitReturnError) {
+ MockHttpCache cache;
+
+ {
+ // Populate the cache.
+ ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
+ mock_transaction.transport_info = TestTransportInfo();
+ RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
+ }
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+
+ {
+ // Attempt to read from cache entry, but abort transaction due to a
+ // connected callback error.
+ ConnectedHandler connected_handler;
+ connected_handler.set_result(ERR_FAILED);
+
+ 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(), IsError(ERR_FAILED));
+
+ // Used the cache entry only.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+ }
+
+ {
+ // Request the same resource once more, observe that it is read from cache.
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // Used the cache entry only.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+ }
+}
+
+// This test verifies that when the callback passed to SetConnectedCallback()
+// returns `ERR_INCONSISTENT_IP_ADDRESS_SPACE`, the cache entry is invalidated.
+TEST_F(HttpCacheTest,
+ SimpleGET_ConnectedCallbackOnCacheHitReturnInconsistentIpError) {
+ MockHttpCache cache;
+
+ ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
+ mock_transaction.transport_info = TestTransportInfo();
+
+ // Populate the cache.
+ RunTransactionTest(cache.http_cache(), mock_transaction);
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+
+ {
+ // Attempt to read from cache entry, but abort transaction due to a
+ // connected callback error.
+ ConnectedHandler connected_handler;
+ connected_handler.set_result(ERR_INCONSISTENT_IP_ADDRESS_SPACE);
+
+ 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(),
+ IsError(ERR_INCONSISTENT_IP_ADDRESS_SPACE));
+
+ // Used the cache entry only.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+ }
+
+ {
+ // Request the same resource once more, observe that it is not read from
+ // cache.
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // Used the network only.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo()));
+ }
}
class HttpCacheTest_SplitCacheFeature
@@ -2052,6 +2183,7 @@ TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRange) {
ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
mock_transaction.request_headers = "Range: bytes = 20-29\r\n" EXTRA_HEADER;
mock_transaction.data = "rg: 20-29 ";
+ mock_transaction.transport_info = TestTransportInfo();
RunTransactionTest(cache.http_cache(), mock_transaction);
}
@@ -2089,26 +2221,201 @@ TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRange) {
// NOTE: This works because only the mock transaction struct's address is
// registered with the mocking framework - the pointee data is consulted
// each time it is read.
- auto new_transport_info = TestTransportInfo();
- new_transport_info.endpoint =
- IPEndPoint(new_transport_info.endpoint.address(), 123);
- mock_transaction.transport_info = new_transport_info;
+ mock_transaction.transport_info = TestTransportInfoWithPort(123);
ReadAndVerifyTransaction(transaction.get(), mock_transaction);
- // A second call for the last range's network transaction.
- // TODO(crbug.com/986744): Expect 3 calls once the callback is notified on
- // cache hits as well as network connections.
- // TODO(crbug.com/986744): Test that the cached data is served as coming
- // from the endpoint whence it was originally downloaded.
+ // A second call for the cached range, reported as coming from the original
+ // endpoint it was cached from. A third call for the last range's network
+ // transaction.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo(), CachedTestTransportInfo(),
+ TestTransportInfoWithPort(123)));
+ }
+}
+
+// This test verifies that when the ConnectedCallback passed to a cache range
+// transaction returns an `ERR_INCONSISTENT_IP_ADDRESS_SPACE` error during a
+// partial read from cache, then the cache entry is invalidated.
+TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnInconsistentIpError) {
+ MockHttpCache cache;
+
+ // Request an infix range and populate the cache with it.
+ {
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 20-29\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 20-29 ";
+ mock_transaction.transport_info = TestTransportInfo();
+
+ RunTransactionTest(cache.http_cache(), mock_transaction);
+ }
+
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-39\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 rg: 20-29 rg: 30-39 ";
+ mock_transaction.transport_info = TestTransportInfo();
+ MockHttpRequest request(mock_transaction);
+
+ // Request a surrounding range. This *should* be read in three parts:
+ //
+ // 1. for the prefix: from the network
+ // 2. for the cached infix: from the cache
+ // 3. for the suffix: from the network
+ //
+ // The connected callback returns OK for 1), but fails during 2). As a result,
+ // the transaction fails partway and 3) is never created. The cache entry is
+ // invalidated as a result of the specific error code.
+ {
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // 1 call for the first range's network transaction.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo()));
+
+ // Set the callback to return an error the next time it is called.
+ connected_handler.set_result(ERR_INCONSISTENT_IP_ADDRESS_SPACE);
+
+ std::string content;
+ EXPECT_THAT(ReadTransaction(transaction.get(), &content),
+ IsError(ERR_INCONSISTENT_IP_ADDRESS_SPACE));
+
+ // A second call that failed.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo(), CachedTestTransportInfo()));
+ }
+
+ // Request the same range again, observe that nothing is read from cache.
+ {
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ std::string content;
+ EXPECT_THAT(ReadTransaction(transaction.get(), &content), IsOk());
+ EXPECT_EQ(content, mock_transaction.data);
+
+ // 1 call for the network transaction from which the whole response was
+ // read. The first 20 bytes were cached by the previous two requests, but
+ // the cache entry was doomed during the last transaction so they are not
+ // used here.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo()));
+ }
+}
+
+// This test verifies that when the ConnectedCallback passed to a cache range
+// transaction returns an `ERR_INCONSISTENT_IP_ADDRESS_SPACE` error during a
+// network transaction, then the cache entry is invalidated.
+TEST_F(HttpCacheTest,
+ RangeGET_ConnectedCallbackReturnInconsistentIpErrorForNetwork) {
+ MockHttpCache cache;
+
+ // Request a prefix range and populate the cache with it.
+ {
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-19\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 ";
+ mock_transaction.transport_info = TestTransportInfo();
+
+ RunTransactionTest(cache.http_cache(), mock_transaction);
+ }
+
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-29\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 rg: 20-29 ";
+ mock_transaction.transport_info = TestTransportInfo();
+ MockHttpRequest request(mock_transaction);
+
+ // Request a longer range. This *should* be read in two parts:
+ //
+ // 1. for the prefix: from the cache
+ // 2. for the suffix: from the network
+ {
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // 1 call for the first range's network transaction.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+
+ // Set the callback to return an error the next time it is called.
+ connected_handler.set_result(ERR_INCONSISTENT_IP_ADDRESS_SPACE);
+
+ std::string content;
+ EXPECT_THAT(ReadTransaction(transaction.get(), &content),
+ IsError(ERR_INCONSISTENT_IP_ADDRESS_SPACE));
+
+ // A second call that failed.
EXPECT_THAT(connected_handler.transports(),
- ElementsAre(TestTransportInfo(), new_transport_info));
+ ElementsAre(CachedTestTransportInfo(), TestTransportInfo()));
+ }
+
+ // Request the same range again, observe that nothing is read from cache.
+ {
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ std::string content;
+ EXPECT_THAT(ReadTransaction(transaction.get(), &content), IsOk());
+ EXPECT_EQ(content, mock_transaction.data);
+
+ // 1 call for the network transaction from which the whole response was
+ // read. The first 20 bytes were cached by the previous two requests, but
+ // the cache entry was doomed during the last transaction so they are not
+ // used here.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(TestTransportInfo()));
}
}
// This test verifies that when the ConnectedCallback passed to a cache
// transaction returns an error for the second (or third) subrange transaction,
-// the overall cache transaction fails with that error.
+// the overall cache transaction fails with that error. The cache entry is still
+// usable after that.
TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) {
MockHttpCache cache;
@@ -2117,23 +2424,27 @@ TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) {
ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
mock_transaction.request_headers = "Range: bytes = 20-29\r\n" EXTRA_HEADER;
mock_transaction.data = "rg: 20-29 ";
+ mock_transaction.transport_info = TestTransportInfo();
RunTransactionTest(cache.http_cache(), mock_transaction);
}
- // Request a surrounding range. This results in three transactions:
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-39\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 rg: 20-29 rg: 30-39 ";
+ mock_transaction.transport_info = TestTransportInfo();
+ MockHttpRequest request(mock_transaction);
+
+ // Request a surrounding range. This *should* be read in three parts:
//
- // 1. for the prefix, from the network
- // 2. for the cached infix, from the cache
- // 3. for the suffix, from the network
+ // 1. for the prefix: from the network
+ // 2. for the cached infix: from the cache
+ // 3. for the suffix: from the network
//
- // The connected callback returns OK for 1), but fails after that.
+ // The connected callback returns OK for 1), but fails during 2). As a result,
+ // the transaction fails partway and 3) is never created. The prefix is still
+ // cached, such that the cache entry ends up with both the prefix and infix.
{
- ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
- mock_transaction.request_headers = "Range: bytes = 10-39\r\n" EXTRA_HEADER;
- mock_transaction.data = "rg: 10-19 rg: 20-29 rg: 30-39 ";
- MockHttpRequest request(mock_transaction);
-
ConnectedHandler connected_handler;
std::unique_ptr<HttpTransaction> transaction;
@@ -2150,7 +2461,7 @@ TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) {
// 1 call for the first range's network transaction.
EXPECT_THAT(connected_handler.transports(),
- ElementsAre(DefaultTransportInfo()));
+ ElementsAre(TestTransportInfo()));
// Set the callback to return an error the next time it is called. The exact
// error code is irrelevant, what matters is that it is reflected in the
@@ -2163,7 +2474,91 @@ TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) {
// A second call that failed.
EXPECT_THAT(connected_handler.transports(),
- ElementsAre(DefaultTransportInfo(), DefaultTransportInfo()));
+ ElementsAre(TestTransportInfo(), CachedTestTransportInfo()));
+ }
+
+ // Request the same range again, observe that the prefix and infix are both
+ // read from cache. Only the suffix is fetched from the network.
+ {
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // 1 call for the first range's cache transaction: the first 20 bytes were
+ // cached by the previous two requests.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+
+ std::string content;
+ EXPECT_THAT(ReadTransaction(transaction.get(), &content), IsOk());
+ EXPECT_EQ(content, mock_transaction.data);
+
+ // A second call from the network transaction for the last 10 bytes.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo(), TestTransportInfo()));
+ }
+}
+
+// This test verifies that the ConnectedCallback passed to a cache transaction
+// is called once per subrange in the case of a range request with a partial
+// cache hit, even when a prefix of the range is cached.
+TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRangeWithPrefix) {
+ MockHttpCache cache;
+
+ // Request a prefix range and populate the cache with it.
+ {
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-19\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 ";
+ mock_transaction.transport_info = TestTransportInfo();
+
+ RunTransactionTest(cache.http_cache(), mock_transaction);
+ }
+
+ // Request a surrounding range and observe that the callback is called once
+ // per subrange, as split up by cache hits.
+ {
+ ScopedMockTransaction mock_transaction(kRangeGET_TransactionOK);
+ mock_transaction.request_headers = "Range: bytes = 10-39\r\n" EXTRA_HEADER;
+ mock_transaction.data = "rg: 10-19 rg: 20-29 rg: 30-39 ";
+ mock_transaction.transport_info = TestTransportInfoWithPort(123);
+ MockHttpRequest request(mock_transaction);
+
+ ConnectedHandler connected_handler;
+
+ 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());
+
+ // 1 call for the first range from the cache, reported as coming from the
+ // endpoint which initially served the cached range.
+ EXPECT_THAT(connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo()));
+
+ ReadAndVerifyTransaction(transaction.get(), mock_transaction);
+
+ // A second call for the last range's network transaction.
+ EXPECT_THAT(
+ connected_handler.transports(),
+ ElementsAre(CachedTestTransportInfo(), TestTransportInfoWithPort(123)));
}
}
@@ -13070,4 +13465,45 @@ TEST_F(HttpCacheTest, DnsAliasesRevalidation) {
EXPECT_THAT(response.dns_aliases, testing::ElementsAre("alias3", "alias4"));
}
+TEST_F(HttpCacheTest, SecurityHeadersAreCopiedToConditionalizedResponse) {
+ MockHttpCache cache;
+ HttpResponseInfo response;
+ ScopedMockTransaction transaction(kSimpleGET_Transaction);
+
+ static const Response kNetResponse1 = {
+ "HTTP/1.1 200 OK",
+ "Date: Fri, 12 Jun 2009 21:46:42 GMT\n"
+ "Server: server1\n"
+ "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n"
+ "Cross-Origin-Resource-Policy: cross-origin\n",
+ "body1"};
+
+ static const Response kNetResponse2 = {
+ "HTTP/1.1 304 Not Modified",
+ "Date: Wed, 22 Jul 2009 03:15:26 GMT\n"
+ "Server: server2\n"
+ "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n",
+ ""};
+
+ kNetResponse1.AssignTo(&transaction);
+ RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+ &response);
+
+ // On the second request, the cache is revalidated.
+ const char kExtraRequestHeaders[] =
+ "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT\r\n";
+ transaction.request_headers = kExtraRequestHeaders;
+ kNetResponse2.AssignTo(&transaction);
+ RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+ &response);
+
+ // Verify that the CORP header was carried over to the response.
+ std::string response_corp_header;
+ response.headers->GetNormalizedHeader("Cross-Origin-Resource-Policy",
+ &response_corp_header);
+
+ EXPECT_EQ(304, response.headers->response_code());
+ EXPECT_EQ("cross-origin", response_corp_header);
+}
+
} // namespace net
diff --git a/chromium/net/http/http_chunked_decoder_unittest.cc b/chromium/net/http/http_chunked_decoder_unittest.cc
index 533e11b6e44..4dbefb346f1 100644
--- a/chromium/net/http/http_chunked_decoder_unittest.cc
+++ b/chromium/net/http/http_chunked_decoder_unittest.cc
@@ -8,7 +8,6 @@
#include <string>
#include <vector>
-#include "base/cxx17_backports.h"
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "net/base/net_errors.h"
@@ -71,14 +70,14 @@ TEST(HttpChunkedDecoderTest, Basic) {
const char* const inputs[] = {
"B\r\nhello hello\r\n0\r\n\r\n"
};
- RunTest(inputs, base::size(inputs), "hello hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello hello", true, 0);
}
TEST(HttpChunkedDecoderTest, OneChunk) {
const char* const inputs[] = {
"5\r\nhello\r\n"
};
- RunTest(inputs, base::size(inputs), "hello", false, 0);
+ RunTest(inputs, std::size(inputs), "hello", false, 0);
}
TEST(HttpChunkedDecoderTest, Typical) {
@@ -88,7 +87,7 @@ TEST(HttpChunkedDecoderTest, Typical) {
"5\r\nworld\r\n",
"0\r\n\r\n"
};
- RunTest(inputs, base::size(inputs), "hello world", true, 0);
+ RunTest(inputs, std::size(inputs), "hello world", true, 0);
}
TEST(HttpChunkedDecoderTest, Incremental) {
@@ -105,7 +104,7 @@ TEST(HttpChunkedDecoderTest, Incremental) {
"\r",
"\n"
};
- RunTest(inputs, base::size(inputs), "hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello", true, 0);
}
// Same as above, but group carriage returns with previous input.
@@ -119,7 +118,7 @@ TEST(HttpChunkedDecoderTest, Incremental2) {
"\n\r",
"\n"
};
- RunTest(inputs, base::size(inputs), "hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello", true, 0);
}
TEST(HttpChunkedDecoderTest, LF_InsteadOf_CRLF) {
@@ -132,7 +131,7 @@ TEST(HttpChunkedDecoderTest, LF_InsteadOf_CRLF) {
"5\nworld\n",
"0\n\n"
};
- RunTest(inputs, base::size(inputs), "hello world", true, 0);
+ RunTest(inputs, std::size(inputs), "hello world", true, 0);
}
TEST(HttpChunkedDecoderTest, Extensions) {
@@ -140,7 +139,7 @@ TEST(HttpChunkedDecoderTest, Extensions) {
"5;x=0\r\nhello\r\n",
"0;y=\"2 \"\r\n\r\n"
};
- RunTest(inputs, base::size(inputs), "hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello", true, 0);
}
TEST(HttpChunkedDecoderTest, Trailers) {
@@ -151,7 +150,7 @@ TEST(HttpChunkedDecoderTest, Trailers) {
"Bar: 2\r\n",
"\r\n"
};
- RunTest(inputs, base::size(inputs), "hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello", true, 0);
}
TEST(HttpChunkedDecoderTest, TrailersUnfinished) {
@@ -160,7 +159,7 @@ TEST(HttpChunkedDecoderTest, TrailersUnfinished) {
"0\r\n",
"Foo: 1\r\n"
};
- RunTest(inputs, base::size(inputs), "hello", false, 0);
+ RunTest(inputs, std::size(inputs), "hello", false, 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_TooBig) {
@@ -171,7 +170,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_TooBig) {
"48469410265455838241\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_0X) {
@@ -182,7 +181,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_0X) {
"0x5\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, ChunkSize_TrailingSpace) {
@@ -194,7 +193,7 @@ TEST(HttpChunkedDecoderTest, ChunkSize_TrailingSpace) {
"5 \r\nhello\r\n",
"0\r\n\r\n"
};
- RunTest(inputs, base::size(inputs), "hello", true, 0);
+ RunTest(inputs, std::size(inputs), "hello", true, 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingTab) {
@@ -204,7 +203,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingTab) {
"5\t\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingFormFeed) {
@@ -215,7 +214,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingFormFeed) {
"5\f\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingVerticalTab) {
@@ -226,7 +225,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingVerticalTab) {
"5\v\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingNonHexDigit) {
@@ -237,7 +236,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingNonHexDigit) {
"5H\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_LeadingSpace) {
@@ -248,7 +247,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_LeadingSpace) {
" 5\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidLeadingSeparator) {
@@ -256,7 +255,7 @@ TEST(HttpChunkedDecoderTest, InvalidLeadingSeparator) {
"\r\n5\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_NoSeparator) {
@@ -265,7 +264,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_NoSeparator) {
"1\r\n \r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 1);
+ RunTestUntilFailure(inputs, std::size(inputs), 1);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_Negative) {
@@ -273,7 +272,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_Negative) {
"8\r\n12345678\r\n-5\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidChunkSize_Plus) {
@@ -284,7 +283,7 @@ TEST(HttpChunkedDecoderTest, InvalidChunkSize_Plus) {
"+5\r\nhello\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, InvalidConsecutiveCRLFs) {
@@ -293,7 +292,7 @@ TEST(HttpChunkedDecoderTest, InvalidConsecutiveCRLFs) {
"\r\n\r\n\r\n\r\n",
"0\r\n\r\n"
};
- RunTestUntilFailure(inputs, base::size(inputs), 1);
+ RunTestUntilFailure(inputs, std::size(inputs), 1);
}
TEST(HttpChunkedDecoderTest, ReallyBigChunks) {
@@ -340,7 +339,7 @@ TEST(HttpChunkedDecoderTest, ReallyBigChunks) {
// Chunk terminator and the final chunk.
char final_chunk[] = "\r\n0\r\n\r\n";
- EXPECT_EQ(OK, decoder.FilterBuf(final_chunk, base::size(final_chunk)));
+ EXPECT_EQ(OK, decoder.FilterBuf(final_chunk, std::size(final_chunk)));
EXPECT_TRUE(decoder.reached_eof());
// Since |data| never included any chunk headers, it should not have been
@@ -354,20 +353,20 @@ TEST(HttpChunkedDecoderTest, ReallyBigChunks) {
TEST(HttpChunkedDecoderTest, ExcessiveChunkLen) {
// Smallest number that can't be represented as a signed int64.
const char* const inputs[] = {"8000000000000000\r\nhello\r\n"};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, ExcessiveChunkLen2) {
// Smallest number that can't be represented as an unsigned int64.
const char* const inputs[] = {"10000000000000000\r\nhello\r\n"};
- RunTestUntilFailure(inputs, base::size(inputs), 0);
+ RunTestUntilFailure(inputs, std::size(inputs), 0);
}
TEST(HttpChunkedDecoderTest, BasicExtraData) {
const char* const inputs[] = {
"5\r\nhello\r\n0\r\n\r\nextra bytes"
};
- RunTest(inputs, base::size(inputs), "hello", true, 11);
+ RunTest(inputs, std::size(inputs), "hello", true, 11);
}
TEST(HttpChunkedDecoderTest, IncrementalExtraData) {
@@ -384,7 +383,7 @@ TEST(HttpChunkedDecoderTest, IncrementalExtraData) {
"\r",
"\nextra bytes"
};
- RunTest(inputs, base::size(inputs), "hello", true, 11);
+ RunTest(inputs, std::size(inputs), "hello", true, 11);
}
TEST(HttpChunkedDecoderTest, MultipleExtraDataBlocks) {
@@ -392,7 +391,7 @@ TEST(HttpChunkedDecoderTest, MultipleExtraDataBlocks) {
"5\r\nhello\r\n0\r\n\r\nextra",
" bytes"
};
- RunTest(inputs, base::size(inputs), "hello", true, 11);
+ RunTest(inputs, std::size(inputs), "hello", true, 11);
}
// Test when the line with the chunk length is too long.
@@ -405,7 +404,7 @@ TEST(HttpChunkedDecoderTest, LongChunkLengthLine) {
big_chunk.get(),
"5"
};
- RunTestUntilFailure(inputs, base::size(inputs), 1);
+ RunTestUntilFailure(inputs, std::size(inputs), 1);
}
// Test when the extension portion of the line with the chunk length is too
@@ -419,7 +418,7 @@ TEST(HttpChunkedDecoderTest, LongLengthLengthLine) {
"5;",
big_chunk.get()
};
- RunTestUntilFailure(inputs, base::size(inputs), 1);
+ RunTestUntilFailure(inputs, std::size(inputs), 1);
}
} // namespace
diff --git a/chromium/net/http/http_content_disposition_unittest.cc b/chromium/net/http/http_content_disposition_unittest.cc
index 104cbba59a1..2e3dfb25e82 100644
--- a/chromium/net/http/http_content_disposition_unittest.cc
+++ b/chromium/net/http/http_content_disposition_unittest.cc
@@ -4,7 +4,6 @@
#include "net/http/http_content_disposition.h"
-#include "base/cxx17_backports.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -202,7 +201,7 @@ TEST(HttpContentDispositionTest, Filename) {
{"attachment; foobar=x; filename=\"foo.html\"", "",
L"foo.html"},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
HttpContentDisposition header(tests[i].header, tests[i].referrer_charset);
EXPECT_EQ(tests[i].expected,
base::UTF8ToWide(header.filename()))
@@ -415,7 +414,7 @@ TEST(HttpContentDispositionTest, tc2231) {
// TODO(abarth): http://greenbytes.de/tech/tc2231/#attrfc2047token
// TODO(abarth): http://greenbytes.de/tech/tc2231/#attrfc2047quoted
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
HttpContentDisposition header(tests[i].header, std::string());
EXPECT_EQ(tests[i].expected_type, header.type())
<< "Failed on input: " << tests[i].header;
@@ -488,7 +487,7 @@ TEST(HttpContentDispositionTest, ParseResult) {
HttpContentDisposition::INVALID},
};
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
const ParseResultTestCase& test_case = kTestCases[i];
HttpContentDisposition content_disposition(test_case.header, "utf-8");
int result = content_disposition.parse_result_flags();
diff --git a/chromium/net/http/http_network_layer.cc b/chromium/net/http/http_network_layer.cc
index ee643060d8d..a02911e5eaf 100644
--- a/chromium/net/http/http_network_layer.cc
+++ b/chromium/net/http/http_network_layer.cc
@@ -18,7 +18,7 @@
#include "net/http/http_stream_factory_job.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h"
namespace net {
diff --git a/chromium/net/http/http_network_session.cc b/chromium/net/http/http_network_session.cc
index 05a4a5377f3..fd3c01b7fc9 100644
--- a/chromium/net/http/http_network_session.cc
+++ b/chromium/net/http/http_network_session.cc
@@ -34,10 +34,10 @@
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/quic_packets.h"
-#include "net/third_party/quiche/src/quic/core/quic_tag.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_tag.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
namespace net {
@@ -171,9 +171,7 @@ HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params,
quic_stream_factory_(context.net_log,
context.host_resolver,
context.ssl_config_service,
- context.client_socket_factory
- ? context.client_socket_factory.get()
- : ClientSocketFactory::GetDefaultFactory(),
+ context.client_socket_factory,
context.http_server_properties,
context.cert_verifier,
context.ct_policy_enforcer,
@@ -208,6 +206,7 @@ HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params,
DCHECK(proxy_resolution_service_);
DCHECK(ssl_config_service_);
CHECK(http_server_properties_);
+ DCHECK(context_.client_socket_factory);
normal_socket_pool_manager_ = std::make_unique<ClientSocketPoolManagerImpl>(
CreateCommonConnectJobParams(false /* for_websockets */),
@@ -235,6 +234,10 @@ HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params,
http_server_properties_->SetMaxServerConfigsStoredInProperties(
context.quic_context->params()->max_server_configs_stored_in_properties);
+ http_server_properties_->SetBrokenAlternativeServicesDelayParams(
+ context.quic_context->params()
+ ->initial_delay_for_broken_alternative_service,
+ context.quic_context->params()->exponential_backoff_on_initial_delay);
if (!params_.disable_idle_sockets_close_on_memory_pressure) {
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
@@ -343,8 +346,6 @@ base::Value HttpNetworkSession::QuicInfoToValue() const {
quic_params->allow_server_migration);
dict.SetBoolKey("race_stale_dns_on_connection",
quic_params->race_stale_dns_on_connection);
- dict.SetBoolKey("go_away_on_path_degrading",
- quic_params->go_away_on_path_degrading);
dict.SetBoolKey("estimate_initial_rtt", quic_params->estimate_initial_rtt);
dict.SetBoolKey("server_push_cancellation",
params_.enable_server_push_cancellation);
@@ -398,9 +399,7 @@ CommonConnectJobParams HttpNetworkSession::CreateCommonConnectJobParams(
// Use null websocket_endpoint_lock_manager, which is only set for WebSockets,
// and only when not using a proxy.
return CommonConnectJobParams(
- context_.client_socket_factory ? context_.client_socket_factory.get()
- : ClientSocketFactory::GetDefaultFactory(),
- context_.host_resolver, &http_auth_cache_,
+ context_.client_socket_factory, context_.host_resolver, &http_auth_cache_,
context_.http_auth_handler_factory, &spdy_session_pool_,
&context_.quic_context->params()->supported_versions,
&quic_stream_factory_, context_.proxy_delegate,
diff --git a/chromium/net/http/http_network_session.h b/chromium/net/http/http_network_session.h
index ead3f0a4f82..3b96c6c062f 100644
--- a/chromium/net/http/http_network_session.h
+++ b/chromium/net/http/http_network_session.h
@@ -35,7 +35,7 @@
#include "net/socket/websocket_endpoint_lock_manager.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/ssl/ssl_client_session_cache.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
diff --git a/chromium/net/http/http_network_transaction.cc b/chromium/net/http/http_network_transaction.cc
index 6989ba8b6f7..7ae9b23194e 100644
--- a/chromium/net/http/http_network_transaction.cc
+++ b/chromium/net/http/http_network_transaction.cc
@@ -378,7 +378,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
// Renewed streams shouldn't carry over sent or received bytes.
DCHECK_EQ(0, new_stream->GetTotalReceivedBytes());
DCHECK_EQ(0, new_stream->GetTotalSentBytes());
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CONNECTED_CALLBACK;
}
stream_.reset(new_stream);
}
@@ -678,9 +678,8 @@ void HttpNetworkTransaction::OnQuicBroken() {
net_error_details_.quic_broken = true;
}
-void HttpNetworkTransaction::GetConnectionAttempts(
- ConnectionAttempts* out) const {
- *out = connection_attempts_;
+ConnectionAttempts HttpNetworkTransaction::GetConnectionAttempts() const {
+ return connection_attempts_;
}
bool HttpNetworkTransaction::IsSecureRequest() const {
@@ -738,6 +737,9 @@ int HttpNetworkTransaction::DoLoop(int result) {
case STATE_INIT_STREAM_COMPLETE:
rv = DoInitStreamComplete(rv);
break;
+ case STATE_CONNECTED_CALLBACK:
+ rv = DoConnectedCallback();
+ break;
case STATE_CONNECTED_CALLBACK_COMPLETE:
rv = DoConnectedCallbackComplete(rv);
break;
@@ -857,7 +859,7 @@ int HttpNetworkTransaction::DoCreateStream() {
int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
CopyConnectionAttemptsFromStreamRequest();
if (result == OK) {
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CONNECTED_CALLBACK;
DCHECK(stream_.get());
} else if (result == ERR_HTTP_1_1_REQUIRED ||
result == ERR_PROXY_HTTP_1_1_REQUIRED) {
@@ -877,10 +879,8 @@ int HttpNetworkTransaction::DoInitStream() {
DCHECK(stream_.get());
next_state_ = STATE_INIT_STREAM_COMPLETE;
- stream_->GetRemoteEndpoint(&remote_endpoint_);
-
- return stream_->InitializeStream(request_, can_send_early_data_, priority_,
- net_log_, io_callback_);
+ return stream_->InitializeStream(can_send_early_data_, priority_, net_log_,
+ io_callback_);
}
int HttpNetworkTransaction::DoInitStreamComplete(int result) {
@@ -898,30 +898,47 @@ int HttpNetworkTransaction::DoInitStreamComplete(int result) {
return result;
}
+ next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+ return result;
+}
+
+int HttpNetworkTransaction::DoConnectedCallback() {
+ // Register the HttpRequestInfo object on the stream here so that it's
+ // available when invoking the `connected_callback_`, as
+ // 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;
- // Fire off notification that we have successfully connected.
- if (!connected_callback_.is_null()) {
- TransportType type = TransportType::kDirect;
- if (!proxy_info_.is_direct()) {
- type = TransportType::kProxied;
- }
- result = connected_callback_.Run(
- TransportInfo(type, remote_endpoint_,
- std::string(stream_->GetAcceptChViaAlps())),
- base::BindOnce(&HttpNetworkTransaction::ResumeAfterConnected,
- base::Unretained(this)));
+ if (connected_callback_.is_null()) {
+ return OK;
}
- return result;
+ // Fire off notification that we have successfully connected.
+ TransportType type = TransportType::kDirect;
+ if (!proxy_info_.is_direct()) {
+ type = TransportType::kProxied;
+ }
+ return connected_callback_.Run(
+ TransportInfo(type, remote_endpoint_,
+ std::string{stream_->GetAcceptChViaAlps()}),
+ base::BindOnce(&HttpNetworkTransaction::ResumeAfterConnected,
+ base::Unretained(this)));
}
int HttpNetworkTransaction::DoConnectedCallbackComplete(int result) {
- if (result == OK) {
- // Only transition if we succeeded. Otherwise stop at STATE_NONE.
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+ if (result != OK) {
+ if (stream_) {
+ stream_->Close(/*not_reusable=*/false);
+ }
+
+ // Stop the state machine here if the call failed.
+ return result;
}
- return result;
+
+ next_state_ = STATE_INIT_STREAM;
+ return OK;
}
int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
diff --git a/chromium/net/http/http_network_transaction.h b/chromium/net/http/http_network_transaction.h
index 551612a572d..38120f07544 100644
--- a/chromium/net/http/http_network_transaction.h
+++ b/chromium/net/http/http_network_transaction.h
@@ -124,7 +124,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
SSLCertRequestInfo* cert_info) override;
void OnQuicBroken() override;
- void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ ConnectionAttempts GetConnectionAttempts() const override;
private:
FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, ResetStateForRestart);
@@ -145,6 +145,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
STATE_CREATE_STREAM_COMPLETE,
STATE_INIT_STREAM,
STATE_INIT_STREAM_COMPLETE,
+ STATE_CONNECTED_CALLBACK,
STATE_CONNECTED_CALLBACK_COMPLETE,
STATE_GENERATE_PROXY_AUTH_TOKEN,
STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE,
@@ -186,7 +187,8 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
int DoCreateStreamComplete(int result);
int DoInitStream();
int DoInitStreamComplete(int result);
- int DoConnectedCallbackComplete(int results);
+ int DoConnectedCallback();
+ int DoConnectedCallbackComplete(int result);
int DoGenerateProxyAuthToken();
int DoGenerateProxyAuthTokenComplete(int result);
int DoGenerateServerAuthToken();
@@ -395,7 +397,8 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
int64_t total_sent_bytes_;
// When the transaction started / finished sending the request, including
- // the body, if present.
+ // the body, if present. |send_start_time_| is set to |base::TimeTicks()|
+ // until |SendRequest()| is called on |stream_|, and reset for auth restarts.
base::TimeTicks send_start_time_;
base::TimeTicks send_end_time_;
diff --git a/chromium/net/http/http_network_transaction_unittest.cc b/chromium/net/http/http_network_transaction_unittest.cc
index 3c2eae1ece9..d9225864e3a 100644
--- a/chromium/net/http/http_network_transaction_unittest.cc
+++ b/chromium/net/http/http_network_transaction_unittest.cc
@@ -17,7 +17,6 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_writer.h"
@@ -37,6 +36,7 @@
#include "base/test/task_environment.h"
#include "base/test/test_file_util.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "net/base/auth.h"
#include "net/base/chunked_upload_data_stream.h"
@@ -115,7 +115,7 @@
#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/test/test_with_task_environment.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/websockets/websocket_handshake_stream_base.h"
@@ -576,7 +576,7 @@ class HttpNetworkTransactionTest : public PlatformTest,
// The total number of sent bytes should not have changed.
EXPECT_EQ(out.total_sent_bytes, trans.GetTotalSentBytes());
- trans.GetConnectionAttempts(&out.connection_attempts);
+ out.connection_attempts = trans.GetConnectionAttempts();
return out;
}
@@ -981,6 +981,57 @@ TEST_F(HttpNetworkTransactionTest, ConnectedCallbackFailure) {
ElementsAre(EmbeddedHttpServerTransportInfo()));
}
+// This test verifies that if the ConnectedCallback returns an error, the
+// underlying socket is not closed and can be reused by the next transaction.
+TEST_F(HttpNetworkTransactionTest, ConnectedCallbackFailureAllowsSocketReuse) {
+ ConnectedHandler connected_handler;
+ connected_handler.set_result(ERR_NOT_IMPLEMENTED);
+
+ std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
+ auto request = DefaultRequestInfo();
+
+ // A single socket should be opened and used for both transactions. Data
+ // providers are matched to sockets at most once.
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.0 200 OK\r\n"),
+ MockRead("X-Test-Header: foo\r\n\r\n"),
+ MockRead(SYNCHRONOUS, OK),
+ };
+ StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ {
+ HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
+ transaction.SetConnectedCallback(connected_handler.Callback());
+
+ TestCompletionCallback callback;
+ EXPECT_THAT(
+ transaction.Start(&request, callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NOT_IMPLEMENTED));
+ }
+
+ // The data provider should still be linked to a socket.
+ EXPECT_TRUE(data.socket());
+ auto* socket = data.socket();
+
+ {
+ HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
+
+ TestCompletionCallback callback;
+ EXPECT_THAT(
+ transaction.Start(&request, callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+ EXPECT_TRUE(transaction.GetResponseInfo()->headers->HasHeaderValue(
+ "X-Test-Header", "foo"));
+
+ // Still linked to the same socket.
+ EXPECT_EQ(data.socket(), socket);
+ }
+}
+
// This test verifies that the ConnectedCallback is called once in the case of
// simple requests.
TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledOnce) {
@@ -1983,7 +2034,7 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
ChunkedUploadDataStream upload_data_stream(0);
if (chunked_upload) {
request.method = "POST";
- upload_data_stream.AppendData(upload_data, base::size(upload_data) - 1,
+ upload_data_stream.AppendData(upload_data, std::size(upload_data) - 1,
true);
request.upload_data_stream = &upload_data_stream;
}
@@ -2524,7 +2575,7 @@ TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
data.set_busy_before_sync_reads(true);
session_deps_.socket_factory->AddSocketDataProvider(&data);
- const int kNumUnreadBodies = base::size(data_writes) - 1;
+ const int kNumUnreadBodies = std::size(data_writes) - 1;
std::string response_lines[kNumUnreadBodies];
uint32_t first_socket_log_id = NetLogSource::kInvalidId;
@@ -2571,7 +2622,7 @@ TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
"HTTP/1.1 200 Hunky-Dory",
};
- static_assert(kNumUnreadBodies == base::size(kStatusLines),
+ static_assert(kNumUnreadBodies == std::size(kStatusLines),
"forgot to update kStatusLines");
for (int i = 0; i < kNumUnreadBodies; ++i)
@@ -5999,7 +6050,7 @@ TEST_F(HttpNetworkTransactionTest, SameDestinationForDifferentProxyTypes) {
};
MockWrite socks5_writes[] = {
MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
- MockWrite(ASYNC, kSOCKS5Request, base::size(kSOCKS5Request)),
+ MockWrite(ASYNC, kSOCKS5Request, std::size(kSOCKS5Request)),
MockWrite(SYNCHRONOUS,
"GET /socks5 HTTP/1.1\r\n"
"Host: test\r\n"
@@ -6687,7 +6738,7 @@ TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
"proxy-authorization", "Basic Zm9vOmJhcg=="
};
spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
- kExtraAuthorizationHeaders, base::size(kExtraAuthorizationHeaders) / 2, 3,
+ kExtraAuthorizationHeaders, std::size(kExtraAuthorizationHeaders) / 2, 3,
LOWEST));
MockWrite spdy_writes[] = {
CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
@@ -6702,7 +6753,7 @@ TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
spdy::SpdySerializedFrame resp_authentication(
spdy_util_.ConstructSpdyReplyError(
"407", kExtraAuthenticationHeaders,
- base::size(kExtraAuthenticationHeaders) / 2, 1));
+ std::size(kExtraAuthenticationHeaders) / 2, 1));
spdy::SpdySerializedFrame body_authentication(
spdy_util_.ConstructSpdyDataFrame(1, true));
spdy::SpdySerializedFrame resp_data(
@@ -8647,18 +8698,18 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuthV2) {
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- base::size(ntlm::test::kExpectedNegotiateMsg)),
+ std::size(ntlm::test::kExpectedNegotiateMsg)),
&negotiate_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- base::size(ntlm::test::kChallengeMsgFromSpecV2)),
+ std::size(ntlm::test::kChallengeMsgFromSpecV2)),
&challenge_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- base::size(
+ std::size(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
&authenticate_msg);
@@ -8799,18 +8850,18 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuthV2WrongThenRightPassword) {
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- base::size(ntlm::test::kExpectedNegotiateMsg)),
+ std::size(ntlm::test::kExpectedNegotiateMsg)),
&negotiate_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- base::size(ntlm::test::kChallengeMsgFromSpecV2)),
+ std::size(ntlm::test::kChallengeMsgFromSpecV2)),
&challenge_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- base::size(
+ std::size(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
&authenticate_msg);
@@ -9045,18 +9096,18 @@ TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2) {
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- base::size(ntlm::test::kExpectedNegotiateMsg)),
+ std::size(ntlm::test::kExpectedNegotiateMsg)),
&negotiate_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- base::size(ntlm::test::kChallengeMsgFromSpecV2)),
+ std::size(ntlm::test::kChallengeMsgFromSpecV2)),
&challenge_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- base::size(
+ std::size(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
&authenticate_msg);
@@ -9236,18 +9287,18 @@ TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2WithWebsockets) {
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- base::size(ntlm::test::kExpectedNegotiateMsg)),
+ std::size(ntlm::test::kExpectedNegotiateMsg)),
&negotiate_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- base::size(ntlm::test::kChallengeMsgFromSpecV2)),
+ std::size(ntlm::test::kChallengeMsgFromSpecV2)),
&challenge_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- base::size(
+ std::size(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
&authenticate_msg);
@@ -9426,18 +9477,18 @@ TEST_F(HttpNetworkTransactionTest, NTLMProxyTLSHandshakeReset) {
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- base::size(ntlm::test::kExpectedNegotiateMsg)),
+ std::size(ntlm::test::kExpectedNegotiateMsg)),
&negotiate_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- base::size(ntlm::test::kChallengeMsgFromSpecV2)),
+ std::size(ntlm::test::kChallengeMsgFromSpecV2)),
&challenge_msg);
base::Base64Encode(
base::StringPiece(
reinterpret_cast<const char*>(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- base::size(
+ std::size(
ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
&authenticate_msg);
@@ -11535,7 +11586,7 @@ TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
"http://login.example.com/",
};
spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
- "302", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
+ "302", kExtraHeaders, std::size(kExtraHeaders) / 2, 1));
MockRead data_reads[] = {
// Pause on first read.
MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2),
@@ -11645,7 +11696,7 @@ TEST_F(HttpNetworkTransactionTest, ErrorResponseToHttpsConnectViaSpdyProxy) {
"http://login.example.com/",
};
spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
- "404", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
+ "404", kExtraHeaders, std::size(kExtraHeaders) / 2, 1));
spdy::SpdySerializedFrame body(
spdy_util_.ConstructSpdyDataFrame(1, "The host does not exist", true));
MockRead data_reads[] = {
@@ -11707,7 +11758,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
"proxy-authorization", "Basic Zm9vOmJhcg==",
};
spdy::SpdySerializedFrame connect2(spdy_util_.ConstructSpdyConnect(
- kAuthCredentials, base::size(kAuthCredentials) / 2, 3,
+ kAuthCredentials, std::size(kAuthCredentials) / 2, 3,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair("www.example.org", 443)));
// fetch https://www.example.org/ via HTTP
@@ -11730,7 +11781,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
"proxy-authenticate", "Basic realm=\"MyRealm1\"",
};
spdy::SpdySerializedFrame conn_auth_resp(spdy_util_.ConstructSpdyReplyError(
- kAuthStatus, kAuthChallenge, base::size(kAuthChallenge) / 2, 1));
+ kAuthStatus, kAuthChallenge, std::size(kAuthChallenge) / 2, 1));
spdy::SpdySerializedFrame conn_resp(
spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
@@ -12339,13 +12390,13 @@ TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
MockWrite data_writes[] = {
- MockWrite(ASYNC, write_buffer, base::size(write_buffer)),
+ MockWrite(ASYNC, write_buffer, std::size(write_buffer)),
MockWrite("GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n")};
MockRead data_reads[] = {
- MockRead(ASYNC, read_buffer, base::size(read_buffer)),
+ MockRead(ASYNC, read_buffer, std::size(read_buffer)),
MockRead("HTTP/1.0 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
@@ -12396,14 +12447,14 @@ TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
MockWrite data_writes[] = {
MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer),
- base::size(write_buffer)),
+ std::size(write_buffer)),
MockWrite("GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n")};
MockRead data_reads[] = {
MockRead(ASYNC, reinterpret_cast<char*>(read_buffer),
- base::size(read_buffer)),
+ std::size(read_buffer)),
MockRead("HTTP/1.0 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
@@ -12456,13 +12507,13 @@ TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
MockWrite data_writes[] = {
- MockWrite(ASYNC, write_buffer, base::size(write_buffer)),
+ MockWrite(ASYNC, write_buffer, std::size(write_buffer)),
MockWrite("GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n")};
MockRead data_reads[] = {
- MockRead(ASYNC, read_buffer, base::size(read_buffer)),
+ MockRead(ASYNC, read_buffer, std::size(read_buffer)),
MockRead("HTTP/1.0 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
@@ -12521,7 +12572,7 @@ TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
MockWrite data_writes[] = {
MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
MockWrite(ASYNC, kSOCKS5ExampleOkRequest,
- base::size(kSOCKS5ExampleOkRequest)),
+ std::size(kSOCKS5ExampleOkRequest)),
MockWrite("GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n")};
@@ -12592,14 +12643,14 @@ TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
MockWrite data_writes[] = {
MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5ExampleOkRequest),
- base::size(kSOCKS5ExampleOkRequest)),
+ std::size(kSOCKS5ExampleOkRequest)),
MockWrite("GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n")};
MockRead data_reads[] = {
MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
- MockRead(ASYNC, kSOCKS5SslOkResponse, base::size(kSOCKS5SslOkResponse)),
+ MockRead(ASYNC, kSOCKS5SslOkResponse, std::size(kSOCKS5SslOkResponse)),
MockRead("HTTP/1.0 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
MockRead("Payload"),
@@ -12731,7 +12782,7 @@ TEST_F(HttpNetworkTransactionTest, GroupIdForDirectConnections) {
},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
session_deps_.proxy_resolution_service =
ConfiguredProxyResolutionService::CreateFixed(
tests[i].proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
@@ -12789,7 +12840,7 @@ TEST_F(HttpNetworkTransactionTest, GroupIdForHTTPProxyConnections) {
},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
session_deps_.proxy_resolution_service =
ConfiguredProxyResolutionService::CreateFixed(
tests[i].proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
@@ -12867,7 +12918,7 @@ TEST_F(HttpNetworkTransactionTest, GroupIdForSOCKSConnections) {
},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
session_deps_.proxy_resolution_service =
ConfiguredProxyResolutionService::CreateFixed(
tests[i].proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
@@ -16712,7 +16763,7 @@ TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) {
ERR_CERT_AUTHORITY_INVALID,
ERR_CERT_DATE_INVALID,
};
- for (size_t i = 0; i < base::size(kErrors); i++) {
+ for (size_t i = 0; i < std::size(kErrors); i++) {
CheckErrorIsPassedBack(kErrors[i], ASYNC);
CheckErrorIsPassedBack(kErrors[i], SYNCHRONOUS);
}
@@ -18544,8 +18595,7 @@ TEST_F(HttpNetworkTransactionTest, HttpSyncConnectError) {
rv = callback.WaitForResult();
EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
- ConnectionAttempts attempts;
- trans.GetConnectionAttempts(&attempts);
+ ConnectionAttempts attempts = trans.GetConnectionAttempts();
ASSERT_EQ(1u, attempts.size());
EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
@@ -18577,8 +18627,7 @@ TEST_F(HttpNetworkTransactionTest, HttpAsyncConnectError) {
rv = callback.WaitForResult();
EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
- ConnectionAttempts attempts;
- trans.GetConnectionAttempts(&attempts);
+ ConnectionAttempts attempts = trans.GetConnectionAttempts();
ASSERT_EQ(1u, attempts.size());
EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
diff --git a/chromium/net/http/http_proxy_connect_job_unittest.cc b/chromium/net/http/http_proxy_connect_job_unittest.cc
index d10e833ba0a..e35978efa98 100644
--- a/chromium/net/http/http_proxy_connect_job_unittest.cc
+++ b/chromium/net/http/http_proxy_connect_job_unittest.cc
@@ -9,7 +9,6 @@
#include <string>
#include <utility>
-#include "base/cxx17_backports.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/field_trial_params.h"
@@ -19,6 +18,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "net/base/host_port_pair.h"
#include "net/base/network_isolation_key.h"
@@ -27,6 +27,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/dns/public/secure_dns_policy.h"
#include "net/http/http_network_session.h"
+#include "net/http/http_response_headers.h"
#include "net/nqe/network_quality_estimator_test_util.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/connect_job_test_util.h"
@@ -512,12 +513,12 @@ TEST_P(HttpProxyConnectJobTest, ProxyDelegateExtraHeaders) {
kResponseHeaderValue,
};
spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
- kExtraRequestHeaders, base::size(kExtraRequestHeaders) / 2, 1,
+ kExtraRequestHeaders, std::size(kExtraRequestHeaders) / 2, 1,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(
- kExtraResponseHeaders, base::size(kExtraResponseHeaders) / 2, 1));
+ kExtraResponseHeaders, std::size(kExtraResponseHeaders) / 2, 1));
MockRead spdy_reads[] = {
CreateMockRead(resp, 1, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
@@ -577,7 +578,7 @@ TEST_P(HttpProxyConnectJobTest, NeedAuth) {
"Basic Zm9vOmJhcg==",
};
spdy::SpdySerializedFrame connect2(spdy_util.ConstructSpdyConnect(
- kSpdyAuthCredentials, base::size(kSpdyAuthCredentials) / 2, 3,
+ kSpdyAuthCredentials, std::size(kSpdyAuthCredentials) / 2, 3,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
@@ -596,7 +597,7 @@ TEST_P(HttpProxyConnectJobTest, NeedAuth) {
};
spdy::SpdySerializedFrame connect_auth_resp(
spdy_util.ConstructSpdyReplyError(kAuthStatus, kAuthChallenge,
- base::size(kAuthChallenge) / 2, 1));
+ std::size(kAuthChallenge) / 2, 1));
spdy::SpdySerializedFrame connect2_resp(
spdy_util.ConstructSpdyGetReply(nullptr, 0, 3));
@@ -694,7 +695,7 @@ TEST_P(HttpProxyConnectJobTest, NeedAuthTwice) {
"Basic Zm9vOmJhcg==",
};
spdy::SpdySerializedFrame connect2(spdy_util.ConstructSpdyConnect(
- kSpdyAuthCredentials, base::size(kSpdyAuthCredentials) / 2, 3,
+ kSpdyAuthCredentials, std::size(kSpdyAuthCredentials) / 2, 3,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
spdy::SpdySerializedFrame rst2(
@@ -702,7 +703,7 @@ TEST_P(HttpProxyConnectJobTest, NeedAuthTwice) {
spdy_util.UpdateWithStreamDestruction(3);
spdy::SpdySerializedFrame connect3(spdy_util.ConstructSpdyConnect(
- kSpdyAuthCredentials, base::size(kSpdyAuthCredentials) / 2, 5,
+ kSpdyAuthCredentials, std::size(kSpdyAuthCredentials) / 2, 5,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
MockWrite spdy_writes[] = {
@@ -722,10 +723,10 @@ TEST_P(HttpProxyConnectJobTest, NeedAuthTwice) {
};
spdy::SpdySerializedFrame connect_auth_resp(
spdy_util.ConstructSpdyReplyError(kAuthStatus, kAuthChallenge,
- base::size(kAuthChallenge) / 2, 1));
+ std::size(kAuthChallenge) / 2, 1));
spdy::SpdySerializedFrame connect2_auth_resp(
spdy_util.ConstructSpdyReplyError(kAuthStatus, kAuthChallenge,
- base::size(kAuthChallenge) / 2, 3));
+ std::size(kAuthChallenge) / 2, 3));
spdy::SpdySerializedFrame connect3_resp(
spdy_util.ConstructSpdyGetReply(nullptr, 0, 5));
MockRead spdy_reads[] = {
@@ -819,7 +820,7 @@ TEST_P(HttpProxyConnectJobTest, HaveAuth) {
};
SpdyTestUtil spdy_util;
spdy::SpdySerializedFrame connect(spdy_util.ConstructSpdyConnect(
- kSpdyAuthCredentials, base::size(kSpdyAuthCredentials) / 2, 1,
+ kSpdyAuthCredentials, std::size(kSpdyAuthCredentials) / 2, 1,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
@@ -1268,7 +1269,7 @@ TEST_P(HttpProxyConnectJobTest, TunnelSetupRedirect) {
"set-cookie",
"foo=bar",
};
- const int responseHeadersSize = base::size(responseHeaders) / 2;
+ const int responseHeadersSize = std::size(responseHeaders) / 2;
spdy::SpdySerializedFrame resp(spdy_util.ConstructSpdyReplyError(
"302", responseHeaders, responseHeadersSize, 1));
MockRead spdy_reads[] = {
@@ -1358,7 +1359,7 @@ TEST_P(HttpProxyConnectJobTest, TestTimeoutsAuthChallenge) {
"Basic Zm9vOmJhcg==",
};
spdy::SpdySerializedFrame connect2(spdy_util.ConstructSpdyConnect(
- kSpdyAuthCredentials, base::size(kSpdyAuthCredentials) / 2, 3,
+ kSpdyAuthCredentials, std::size(kSpdyAuthCredentials) / 2, 3,
HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair(kEndpointHost, 443)));
// This may be sent in some tests, either when tearing down a successful
@@ -1380,7 +1381,7 @@ TEST_P(HttpProxyConnectJobTest, TestTimeoutsAuthChallenge) {
"Basic realm=\"MyRealm1\"",
};
spdy::SpdySerializedFrame connect_auth_resp(spdy_util.ConstructSpdyReplyError(
- kAuthStatus, kAuthChallenge, base::size(kAuthChallenge) / 2, 1));
+ kAuthStatus, kAuthChallenge, std::size(kAuthChallenge) / 2, 1));
spdy::SpdySerializedFrame connect2_resp(
spdy_util.ConstructSpdyGetReply(nullptr, 0, 3));
MockRead spdy_reads[] = {
diff --git a/chromium/net/http/http_response_body_drainer_unittest.cc b/chromium/net/http/http_response_body_drainer_unittest.cc
index d2f92e426ba..ed70a0d0f83 100644
--- a/chromium/net/http/http_response_body_drainer_unittest.cc
+++ b/chromium/net/http/http_response_body_drainer_unittest.cc
@@ -32,6 +32,7 @@
#include "net/http/transport_security_state.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/quic/quic_context.h"
+#include "net/socket/socket_test_util.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/test/test_with_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -97,8 +98,8 @@ class MockHttpStream : public HttpStream {
~MockHttpStream() override = default;
// HttpStream implementation.
- int InitializeStream(const HttpRequestInfo* request_info,
- bool can_send_early,
+ void RegisterRequest(const HttpRequestInfo* request_info) override {}
+ int InitializeStream(bool can_send_early,
RequestPriority priority,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override {
@@ -256,6 +257,7 @@ class HttpResponseBodyDrainerTest : public TestWithTaskEnvironment {
HttpNetworkSession* CreateNetworkSession() {
HttpNetworkSessionContext context;
+ context.client_socket_factory = &socket_factory_;
context.proxy_resolution_service = proxy_resolution_service_.get();
context.ssl_config_service = ssl_config_service_.get();
context.http_server_properties = http_server_properties_.get();
@@ -273,6 +275,7 @@ class HttpResponseBodyDrainerTest : public TestWithTaskEnvironment {
TransportSecurityState transport_security_state_;
DefaultCTPolicyEnforcer ct_policy_enforcer_;
QuicContext quic_context_;
+ MockClientSocketFactory socket_factory_;
const std::unique_ptr<HttpNetworkSession> session_;
CloseResultWaiter result_waiter_;
const raw_ptr<MockHttpStream> mock_stream_; // Owned by |drainer_|.
diff --git a/chromium/net/http/http_response_headers.cc b/chromium/net/http/http_response_headers.cc
index 4e4cd171d4a..91536513f3d 100644
--- a/chromium/net/http/http_response_headers.cc
+++ b/chromium/net/http/http_response_headers.cc
@@ -15,7 +15,6 @@
#include <unordered_map>
#include <utility>
-#include "base/cxx17_backports.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -110,11 +109,11 @@ const char* const kNonUpdatedHeaderPrefixes[] = {
};
bool ShouldUpdateHeader(base::StringPiece name) {
- for (size_t i = 0; i < base::size(kNonUpdatedHeaders); ++i) {
+ for (size_t i = 0; i < std::size(kNonUpdatedHeaders); ++i) {
if (base::LowerCaseEqualsASCII(name, kNonUpdatedHeaders[i]))
return false;
}
- for (size_t i = 0; i < base::size(kNonUpdatedHeaderPrefixes); ++i) {
+ for (size_t i = 0; i < std::size(kNonUpdatedHeaderPrefixes); ++i) {
if (base::StartsWith(name, kNonUpdatedHeaderPrefixes[i],
base::CompareCase::INSENSITIVE_ASCII))
return false;
@@ -887,17 +886,17 @@ void HttpResponseHeaders::AddNonCacheableHeaders(HeaderSet* result) const {
}
void HttpResponseHeaders::AddHopByHopHeaders(HeaderSet* result) {
- for (size_t i = 0; i < base::size(kHopByHopResponseHeaders); ++i)
+ for (size_t i = 0; i < std::size(kHopByHopResponseHeaders); ++i)
result->insert(std::string(kHopByHopResponseHeaders[i]));
}
void HttpResponseHeaders::AddCookieHeaders(HeaderSet* result) {
- for (size_t i = 0; i < base::size(kCookieResponseHeaders); ++i)
+ for (size_t i = 0; i < std::size(kCookieResponseHeaders); ++i)
result->insert(std::string(kCookieResponseHeaders[i]));
}
void HttpResponseHeaders::AddChallengeHeaders(HeaderSet* result) {
- for (size_t i = 0; i < base::size(kChallengeResponseHeaders); ++i)
+ for (size_t i = 0; i < std::size(kChallengeResponseHeaders); ++i)
result->insert(std::string(kChallengeResponseHeaders[i]));
}
@@ -906,7 +905,7 @@ void HttpResponseHeaders::AddHopContentRangeHeaders(HeaderSet* result) {
}
void HttpResponseHeaders::AddSecurityStateHeaders(HeaderSet* result) {
- for (size_t i = 0; i < base::size(kSecurityStateHeaders); ++i)
+ for (size_t i = 0; i < std::size(kSecurityStateHeaders); ++i)
result->insert(std::string(kSecurityStateHeaders[i]));
}
diff --git a/chromium/net/http/http_response_info.cc b/chromium/net/http/http_response_info.cc
index 111817b508b..cc35dd83961 100644
--- a/chromium/net/http/http_response_info.cc
+++ b/chromium/net/http/http_response_info.cc
@@ -15,7 +15,7 @@
#include "net/http/http_response_headers.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_connection_status_flags.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
using base::Time;
diff --git a/chromium/net/http/http_security_headers_unittest.cc b/chromium/net/http/http_security_headers_unittest.cc
index 63223ba9e01..4d4369c2b4a 100644
--- a/chromium/net/http/http_security_headers_unittest.cc
+++ b/chromium/net/http/http_security_headers_unittest.cc
@@ -4,6 +4,8 @@
#include <stdint.h>
+#include <iterator>
+
#include "base/base64.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
@@ -21,6 +23,7 @@ namespace net {
namespace {
namespace test_default {
+#include "base/time/time.h"
#include "net/http/transport_security_state_static_unittest_default.h"
}
diff --git a/chromium/net/http/http_server_properties.cc b/chromium/net/http/http_server_properties.cc
index 39e8b65038b..0ac003c574e 100644
--- a/chromium/net/http/http_server_properties.cc
+++ b/chromium/net/http/http_server_properties.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/check_op.h"
+#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/location.h"
@@ -551,10 +552,9 @@ void HttpServerProperties::SetMaxServerConfigsStoredInProperties(
// Update the |canonical_server_info_map_| as well, so it stays in sync with
// |quic_server_info_map_|.
canonical_server_info_map_ = QuicCanonicalMap();
- for (auto it = quic_server_info_map_.rbegin();
- it != quic_server_info_map_.rend(); ++it) {
- temp_map.Put(it->first, it->second);
- UpdateCanonicalServerInfoMap(it->first);
+ for (const auto& [key, server_info] : base::Reversed(quic_server_info_map_)) {
+ temp_map.Put(key, server_info);
+ UpdateCanonicalServerInfoMap(key);
}
quic_server_info_map_.Swap(temp_map);
@@ -564,6 +564,13 @@ void HttpServerProperties::SetMaxServerConfigsStoredInProperties(
}
}
+void HttpServerProperties::SetBrokenAlternativeServicesDelayParams(
+ absl::optional<base::TimeDelta> initial_delay,
+ absl::optional<bool> exponential_backoff_on_initial_delay) {
+ broken_alternative_services_.SetDelayParams(
+ initial_delay, exponential_backoff_on_initial_delay);
+}
+
bool HttpServerProperties::IsInitialized() const {
return is_initialized_;
}
@@ -1119,28 +1126,27 @@ void HttpServerProperties::OnServerInfoLoaded(
server_info_map_.Swap(*server_info_map);
// Add the entries from the memory cache.
- for (auto it = server_info_map->rbegin(); it != server_info_map->rend();
- ++it) {
+ for (auto& [key, server_info] : base::Reversed(*server_info_map)) {
// If there's no corresponding old entry, add the new entry directly.
- auto old_entry = server_info_map_.Get(it->first);
+ auto old_entry = server_info_map_.Get(key);
if (old_entry == server_info_map_.end()) {
- server_info_map_.Put(it->first, std::move(it->second));
+ server_info_map_.Put(key, std::move(server_info));
continue;
}
// Otherwise, merge the old and new entries. Prefer values from older
// entries.
if (!old_entry->second.supports_spdy.has_value())
- old_entry->second.supports_spdy = it->second.supports_spdy;
+ old_entry->second.supports_spdy = server_info.supports_spdy;
if (!old_entry->second.alternative_services.has_value())
- old_entry->second.alternative_services = it->second.alternative_services;
+ old_entry->second.alternative_services = server_info.alternative_services;
if (!old_entry->second.server_network_stats.has_value())
- old_entry->second.server_network_stats = it->second.server_network_stats;
+ old_entry->second.server_network_stats = server_info.server_network_stats;
// |requires_http11| isn't saved to prefs, so the loaded entry should not
// have it set. Unconditionally copy it from the new entry.
DCHECK(!old_entry->second.requires_http11.has_value());
- old_entry->second.requires_http11 = it->second.requires_http11;
+ old_entry->second.requires_http11 = server_info.requires_http11;
}
// Attempt to find canonical servers. Canonical suffix only apply to HTTPS.
@@ -1184,19 +1190,17 @@ void HttpServerProperties::OnQuicServerInfoMapLoaded(
quic_server_info_map_.Swap(*quic_server_info_map);
// Add the entries from the memory cache.
- for (auto it = quic_server_info_map->rbegin();
- it != quic_server_info_map->rend(); ++it) {
- if (quic_server_info_map_.Get(it->first) == quic_server_info_map_.end()) {
- quic_server_info_map_.Put(it->first, it->second);
+ for (const auto& [key, server_info] : base::Reversed(*quic_server_info_map)) {
+ if (quic_server_info_map_.Get(key) == quic_server_info_map_.end()) {
+ quic_server_info_map_.Put(key, server_info);
}
}
// Repopulate |canonical_server_info_map_| to stay in sync with
// |quic_server_info_map_|.
canonical_server_info_map_.clear();
- for (auto it = quic_server_info_map_.rbegin();
- it != quic_server_info_map_.rend(); ++it) {
- UpdateCanonicalServerInfoMap(it->first);
+ for (const auto& [key, server_info] : base::Reversed(quic_server_info_map_)) {
+ UpdateCanonicalServerInfoMap(key);
}
}
diff --git a/chromium/net/http/http_server_properties.h b/chromium/net/http/http_server_properties.h
index 2ea3bf4cbe0..2d782f38455 100644
--- a/chromium/net/http/http_server_properties.h
+++ b/chromium/net/http/http_server_properties.h
@@ -29,11 +29,11 @@
#include "net/base/network_isolation_key.h"
#include "net/http/alternative_service.h"
#include "net/http/broken_alternative_services.h"
-#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
-#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" // TODO(willchan): Reconsider this.
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_bandwidth.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_server_id.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h" // TODO(willchan): Reconsider this.
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/scheme_host_port.h"
@@ -413,6 +413,13 @@ class NET_EXPORT HttpServerProperties
void SetMaxServerConfigsStoredInProperties(
size_t max_server_configs_stored_in_properties);
+ // If values are present, sets initial_delay and
+ // exponential_backoff_on_initial_delay which are used to calculate delay of
+ // broken alternative services.
+ void SetBrokenAlternativeServicesDelayParams(
+ absl::optional<base::TimeDelta> initial_delay,
+ absl::optional<bool> exponential_backoff_on_initial_delay);
+
// Returns whether HttpServerProperties is initialized.
bool IsInitialized() const;
diff --git a/chromium/net/http/http_server_properties_manager.cc b/chromium/net/http/http_server_properties_manager.cc
index a6836ff2555..3513f4fd685 100644
--- a/chromium/net/http/http_server_properties_manager.cc
+++ b/chromium/net/http/http_server_properties_manager.cc
@@ -7,10 +7,12 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/adapters.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/tick_clock.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/host_port_pair.h"
@@ -18,7 +20,7 @@
#include "net/base/port_util.h"
#include "net/base/privacy_mode.h"
#include "net/http/http_server_properties.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/platform/api/quic_hostname_utils.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
@@ -717,11 +719,7 @@ void HttpServerPropertiesManager::WriteToPrefs(
// Convert |server_info_map| to a dictionary Value and add it to
// |http_server_properties_dict|.
base::Value servers_list(base::Value::Type::LIST);
- for (auto map_it = server_info_map.rbegin(); map_it != server_info_map.rend();
- ++map_it) {
- const HttpServerProperties::ServerInfoMapKey key = map_it->first;
- const HttpServerProperties::ServerInfo& server_info = map_it->second;
-
+ 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.
base::Value network_isolation_key_value;
@@ -844,10 +842,7 @@ void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
if (quic_server_info_map.empty())
return;
base::Value quic_servers_list(base::Value::Type::LIST);
- for (auto it = quic_server_info_map.rbegin();
- it != quic_server_info_map.rend(); ++it) {
- const HttpServerProperties::QuicServerInfoMapKey& key = it->first;
-
+ 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))
@@ -858,7 +853,7 @@ void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
QuicServerIdToString(key.server_id));
quic_server_pref_dict.SetKey(kNetworkIsolationKey,
std::move(network_isolation_key_value));
- quic_server_pref_dict.SetStringKey(kServerInfoKey, it->second);
+ quic_server_pref_dict.SetStringKey(kServerInfoKey, server_info);
quic_servers_list.Append(std::move(quic_server_pref_dict));
}
@@ -886,11 +881,8 @@ void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
std::map<BrokenAlternativeService, size_t> json_list_index_map;
if (!recently_broken_alternative_services.empty()) {
- for (auto it = recently_broken_alternative_services.rbegin();
- it != recently_broken_alternative_services.rend(); ++it) {
- const BrokenAlternativeService& broken_alt_service = it->first;
- int broken_count = it->second;
-
+ for (const auto& [broken_alt_service, broken_count] :
+ base::Reversed(recently_broken_alternative_services)) {
base::Value entry_dict(base::Value::Type::DICTIONARY);
if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
broken_alt_service, &entry_dict)) {
diff --git a/chromium/net/http/http_server_properties_manager_unittest.cc b/chromium/net/http/http_server_properties_manager_unittest.cc
index 0b3b339a0e2..598d9c934f7 100644
--- a/chromium/net/http/http_server_properties_manager_unittest.cc
+++ b/chromium/net/http/http_server_properties_manager_unittest.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/feature_list.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
@@ -20,6 +21,7 @@
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/ip_address.h"
diff --git a/chromium/net/http/http_server_properties_unittest.cc b/chromium/net/http/http_server_properties_unittest.cc
index 91a1dc3bb2f..d933e6cab06 100644
--- a/chromium/net/http/http_server_properties_unittest.cc
+++ b/chromium/net/http/http_server_properties_unittest.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/check.h"
#include "base/feature_list.h"
#include "base/json/json_writer.h"
@@ -17,6 +18,7 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/host_port_pair.h"
@@ -2178,6 +2180,66 @@ TEST_F(AlternateProtocolServerPropertiesTest, RemoveExpiredBrokenAltSvc) {
baz_alternative_service, NetworkIsolationKey()));
}
+TEST_F(AlternateProtocolServerPropertiesTest,
+ SetBrokenAlternativeServicesDelayParams1) {
+ url::SchemeHostPort server("https", "foo", 443);
+ AlternativeService alternative_service(kProtoQUIC, "foo", 443);
+ SetAlternativeService(server, alternative_service);
+
+ const base::TimeDelta initial_delay = base::Seconds(1);
+ impl_.SetBrokenAlternativeServicesDelayParams(initial_delay, true);
+ for (int i = 0; i < 10; ++i) {
+ impl_.MarkAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey());
+ // |impl_| should have posted task to expire the brokenness of
+ // |alternative_service|
+ EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
+ EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey()));
+
+ // Advance time by just enough so that |alternative_service|'s brokenness
+ // expires.
+ FastForwardBy(initial_delay * (1 << i));
+
+ // Ensure brokenness of |alternative_service| has expired.
+ EXPECT_EQ(0u, GetPendingMainThreadTaskCount());
+ EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey()));
+ }
+}
+
+TEST_F(AlternateProtocolServerPropertiesTest,
+ SetBrokenAlternativeServicesDelayParams2) {
+ url::SchemeHostPort server("https", "foo", 443);
+ AlternativeService alternative_service(kProtoQUIC, "foo", 443);
+ SetAlternativeService(server, alternative_service);
+
+ const base::TimeDelta initial_delay = base::Seconds(5);
+ impl_.SetBrokenAlternativeServicesDelayParams(initial_delay, false);
+ for (int i = 0; i < 10; ++i) {
+ impl_.MarkAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey());
+ // |impl_| should have posted task to expire the brokenness of
+ // |alternative_service|
+ EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
+ EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey()));
+
+ // Advance time by just enough so that |alternative_service|'s brokenness
+ // expires.
+ if (i == 0) {
+ FastForwardBy(initial_delay);
+ } else {
+ FastForwardBy(base::Seconds(300) * (1 << (i - 1)));
+ }
+
+ // Ensure brokenness of |alternative_service| has expired.
+ EXPECT_EQ(0u, GetPendingMainThreadTaskCount());
+ EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service,
+ NetworkIsolationKey()));
+ }
+}
+
// Regression test for https://crbug.com/724302
TEST_F(AlternateProtocolServerPropertiesTest, RemoveExpiredBrokenAltSvc2) {
// This test will mark an alternative service A that has already been marked
diff --git a/chromium/net/http/http_stream.h b/chromium/net/http/http_stream.h
index 668b1fff169..04d1507f8ce 100644
--- a/chromium/net/http/http_stream.h
+++ b/chromium/net/http/http_stream.h
@@ -48,15 +48,21 @@ class NET_EXPORT_PRIVATE HttpStream {
virtual ~HttpStream() {}
- // Initialize stream. Must be called before calling SendRequest().
- // The consumer should ensure that request_info points to a valid value till
- // final response headers are received; after that point, the HttpStream
- // will not access |*request_info| and it may be deleted. If |can_send_early|
- // is true, this stream may send data early without confirming the handshake
- // if this is a resumption of a previously established connection.
- // Returns a net error code, possibly ERR_IO_PENDING.
- virtual int InitializeStream(const HttpRequestInfo* request_info,
- bool can_send_early,
+ // Registers the HTTP request for the stream. Must be called before calling
+ // InitializeStream(). Separating the registration of the request from the
+ // initialization of the stream allows the connection callback to run prior
+ // to stream initialization.
+ //
+ // The consumer should ensure that request_info points to a valid non-null
+ // value till final response headers are received; after that point, the
+ // HttpStream will not access |*request_info| and it may be deleted.
+ virtual void RegisterRequest(const HttpRequestInfo* request_info) = 0;
+
+ // Initializes the stream. Must be called before calling SendRequest().
+ // If |can_send_early| is true, this stream may send data early without
+ // confirming the handshake if this is a resumption of a previously
+ // established connection. Returns a net error code, possibly ERR_IO_PENDING.
+ virtual int InitializeStream(bool can_send_early,
RequestPriority priority,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) = 0;
diff --git a/chromium/net/http/http_stream_factory.cc b/chromium/net/http/http_stream_factory.cc
index cd4437ebdb5..7812973922f 100644
--- a/chromium/net/http/http_stream_factory.cc
+++ b/chromium/net/http/http_stream_factory.cc
@@ -29,9 +29,9 @@
#include "net/quic/quic_http_utils.h"
#include "net/spdy/bidirectional_stream_spdy_impl.h"
#include "net/spdy/spdy_http_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_packets.h"
-#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_server_id.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_alt_svc_wire_format.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
#include "url/url_constants.h"
diff --git a/chromium/net/http/http_stream_factory_job.cc b/chromium/net/http/http_stream_factory_job.cc
index a01b633bec3..b8583f068a9 100644
--- a/chromium/net/http/http_stream_factory_job.cc
+++ b/chromium/net/http/http_stream_factory_job.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
@@ -55,7 +56,7 @@
#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_session.h"
#include "net/ssl/ssl_cert_request_info.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
#include "url/scheme_host_port.h"
#include "url/url_constants.h"
diff --git a/chromium/net/http/http_stream_factory_job_controller.cc b/chromium/net/http/http_stream_factory_job_controller.cc
index dbd06029d26..98d2dfdc8f5 100644
--- a/chromium/net/http/http_stream_factory_job_controller.cc
+++ b/chromium/net/http/http_stream_factory_job_controller.cc
@@ -58,12 +58,10 @@ GURL CreateAltSvcUrl(const GURL& origin_url,
DCHECK(origin_url.is_valid());
DCHECK(origin_url.IsStandard());
- url::Replacements<char> replacements;
+ GURL::Replacements replacements;
std::string port_str = base::NumberToString(alternative_destination.port());
- replacements.SetPort(port_str.c_str(), url::Component(0, port_str.size()));
- replacements.SetHost(
- alternative_destination.host().c_str(),
- url::Component(0, alternative_destination.host().size()));
+ replacements.SetPortStr(port_str);
+ replacements.SetHostStr(alternative_destination.host());
return origin_url.ReplaceComponents(replacements);
}
diff --git a/chromium/net/http/http_stream_factory_job_controller.h b/chromium/net/http/http_stream_factory_job_controller.h
index 030b4684c83..5b5cb2ad651 100644
--- a/chromium/net/http/http_stream_factory_job_controller.h
+++ b/chromium/net/http/http_stream_factory_job_controller.h
@@ -10,6 +10,7 @@
#include "base/cancelable_callback.h"
#include "base/memory/raw_ptr.h"
+#include "base/time/time.h"
#include "net/base/host_port_pair.h"
#include "net/base/privacy_mode.h"
#include "net/http/http_stream_factory_job.h"
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 dfc8a8db3af..cd013d32fa1 100644
--- a/chromium/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/chromium/net/http/http_stream_factory_job_controller_unittest.cc
@@ -32,6 +32,7 @@
#include "net/dns/public/secure_dns_policy.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_network_session_peer.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_server_properties_manager.h"
#include "net/http/http_stream_factory.h"
@@ -55,7 +56,7 @@
#include "net/spdy/spdy_session_key.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/test/test_with_task_environment.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/net/http/http_stream_factory_unittest.cc b/chromium/net/http/http_stream_factory_unittest.cc
index a3d9af1983a..7145365d4ac 100644
--- a/chromium/net/http/http_stream_factory_unittest.cc
+++ b/chromium/net/http/http_stream_factory_unittest.cc
@@ -15,7 +15,6 @@
#include "base/compiler_specific.h"
#include "base/containers/contains.h"
-#include "base/cxx17_backports.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
@@ -77,12 +76,16 @@
#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/test/test_with_task_environment.h"
-#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_server_id.h"
+#include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quiche/quic/test_tools/mock_random.h"
+#include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+// This file can be included from net/http even though
+// it is in net/websockets because it doesn't
+// introduce any link dependency to net/websockets.
+#include "net/websockets/websocket_handshake_stream_base.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -90,11 +93,6 @@
#include "url/scheme_host_port.h"
#include "url/url_constants.h"
-// This file can be included from net/http even though
-// it is in net/websockets because it doesn't
-// introduce any link dependency to net/websockets.
-#include "net/websockets/websocket_handshake_stream_base.h"
-
using ::testing::Contains;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
@@ -129,8 +127,8 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
StreamType type() const { return type_; }
// HttpStream methods
- int InitializeStream(const HttpRequestInfo* request_info,
- bool can_send_early,
+ void RegisterRequest(const HttpRequestInfo* request_info) override {}
+ int InitializeStream(bool can_send_early,
RequestPriority priority,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override {
@@ -505,7 +503,7 @@ class CapturePreconnectsTransportSocketPool : public TransportClientSocketPool {
using HttpStreamFactoryTest = TestWithTaskEnvironment;
TEST_F(HttpStreamFactoryTest, PreconnectDirect) {
- for (size_t i = 0; i < base::size(kTests); ++i) {
+ for (size_t i = 0; i < std::size(kTests); ++i) {
SpdySessionDependencies session_deps(
ConfiguredProxyResolutionService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
@@ -530,7 +528,7 @@ TEST_F(HttpStreamFactoryTest, PreconnectDirect) {
}
TEST_F(HttpStreamFactoryTest, PreconnectHttpProxy) {
- for (size_t i = 0; i < base::size(kTests); ++i) {
+ for (size_t i = 0; i < std::size(kTests); ++i) {
SpdySessionDependencies session_deps(
ConfiguredProxyResolutionService::CreateFixed(
"http_proxy", TRAFFIC_ANNOTATION_FOR_TESTS));
@@ -554,7 +552,7 @@ TEST_F(HttpStreamFactoryTest, PreconnectHttpProxy) {
}
TEST_F(HttpStreamFactoryTest, PreconnectSocksProxy) {
- for (size_t i = 0; i < base::size(kTests); ++i) {
+ for (size_t i = 0; i < std::size(kTests); ++i) {
SpdySessionDependencies session_deps(
ConfiguredProxyResolutionService::CreateFixed(
"socks4://socks_proxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS));
@@ -578,7 +576,7 @@ TEST_F(HttpStreamFactoryTest, PreconnectSocksProxy) {
}
TEST_F(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) {
- for (size_t i = 0; i < base::size(kTests); ++i) {
+ for (size_t i = 0; i < std::size(kTests); ++i) {
SpdySessionDependencies session_deps(
ConfiguredProxyResolutionService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
@@ -2753,10 +2751,10 @@ TEST_F(HttpStreamFactoryTest, ChangeSocketTag) {
// Verify attempting to use the first stream fails because the session's
// socket tag has since changed.
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_FAILED,
- waiter1.stream()->InitializeStream(
- &request_info1, /* can_send_early = */ false, DEFAULT_PRIORITY,
- NetLogWithSource(), callback1.callback()));
+ waiter1.stream()->RegisterRequest(&request_info1);
+ EXPECT_EQ(ERR_FAILED, waiter1.stream()->InitializeStream(
+ /* can_send_early = */ false, DEFAULT_PRIORITY,
+ NetLogWithSource(), callback1.callback()));
// Verify the socket tag can be changed, this time using an IP alias
// (different host, same IP).
@@ -2787,10 +2785,10 @@ TEST_F(HttpStreamFactoryTest, ChangeSocketTag) {
// Initialize the third stream, thus marking the session active, so it cannot
// have its socket tag changed.
TestCompletionCallback callback3;
- EXPECT_EQ(OK,
- waiter3.stream()->InitializeStream(
- &request_info3, /* can_send_early = */ false, DEFAULT_PRIORITY,
- NetLogWithSource(), callback3.callback()));
+ waiter3.stream()->RegisterRequest(&request_info3);
+ EXPECT_EQ(OK, waiter3.stream()->InitializeStream(
+ /* can_send_early = */ false, DEFAULT_PRIORITY,
+ NetLogWithSource(), callback3.callback()));
// Verify a new session is created when a request with a different tag is
// started.
@@ -2910,10 +2908,10 @@ TEST_F(HttpStreamFactoryTest, ChangeSocketTagAvoidOverwrite) {
// Initialize the first stream, thus marking the session active, so it cannot
// have its socket tag changed and be reused for the second session.
TestCompletionCallback callback1;
- EXPECT_EQ(OK,
- waiter1.stream()->InitializeStream(
- &request_info1, /* can_send_early = */ false, DEFAULT_PRIORITY,
- NetLogWithSource(), callback1.callback()));
+ waiter1.stream()->RegisterRequest(&request_info1);
+ EXPECT_EQ(OK, waiter1.stream()->InitializeStream(
+ /* can_send_early = */ false, DEFAULT_PRIORITY,
+ NetLogWithSource(), callback1.callback()));
// Create a second stream with a new tag.
StreamRequestWaiter waiter2;
@@ -2946,10 +2944,10 @@ TEST_F(HttpStreamFactoryTest, ChangeSocketTagAvoidOverwrite) {
// Initialize the second stream, thus marking the session active, so it cannot
// have its socket tag changed and be reused for the third session.
TestCompletionCallback callback2;
- EXPECT_EQ(OK,
- waiter2.stream()->InitializeStream(
- &request_info2, /* can_send_early = */ false, DEFAULT_PRIORITY,
- NetLogWithSource(), callback2.callback()));
+ waiter2.stream()->RegisterRequest(&request_info2);
+ EXPECT_EQ(OK, waiter2.stream()->InitializeStream(
+ /* can_send_early = */ false, DEFAULT_PRIORITY,
+ NetLogWithSource(), callback2.callback()));
// Release first stream so first session can be retagged for third request.
waiter1.stream()->Close(/* not_reusable = */ true);
diff --git a/chromium/net/http/http_stream_parser.cc b/chromium/net/http/http_stream_parser.cc
index aaa22ac7001..0637a502b9a 100644
--- a/chromium/net/http/http_stream_parser.cc
+++ b/chromium/net/http/http_stream_parser.cc
@@ -52,24 +52,6 @@ std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) {
return cr_separated_headers;
}
-// Return true if |headers| contain multiple |field_name| fields with different
-// values.
-bool HeadersContainMultipleCopiesOfField(const HttpResponseHeaders& headers,
- const std::string& field_name) {
- size_t it = 0;
- std::string field_value;
- if (!headers.EnumerateHeader(&it, field_name, &field_value))
- return false;
- // There's at least one |field_name| header. Check if there are any more
- // such headers, and if so, return true if they have different values.
- std::string field_value2;
- while (headers.EnumerateHeader(&it, field_name, &field_value2)) {
- if (field_value != field_value2)
- return true;
- }
- return false;
-}
-
base::Value NetLogSendRequestBodyParams(uint64_t length,
bool is_chunked,
bool did_merge) {
@@ -1049,15 +1031,17 @@ int HttpStreamParser::ParseResponseHeaders(int end_offset) {
// chunked-encoded. If they exist, and have distinct values, it's a potential
// response smuggling attack.
if (!headers->IsChunkEncoded()) {
- if (HeadersContainMultipleCopiesOfField(*headers, "Content-Length"))
+ if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
+ "Content-Length"))
return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH;
}
// Check for multiple Content-Disposition or Location headers. If they exist,
// it's also a potential response smuggling attack.
- if (HeadersContainMultipleCopiesOfField(*headers, "Content-Disposition"))
+ if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
+ "Content-Disposition"))
return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION;
- if (HeadersContainMultipleCopiesOfField(*headers, "Location"))
+ if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers, "Location"))
return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION;
response_->headers = headers;
diff --git a/chromium/net/http/http_stream_parser.h b/chromium/net/http/http_stream_parser.h
index 0c0619bdcf4..16b5c49983b 100644
--- a/chromium/net/http/http_stream_parser.h
+++ b/chromium/net/http/http_stream_parser.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
+#include "base/time/time.h"
#include "crypto/ec_private_key.h"
#include "net/base/completion_once_callback.h"
#include "net/base/completion_repeating_callback.h"
diff --git a/chromium/net/http/http_stream_parser_unittest.cc b/chromium/net/http/http_stream_parser_unittest.cc
index e25b78539df..62373540a51 100644
--- a/chromium/net/http/http_stream_parser_unittest.cc
+++ b/chromium/net/http/http_stream_parser_unittest.cc
@@ -13,7 +13,6 @@
#include <vector>
#include "base/bind.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -273,7 +272,7 @@ TEST(HttpStreamParser, InitAsynchronousUploadDataStream) {
callback1.callback());
EXPECT_EQ(ERR_IO_PENDING, result1);
base::RunLoop().RunUntilIdle();
- upload_data_stream.AppendData(kChunk, base::size(kChunk) - 1, true);
+ upload_data_stream.AppendData(kChunk, std::size(kChunk) - 1, true);
// Check progress after read completes.
progress = upload_data_stream.GetUploadProgress();
@@ -644,11 +643,11 @@ TEST(HttpStreamParser, SentBytesChunkedPostError) {
&response, callback.callback()));
base::RunLoop().RunUntilIdle();
- upload_data_stream.AppendData(kChunk, base::size(kChunk) - 1, false);
+ upload_data_stream.AppendData(kChunk, std::size(kChunk) - 1, false);
base::RunLoop().RunUntilIdle();
// This write should fail.
- upload_data_stream.AppendData(kChunk, base::size(kChunk) - 1, false);
+ upload_data_stream.AppendData(kChunk, std::size(kChunk) - 1, false);
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FAILED));
EXPECT_EQ(CountWriteBytes(writes), parser.sent_bytes());
@@ -720,7 +719,7 @@ TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
ASSERT_FALSE(callback.have_result());
// Now append the only chunk and wait for the callback.
- upload_stream.AppendData(kChunk, base::size(kChunk) - 1, true);
+ upload_stream.AppendData(kChunk, std::size(kChunk) - 1, true);
ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
@@ -772,7 +771,7 @@ TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
NetLogWithSource()),
IsOk());
// Append the only chunk.
- upload_stream.AppendData(kChunk, base::size(kChunk) - 1, true);
+ upload_stream.AppendData(kChunk, std::size(kChunk) - 1, true);
SequencedSocketData data(reads, writes);
std::unique_ptr<StreamSocket> stream_socket = CreateConnectedSocket(&data);
@@ -853,7 +852,7 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
};
ChunkedUploadDataStream upload_stream(0);
- upload_stream.AppendData(kChunk1, base::size(kChunk1) - 1, false);
+ upload_stream.AppendData(kChunk1, std::size(kChunk1) - 1, false);
ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
NetLogWithSource()),
IsOk());
@@ -889,12 +888,12 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
ASSERT_FALSE(callback.have_result());
// Now append another chunk.
- upload_stream.AppendData(kChunk2, base::size(kChunk2) - 1, false);
+ upload_stream.AppendData(kChunk2, std::size(kChunk2) - 1, false);
ASSERT_FALSE(callback.have_result());
// Add the final chunk, while the write for the second is still pending,
// which should not confuse the state machine.
- upload_stream.AppendData(kChunk3, base::size(kChunk3) - 1, true);
+ upload_stream.AppendData(kChunk3, std::size(kChunk3) - 1, true);
ASSERT_FALSE(callback.have_result());
// Wait for writes to complete.
@@ -1123,7 +1122,7 @@ TEST(HttpStreamParser, TruncatedHeaders) {
for (size_t protocol = 0; protocol < NUM_PROTOCOLS; protocol++) {
SCOPED_TRACE(protocol);
- for (size_t i = 0; i < base::size(reads); i++) {
+ for (size_t i = 0; i < std::size(reads); i++) {
SCOPED_TRACE(i);
SequencedSocketData data(reads[i], writes);
std::unique_ptr<StreamSocket> stream_socket(CreateConnectedSocket(&data));
@@ -1152,7 +1151,7 @@ TEST(HttpStreamParser, TruncatedHeaders) {
int rv = parser.ReadResponseHeaders(callback.callback());
EXPECT_EQ(CountWriteBytes(writes), parser.sent_bytes());
- if (i == base::size(reads) - 1) {
+ if (i == std::size(reads) - 1) {
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(response_info.headers.get());
EXPECT_EQ(CountReadBytes(reads[i]), parser.received_bytes());
@@ -1430,7 +1429,7 @@ TEST(HttpStreamParser, NullFails) {
// Need to start at 4 because HttpStreamParser will treat the response as
// HTTP/0.9 if it doesn't see "HTTP", and need to end at -1 because "\r\n\r"
// is currently treated as a valid end of header marker.
- for (size_t i = 4; i < base::size(kTestHeaders) - 1; ++i) {
+ for (size_t i = 4; i < std::size(kTestHeaders) - 1; ++i) {
std::string read_data(kTestHeaders);
read_data.insert(i, 1, '\0');
read_data.append("body");
diff --git a/chromium/net/http/http_transaction.h b/chromium/net/http/http_transaction.h
index f575e1dc4c1..58e46c5123e 100644
--- a/chromium/net/http/http_transaction.h
+++ b/chromium/net/http/http_transaction.h
@@ -205,7 +205,7 @@ class NET_EXPORT_PRIVATE HttpTransaction {
// Resumes the transaction after being deferred.
virtual int ResumeNetworkStart() = 0;
- virtual void GetConnectionAttempts(ConnectionAttempts* out) const = 0;
+ virtual ConnectionAttempts GetConnectionAttempts() const = 0;
// Configures the transaction to close the network connection, if any, on
// destruction. Intended for cases where keeping the socket alive may leak
diff --git a/chromium/net/http/http_transaction_test_util.cc b/chromium/net/http/http_transaction_test_util.cc
index 5c45e141607..6c750250382 100644
--- a/chromium/net/http/http_transaction_test_util.cc
+++ b/chromium/net/http/http_transaction_test_util.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/cxx17_backports.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
@@ -181,7 +180,7 @@ const MockTransaction* FindMockTransaction(const GURL& url) {
return it->second;
// look for builtins:
- for (size_t i = 0; i < base::size(kBuiltinMockTransactions); ++i) {
+ for (size_t i = 0; i < std::size(kBuiltinMockTransactions); ++i) {
if (url == GURL(kBuiltinMockTransactions[i]->url))
return kBuiltinMockTransactions[i];
}
@@ -512,6 +511,7 @@ int MockNetworkTransaction::StartInternal(const HttpRequestInfo* request,
response_.was_cached = false;
response_.network_accessed = true;
+ response_.remote_endpoint = t->transport_info.endpoint;
response_.response_time = transaction_factory_->Now();
if (!t->response_time.is_null())
@@ -575,9 +575,9 @@ int MockNetworkTransaction::ResumeNetworkStart() {
return ERR_IO_PENDING;
}
-void MockNetworkTransaction::GetConnectionAttempts(
- ConnectionAttempts* out) const {
+ConnectionAttempts MockNetworkTransaction::GetConnectionAttempts() const {
NOTIMPLEMENTED();
+ return {};
}
void MockNetworkTransaction::CloseConnectionOnDestruction() {
diff --git a/chromium/net/http/http_transaction_test_util.h b/chromium/net/http/http_transaction_test_util.h
index c68a375b70e..18e015452d9 100644
--- a/chromium/net/http/http_transaction_test_util.h
+++ b/chromium/net/http/http_transaction_test_util.h
@@ -18,6 +18,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
#include "net/base/completion_once_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
@@ -250,7 +251,7 @@ class MockNetworkTransaction
int ResumeNetworkStart() override;
- void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ ConnectionAttempts GetConnectionAttempts() const override;
void CloseConnectionOnDestruction() override;
diff --git a/chromium/net/http/http_util.cc b/chromium/net/http/http_util.cc
index 32948a3b469..0978147da37 100644
--- a/chromium/net/http/http_util.cc
+++ b/chromium/net/http/http_util.cc
@@ -23,6 +23,7 @@
#include "net/base/mime_util.h"
#include "net/base/parse_number.h"
#include "net/base/url_util.h"
+#include "net/http/http_response_headers.h"
namespace net {
@@ -1122,4 +1123,21 @@ bool HttpUtil::ParseContentEncoding(const std::string& content_encoding,
return true;
}
+bool HttpUtil::HeadersContainMultipleCopiesOfField(
+ const HttpResponseHeaders& headers,
+ const std::string& field_name) {
+ size_t it = 0;
+ std::string field_value;
+ if (!headers.EnumerateHeader(&it, field_name, &field_value))
+ return false;
+ // There's at least one `field_name` header. Check if there are any more
+ // such headers, and if so, return true if they have different values.
+ std::string field_value2;
+ while (headers.EnumerateHeader(&it, field_name, &field_value2)) {
+ if (field_value != field_value2)
+ return true;
+ }
+ return false;
+}
+
} // namespace net
diff --git a/chromium/net/http/http_util.h b/chromium/net/http/http_util.h
index 7494ae8a8b8..65f64279020 100644
--- a/chromium/net/http/http_util.h
+++ b/chromium/net/http/http_util.h
@@ -29,6 +29,8 @@
namespace net {
+class HttpResponseHeaders;
+
class NET_EXPORT HttpUtil {
public:
// Returns the absolute URL, to be used for the http request. This url is
@@ -260,6 +262,12 @@ class NET_EXPORT HttpUtil {
static bool ParseContentEncoding(const std::string& content_encoding,
std::set<std::string>* used_encodings);
+ // Return true if `headers` contain multiple `field_name` fields with
+ // different values.
+ static bool HeadersContainMultipleCopiesOfField(
+ const HttpResponseHeaders& headers,
+ const std::string& field_name);
+
// Used to iterate over the name/value pairs of HTTP headers. To iterate
// over the values in a multi-value header, use ValuesIterator.
// See AssembleRawHeaders for joining line continuations (this iterator
diff --git a/chromium/net/http/http_util_unittest.cc b/chromium/net/http/http_util_unittest.cc
index 7ba495f988c..5072a7cbfee 100644
--- a/chromium/net/http/http_util_unittest.cc
+++ b/chromium/net/http/http_util_unittest.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/http/http_util.h"
+
#include <algorithm>
#include <limits>
-#include "base/cxx17_backports.h"
#include "base/strings/string_util.h"
-#include "net/http/http_util.h"
+#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -44,7 +45,7 @@ TEST(HttpUtilTest, IsSafeHeader) {
"user-agent",
"via",
};
- for (size_t i = 0; i < base::size(unsafe_headers); ++i) {
+ for (size_t i = 0; i < std::size(unsafe_headers); ++i) {
EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i]))
<< unsafe_headers[i];
EXPECT_FALSE(HttpUtil::IsSafeHeader(base::ToUpperASCII(unsafe_headers[i])))
@@ -91,7 +92,7 @@ TEST(HttpUtilTest, IsSafeHeader) {
"user_agent",
"viaa",
};
- for (size_t i = 0; i < base::size(safe_headers); ++i) {
+ for (size_t i = 0; i < std::size(safe_headers); ++i) {
EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i];
EXPECT_TRUE(HttpUtil::IsSafeHeader(base::ToUpperASCII(safe_headers[i])))
<< safe_headers[i];
@@ -338,7 +339,7 @@ TEST(HttpUtilTest, LocateEndOfHeaders) {
{"foo\nbar\n\r\njunk", 10},
{"foo\nbar\r\n\njunk", 10},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
size_t input_len = strlen(tests[i].input);
size_t eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len);
EXPECT_EQ(tests[i].expected_result, eoh);
@@ -362,7 +363,7 @@ TEST(HttpUtilTest, LocateEndOfAdditionalHeaders) {
{"foo\nbar\n\r\njunk", 10},
{"foo\nbar\r\n\njunk", 10},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
size_t input_len = strlen(tests[i].input);
size_t eoh =
HttpUtil::LocateEndOfAdditionalHeaders(tests[i].input, input_len);
@@ -685,7 +686,7 @@ TEST(HttpUtilTest, AssembleRawHeaders) {
},
};
// clang-format on
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string input = tests[i].input;
std::replace(input.begin(), input.end(), '|', '\0');
std::string raw = HttpUtil::AssembleRawHeaders(input);
@@ -725,7 +726,7 @@ TEST(HttpUtilTest, RequestUrlSanitize) {
"wss://www.google.com:78/foobar?query=1",
}
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
SCOPED_TRACE(i);
GURL url(GURL(tests[i].url));
@@ -989,7 +990,7 @@ TEST(HttpUtilTest, ParseContentType) {
// TODO(abarth): Add more interesting test cases.
};
// clang-format on
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string mime_type;
std::string charset;
bool had_charset = false;
@@ -1097,7 +1098,7 @@ TEST(HttpUtilTest, ParseRetryAfterHeader) {
{"Thu, 1 Jan 2015 12:34:56 GMT", true, later - now},
{"Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta()}};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
base::TimeDelta retry_after;
bool return_value = HttpUtil::ParseRetryAfterHeader(
tests[i].retry_after_string, now, &retry_after);
@@ -1593,7 +1594,7 @@ TEST(HttpUtilTest, ParseAcceptEncoding) {
{"foo,\"bar\"", "INVALID"},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string value(tests[i].value);
std::string reformatted;
std::set<std::string> allowed_encodings;
@@ -1623,7 +1624,7 @@ TEST(HttpUtilTest, ParseContentEncoding) {
{"foo,\"bar\"", "INVALID"},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
std::string value(tests[i].value);
std::string reformatted;
std::set<std::string> used_encodings;
diff --git a/chromium/net/http/http_vary_data_unittest.cc b/chromium/net/http/http_vary_data_unittest.cc
index 491454b9361..0b11adf91f6 100644
--- a/chromium/net/http/http_vary_data_unittest.cc
+++ b/chromium/net/http/http_vary_data_unittest.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/http/http_vary_data.h"
+
#include <algorithm>
-#include "base/cxx17_backports.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
-#include "net/http/http_vary_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -15,19 +15,21 @@ namespace net {
namespace {
typedef testing::Test HttpVaryDataTest;
+using ExtraHeaders = std::vector<std::pair<std::string, std::string>>;
struct TestTransaction {
HttpRequestInfo request;
scoped_refptr<HttpResponseHeaders> response;
- void Init(const std::string& request_headers,
+ void Init(const ExtraHeaders& request_headers,
const std::string& response_headers) {
std::string temp(response_headers);
std::replace(temp.begin(), temp.end(), '\n', '\0');
response = new HttpResponseHeaders(temp);
request.extra_headers.Clear();
- request.extra_headers.AddHeadersFromString(request_headers);
+ for (const auto& [key, value] : request_headers)
+ request.extra_headers.SetHeader(key, value);
}
};
@@ -44,9 +46,9 @@ TEST(HttpVaryDataTest, IsInvalid) {
const bool kExpectedValid[] = {false, true, true, true};
- for (size_t i = 0; i < base::size(kTestResponses); ++i) {
+ for (size_t i = 0; i < std::size(kTestResponses); ++i) {
TestTransaction t;
- t.Init(std::string(), kTestResponses[i]);
+ t.Init(/*request_headers=*/{}, kTestResponses[i]);
HttpVaryData v;
EXPECT_FALSE(v.is_valid());
@@ -60,23 +62,23 @@ TEST(HttpVaryDataTest, MultipleInit) {
// Init to something valid.
TestTransaction t1;
- t1.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
+ t1.Init({{"Foo", "1"}, {"bar", "23"}}, "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
EXPECT_TRUE(v.Init(t1.request, *t1.response.get()));
EXPECT_TRUE(v.is_valid());
// Now overwrite by initializing to something invalid.
TestTransaction t2;
- t2.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\n\n");
+ t2.Init({{"Foo", "1"}, {"bar", "23"}}, "HTTP/1.1 200 OK\n\n");
EXPECT_FALSE(v.Init(t2.request, *t2.response.get()));
EXPECT_FALSE(v.is_valid());
}
TEST(HttpVaryDataTest, DoesVary) {
TestTransaction a;
- a.Init("Foo: 1", "HTTP/1.1 200 OK\nVary: foo\n\n");
+ a.Init({{"Foo", "1"}}, "HTTP/1.1 200 OK\nVary: foo\n\n");
TestTransaction b;
- b.Init("Foo: 2", "HTTP/1.1 200 OK\nVary: foo\n\n");
+ b.Init({{"Foo", "2"}}, "HTTP/1.1 200 OK\nVary: foo\n\n");
HttpVaryData v;
EXPECT_TRUE(v.Init(a.request, *a.response.get()));
@@ -86,10 +88,10 @@ TEST(HttpVaryDataTest, DoesVary) {
TEST(HttpVaryDataTest, DoesVary2) {
TestTransaction a;
- a.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
+ a.Init({{"Foo", "1"}, {"bar", "23"}}, "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
TestTransaction b;
- b.Init("Foo: 12\r\nbar: 3", "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
+ b.Init({{"Foo", "12"}, {"bar", "3"}}, "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
HttpVaryData v;
EXPECT_TRUE(v.Init(a.request, *a.response.get()));
@@ -99,7 +101,7 @@ TEST(HttpVaryDataTest, DoesVary2) {
TEST(HttpVaryDataTest, DoesVaryStar) {
// Vary: * varies even when headers are identical
- const char kRequestHeaders[] = "Foo:1";
+ const ExtraHeaders kRequestHeaders = {{"Foo", "1"}};
const char kResponse[] = "HTTP/1.1 200 OK\nVary: *\n\n";
TestTransaction a;
@@ -116,10 +118,10 @@ TEST(HttpVaryDataTest, DoesVaryStar) {
TEST(HttpVaryDataTest, DoesntVary) {
TestTransaction a;
- a.Init("Foo: 1", "HTTP/1.1 200 OK\nVary: foo\n\n");
+ a.Init({{"Foo", "1"}}, "HTTP/1.1 200 OK\nVary: foo\n\n");
TestTransaction b;
- b.Init("Foo: 1", "HTTP/1.1 200 OK\nVary: foo\n\n");
+ b.Init({{"Foo", "1"}}, "HTTP/1.1 200 OK\nVary: foo\n\n");
HttpVaryData v;
EXPECT_TRUE(v.Init(a.request, *a.response.get()));
@@ -129,10 +131,11 @@ TEST(HttpVaryDataTest, DoesntVary) {
TEST(HttpVaryDataTest, DoesntVary2) {
TestTransaction a;
- a.Init("Foo: 1\r\nbAr: 2", "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
+ a.Init({{"Foo", "1"}, {"bAr", "2"}}, "HTTP/1.1 200 OK\nVary: foo, bar\n\n");
TestTransaction b;
- b.Init("Foo: 1\r\nbaR: 2", "HTTP/1.1 200 OK\nVary: foo\nVary: bar\n\n");
+ b.Init({{"Foo", "1"}, {"baR", "2"}},
+ "HTTP/1.1 200 OK\nVary: foo\nVary: bar\n\n");
HttpVaryData v;
EXPECT_TRUE(v.Init(a.request, *a.response.get()));
@@ -142,7 +145,7 @@ TEST(HttpVaryDataTest, DoesntVary2) {
TEST(HttpVaryDataTest, DoesntVaryByCookieForRedirect) {
TestTransaction a;
- a.Init("Cookie: 1", "HTTP/1.1 301 Moved\nLocation: x\n\n");
+ a.Init({{"Cookie", "1"}}, "HTTP/1.1 301 Moved\nLocation: x\n\n");
HttpVaryData v;
EXPECT_FALSE(v.Init(a.request, *a.response.get()));
diff --git a/chromium/net/http/mock_http_cache.cc b/chromium/net/http/mock_http_cache.cc
index 1ceb20fdc76..7a4eea72f62 100644
--- a/chromium/net/http/mock_http_cache.cc
+++ b/chromium/net/http/mock_http_cache.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/location.h"
diff --git a/chromium/net/http/mock_sspi_library_win.cc b/chromium/net/http/mock_sspi_library_win.cc
index c5b5fb025ef..a6cb1b7087f 100644
--- a/chromium/net/http/mock_sspi_library_win.cc
+++ b/chromium/net/http/mock_sspi_library_win.cc
@@ -11,6 +11,7 @@
#include "base/check_op.h"
#include "base/memory/raw_ptr.h"
+#include "base/strings/string_util_win.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
diff --git a/chromium/net/http/structured_headers.cc b/chromium/net/http/structured_headers.cc
index 21bf17861c1..58953d7ee4a 100644
--- a/chromium/net/http/structured_headers.cc
+++ b/chromium/net/http/structured_headers.cc
@@ -28,19 +28,19 @@ namespace {
#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://tools.ietf.org/html/draft-ietf-httpbis-header-structure-15#section-3.3.4
-constexpr char kTokenChars15[] = TCHAR ":/";
+// 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://tools.ietf.org/html/draft-ietf-httpbis-header-structure-15#section-3.1.2
-constexpr char kKeyChars15[] = 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://tools.ietf.org/html/draft-ietf-httpbis-header-structure-15#section-3.3.1
+// 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;
@@ -51,21 +51,22 @@ constexpr int64_t kMinInteger = -999'999'999'999'999L;
constexpr double kTooLargeDecimal = 1e12 - 0.0005;
// Parser for (a subset of) Structured Headers for HTTP defined in [SH09] and
-// [SH15]. [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.
+// [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
-// [SH15] https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-15
+// [RFC8941] https://www.rfc-editor.org/rfc/rfc8941.html
class StructuredHeaderParser {
public:
enum DraftVersion {
kDraft09,
- kDraft15,
+ kFinal,
};
explicit StructuredHeaderParser(base::StringPiece str, DraftVersion version)
: input_(str), version_(version) {
// [SH09] 4.2 Step 1.
- // [SH15] 4.2 Step 2.
// 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;
@@ -74,10 +75,12 @@ class StructuredHeaderParser {
// Callers should call this after ReadSomething(), to check if parser has
// consumed all the input successfully.
bool FinishParsing() {
- // [SH09] 4.2 Step 7. [SH15] 4.2 Step 6.
+ // [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. [SH15] 4.2 Step 7.
+ // [SH09] 4.2 Step 8. [RFC8941] 4.2 Step 7.
// If input_string is not empty, fail parsing.
return input_.empty();
}
@@ -107,28 +110,28 @@ class StructuredHeaderParser {
return result;
}
- // Parses a List ([SH15] 4.2.1).
+ // Parses a List ([RFC8941] 4.2.1).
absl::optional<List> ReadList() {
- DCHECK_EQ(version_, kDraft15);
+ 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));
- SkipWhitespaces();
+ SkipOWS();
if (input_.empty())
break;
if (!ConsumeChar(','))
return absl::nullopt;
- SkipWhitespaces();
+ SkipOWS();
if (input_.empty())
return absl::nullopt;
}
return members;
}
- // Parses an Item ([SH15] 4.2.3).
+ // Parses an Item ([RFC8941] 4.2.3).
absl::optional<ParameterizedItem> ReadItem() {
absl::optional<Item> item = ReadBareItem();
if (!item)
@@ -139,8 +142,8 @@ class StructuredHeaderParser {
return ParameterizedItem(std::move(*item), std::move(*parameters));
}
- // Parses a bare Item ([SH15] 4.2.3.1, though this is also the algorithm for
- // parsing an Item from [SH09] 4.2.7).
+ // 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";
@@ -154,7 +157,7 @@ class StructuredHeaderParser {
return ReadByteSequence();
return ReadToken();
case ':':
- if (version_ == kDraft15)
+ if (version_ == kFinal)
return ReadByteSequence();
return absl::nullopt;
case '?':
@@ -168,9 +171,9 @@ class StructuredHeaderParser {
}
}
- // Parses a Dictionary ([SH15] 4.2.2).
+ // Parses a Dictionary ([RFC8941] 4.2.2).
absl::optional<Dictionary> ReadDictionary() {
- DCHECK_EQ(version_, kDraft15);
+ DCHECK_EQ(version_, kFinal);
Dictionary members;
while (!input_.empty()) {
absl::optional<std::string> key(ReadKey());
@@ -189,12 +192,12 @@ class StructuredHeaderParser {
member = ParameterizedMember{Item(true), std::move(*parameters)};
}
members[*key] = std::move(*member);
- SkipWhitespaces();
+ SkipOWS();
if (input_.empty())
break;
if (!ConsumeChar(','))
return absl::nullopt;
- SkipWhitespaces();
+ SkipOWS();
if (input_.empty())
return absl::nullopt;
}
@@ -254,9 +257,9 @@ class StructuredHeaderParser {
std::move(parameters));
}
- // Parses an Item or Inner List ([SH15] 4.2.1.1).
+ // Parses an Item or Inner List ([RFC8941] 4.2.1.1).
absl::optional<ParameterizedMember> ReadItemOrInnerList() {
- DCHECK_EQ(version_, kDraft15);
+ DCHECK_EQ(version_, kFinal);
std::vector<Item> member;
bool member_is_inner_list = (!input_.empty() && input_.front() == '(');
if (member_is_inner_list) {
@@ -270,7 +273,7 @@ class StructuredHeaderParser {
}
}
- // Parses Parameters ([SH15] 4.2.3.2)
+ // Parses Parameters ([RFC8941] 4.2.3.2)
absl::optional<Parameters> ReadParameters() {
Parameters parameters;
base::flat_set<std::string> keys;
@@ -304,9 +307,9 @@ class StructuredHeaderParser {
return parameters;
}
- // Parses an Inner List ([SH15] 4.2.1.2).
+ // Parses an Inner List ([RFC8941] 4.2.1.2).
absl::optional<ParameterizedMember> ReadInnerList() {
- DCHECK_EQ(version_, kDraft15);
+ DCHECK_EQ(version_, kFinal);
if (!ConsumeChar('('))
return absl::nullopt;
std::vector<ParameterizedItem> inner_list;
@@ -331,7 +334,7 @@ class StructuredHeaderParser {
return absl::nullopt;
}
- // Parses a Key ([SH09] 4.2.2, [SH15] 4.2.3.3).
+ // 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())) {
@@ -346,7 +349,7 @@ class StructuredHeaderParser {
}
}
const char* allowed_chars =
- (version_ == kDraft09 ? kKeyChars09 : kKeyChars15);
+ (version_ == kDraft09 ? kKeyChars09 : kKeyChars);
size_t len = input_.find_first_not_of(allowed_chars);
if (len == base::StringPiece::npos)
len = input_.size();
@@ -355,7 +358,7 @@ class StructuredHeaderParser {
return key;
}
- // Parses a Token ([SH09] 4.2.10, [SH15] 4.2.6).
+ // Parses a Token ([SH09] 4.2.10, [RFC8941] 4.2.6).
absl::optional<Item> ReadToken() {
if (input_.empty() ||
!(base::IsAsciiAlpha(input_.front()) || input_.front() == '*')) {
@@ -363,7 +366,7 @@ class StructuredHeaderParser {
return absl::nullopt;
}
size_t len = input_.find_first_not_of(version_ == kDraft09 ? kTokenChars09
- : kTokenChars15);
+ : kTokenChars);
if (len == base::StringPiece::npos)
len = input_.size();
std::string token(input_.substr(0, len));
@@ -371,7 +374,7 @@ class StructuredHeaderParser {
return Item(std::move(token), Item::kTokenType);
}
- // Parses a Number ([SH09] 4.2.8, [SH15] 4.2.4).
+ // Parses a Number ([SH09] 4.2.8, [RFC8941] 4.2.4).
absl::optional<Item> ReadNumber() {
bool is_negative = ConsumeChar('-');
bool is_decimal = false;
@@ -391,21 +394,21 @@ class StructuredHeaderParser {
return absl::nullopt;
}
if (!is_decimal) {
- // [SH15] restricts the range of integers further.
- if (version_ == kDraft15 && i > 15) {
+ // [RFC8941] restricts the range of integers further.
+ if (version_ == kFinal && i > 15) {
LogParseError("ReadNumber", "integer too long");
return absl::nullopt;
}
} else {
- if (version_ != kDraft15 && i > 16) {
+ if (version_ != kFinal && i > 16) {
LogParseError("ReadNumber", "float too long");
return absl::nullopt;
}
- if (version_ == kDraft15 && decimal_position > 12) {
+ if (version_ == kFinal && decimal_position > 12) {
LogParseError("ReadNumber", "decimal too long");
return absl::nullopt;
}
- if (i - decimal_position > (version_ == kDraft15 ? 4 : 7)) {
+ if (i - decimal_position > (version_ == kFinal ? 4 : 7)) {
LogParseError("ReadNumber", "too many digits after decimal");
return absl::nullopt;
}
@@ -430,12 +433,12 @@ class StructuredHeaderParser {
int64_t n;
if (!base::StringToInt64(output_number_string, &n))
return absl::nullopt;
- DCHECK(version_ != kDraft15 || (n <= kMaxInteger && n >= kMinInteger));
+ DCHECK(version_ != kFinal || (n <= kMaxInteger && n >= kMinInteger));
return Item(is_negative ? -n : n);
}
}
- // Parses a String ([SH09] 4.2.9, [SH15] 4.2.5).
+ // Parses a String ([SH09] 4.2.9, [RFC8941] 4.2.5).
absl::optional<Item> ReadString() {
std::string s;
if (!ConsumeChar('"')) {
@@ -474,7 +477,7 @@ class StructuredHeaderParser {
return s;
}
- // Parses a Byte Sequence ([SH09] 4.2.11, [SH15] 4.2.7).
+ // Parses a Byte Sequence ([SH09] 4.2.11, [RFC8941] 4.2.7).
absl::optional<Item> ReadByteSequence() {
char delimiter = (version_ == kDraft09 ? '*' : ':');
if (!ConsumeChar(delimiter)) {
@@ -500,7 +503,7 @@ class StructuredHeaderParser {
return Item(std::move(binary), Item::kByteSequenceType);
}
- // Parses a Boolean ([SH15] 4.2.8).
+ // 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() {
@@ -517,6 +520,9 @@ class StructuredHeaderParser {
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_ =
@@ -527,6 +533,11 @@ class StructuredHeaderParser {
}
}
+ 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);
@@ -545,8 +556,8 @@ class StructuredHeaderParser {
DraftVersion version_;
};
-// Serializer for (a subset of) Structured Headers for HTTP defined in [SH15].
-// [SH15] https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-15
+// 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;
@@ -557,7 +568,7 @@ class StructuredHeaderSerializer {
std::string Output() { return output_.str(); }
- // Serializes a List ([SH15] 4.1.1).
+ // Serializes a List ([RFC8941] 4.1.1).
bool WriteList(const List& value) {
bool first = true;
for (const auto& member : value) {
@@ -570,17 +581,17 @@ class StructuredHeaderSerializer {
return true;
}
- // Serializes an Item ([SH15] 4.1.3).
+ // 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 ([SH15] 4.1.3).
+ // Serializes an Item ([RFC8941] 4.1.3).
bool WriteBareItem(const Item& value) {
if (value.is_string()) {
- // Serializes a String ([SH15] 4.1.6).
+ // Serializes a String ([RFC8941] 4.1.6).
output_ << "\"";
for (const char& c : value.GetString()) {
if (!base::IsAsciiPrintable(c))
@@ -593,19 +604,18 @@ class StructuredHeaderSerializer {
return true;
}
if (value.is_token()) {
- // Serializes a Token ([SH15] 4.1.7).
+ // 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(kTokenChars15) !=
- std::string::npos)
+ 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 ([SH15] 4.1.8).
+ // Serializes a Byte Sequence ([RFC8941] 4.1.8).
output_ << ":";
output_ << base::Base64Encode(
base::as_bytes(base::make_span(value.GetString())));
@@ -613,14 +623,14 @@ class StructuredHeaderSerializer {
return true;
}
if (value.is_integer()) {
- // Serializes an Integer ([SH15] 4.1.4).
+ // 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 ([SH15] 4.1.5).
+ // Serializes a Decimal ([RFC8941] 4.1.5).
double decimal_value = value.GetDecimal();
if (!std::isfinite(decimal_value) ||
fabs(decimal_value) >= kTooLargeDecimal)
@@ -650,7 +660,7 @@ class StructuredHeaderSerializer {
// Maximum is 12 integer digits, one decimal point, three fractional
// digits, and a null terminator.
char buffer[17];
- base::snprintf(buffer, base::size(buffer), "%#.3f", decimal_value);
+ 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
@@ -663,14 +673,14 @@ class StructuredHeaderSerializer {
return true;
}
if (value.is_boolean()) {
- // Serializes a Boolean ([SH15] 4.1.9).
+ // Serializes a Boolean ([RFC8941] 4.1.9).
output_ << (value.GetBoolean() ? "?1" : "?0");
return true;
}
return false;
}
- // Serializes a Dictionary ([SH15] 4.1.2).
+ // Serializes a Dictionary ([RFC8941] 4.1.2).
bool WriteDictionary(const Dictionary& value) {
bool first = true;
for (const auto& dict : value) {
@@ -696,7 +706,7 @@ class StructuredHeaderSerializer {
private:
bool WriteParameterizedMember(const ParameterizedMember& value) {
- // Serializes a parameterized member ([SH15] 4.1.1).
+ // Serializes a parameterized member ([RFC8941] 4.1.1).
if (value.member_is_inner_list) {
if (!WriteInnerList(value.member))
return false;
@@ -709,7 +719,7 @@ class StructuredHeaderSerializer {
}
bool WriteInnerList(const std::vector<ParameterizedItem>& value) {
- // Serializes an inner list ([SH15] 4.1.1.1).
+ // Serializes an inner list ([RFC8941] 4.1.1.1).
output_ << "(";
bool first = true;
for (const ParameterizedItem& member : value) {
@@ -724,7 +734,7 @@ class StructuredHeaderSerializer {
}
bool WriteParameters(const Parameters& value) {
- // Serializes a parameter list ([SH15] 4.1.1.2).
+ // 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;
@@ -743,10 +753,10 @@ class StructuredHeaderSerializer {
}
bool WriteKey(const std::string& value) {
- // Serializes a Key ([SH15] 4.1.1.3).
+ // Serializes a Key ([RFC8941] 4.1.1.3).
if (!value.size())
return false;
- if (value.find_first_not_of(kKeyChars15) != std::string::npos)
+ if (value.find_first_not_of(kKeyChars) != std::string::npos)
return false;
if (!base::IsAsciiLower(value[0]) && value[0] != '*')
return false;
@@ -894,7 +904,7 @@ bool Dictionary::contains(base::StringPiece key) const {
}
absl::optional<ParameterizedItem> ParseItem(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft15);
+ StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
absl::optional<ParameterizedItem> item = parser.ReadItem();
if (item && parser.FinishParsing())
return item;
@@ -902,7 +912,7 @@ absl::optional<ParameterizedItem> ParseItem(base::StringPiece str) {
}
absl::optional<Item> ParseBareItem(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft15);
+ StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
absl::optional<Item> item = parser.ReadBareItem();
if (item && parser.FinishParsing())
return item;
@@ -927,7 +937,7 @@ absl::optional<ListOfLists> ParseListOfLists(base::StringPiece str) {
}
absl::optional<List> ParseList(base::StringPiece str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft15);
+ StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
absl::optional<List> list = parser.ReadList();
if (list && parser.FinishParsing())
return list;
@@ -935,7 +945,7 @@ absl::optional<List> ParseList(base::StringPiece str) {
}
absl::optional<Dictionary> ParseDictionary(const base::StringPiece& str) {
- StructuredHeaderParser parser(str, StructuredHeaderParser::kDraft15);
+ StructuredHeaderParser parser(str, StructuredHeaderParser::kFinal);
absl::optional<Dictionary> dictionary = parser.ReadDictionary();
if (dictionary && parser.FinishParsing())
return dictionary;
diff --git a/chromium/net/http/structured_headers.h b/chromium/net/http/structured_headers.h
index 5292f018e3b..262724694a9 100644
--- a/chromium/net/http/structured_headers.h
+++ b/chromium/net/http/structured_headers.h
@@ -19,14 +19,19 @@ namespace net {
namespace structured_headers {
// This file implements parsing of HTTP structured headers, as defined in
-// https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html.
+// 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/)
//
-// Both drafts 9 and 15 are currently supported. The major difference
-// between the two drafts is in the various list formats: Draft 9 describes
-// Parameterised lists and lists-of-lists, while draft 15 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.
+// 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:
diff --git a/chromium/net/http/structured_headers_generated_unittest.cc b/chromium/net/http/structured_headers_generated_unittest.cc
index f2250839902..82d1e01205f 100644
--- a/chromium/net/http/structured_headers_generated_unittest.cc
+++ b/chromium/net/http/structured_headers_generated_unittest.cc
@@ -13,14 +13,14 @@
// 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-header-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
+// 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 2020-04-10 from structured-header-tests.git @
-// 0a8ab1b649080239abb21ecd3ca15a4aead419aa
+// Generated on 2022-03-05 from structured-field-tests.git @
+// 4d33b9c2f4e0a7d7d1d733ccf48783aaead8ca4d
namespace net {
namespace structured_headers {
@@ -129,8 +129,8 @@ const struct ParameterizedItemTestCase {
{"Example-BoolHdr", "?1", 2, {{Item(true), {}}}},
// item.json
{"empty item", "", 0, absl::nullopt},
- {"leading space", " 1", 3, {{Integer(1), {}}}, "1"},
- {"trailing space", "1 ", 3, {{Integer(1), {}}}, "1"},
+ {"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
@@ -836,7 +836,6 @@ const struct ParameterizedItemTestCase {
// number.json
{"basic integer", "42", 2, {{Integer(42), {}}}},
{"zero integer", "0", 1, {{Integer(0), {}}}},
- {"leading 0 zero", "00", 2, {{Integer(0), {}}}, "0"},
{"negative zero", "-0", 2, {{Integer(0), {}}}, "0"},
{"double negative zero", "--0", 3, absl::nullopt},
{"negative integer", "-42", 3, {{Integer(-42), {}}}},
@@ -1009,134 +1008,134 @@ const struct ParameterizedItemTestCase {
{"0x7d in string", "\" } \"", 5, {{Item(" } "), {}}}},
{"0x7e in string", "\" ~ \"", 5, {{Item(" ~ "), {}}}},
{"0x7f in string", "\" \177 \"", 5, absl::nullopt},
- {"0x00 in string", "\"\\\000\"", 4, absl::nullopt},
- {"0x01 in string", "\"\\\001\"", 4, absl::nullopt},
- {"0x02 in string", "\"\\\002\"", 4, absl::nullopt},
- {"0x03 in string", "\"\\\003\"", 4, absl::nullopt},
- {"0x04 in string", "\"\\\004\"", 4, absl::nullopt},
- {"0x05 in string", "\"\\\005\"", 4, absl::nullopt},
- {"0x06 in string", "\"\\\006\"", 4, absl::nullopt},
- {"0x07 in string", "\"\\\a\"", 4, absl::nullopt},
- {"0x08 in string", "\"\\\b\"", 4, absl::nullopt},
- {"0x09 in string", "\"\\\t\"", 4, absl::nullopt},
- {"0x0a in string", "\"\\\n\"", 4, absl::nullopt},
- {"0x0b in string", "\"\\\v\"", 4, absl::nullopt},
- {"0x0c in string", "\"\\\f\"", 4, absl::nullopt},
- {"0x0d in string", "\"\\\r\"", 4, absl::nullopt},
- {"0x0e in string", "\"\\\016\"", 4, absl::nullopt},
- {"0x0f in string", "\"\\\017\"", 4, absl::nullopt},
- {"0x10 in string", "\"\\\020\"", 4, absl::nullopt},
- {"0x11 in string", "\"\\\021\"", 4, absl::nullopt},
- {"0x12 in string", "\"\\\022\"", 4, absl::nullopt},
- {"0x13 in string", "\"\\\023\"", 4, absl::nullopt},
- {"0x14 in string", "\"\\\024\"", 4, absl::nullopt},
- {"0x15 in string", "\"\\\025\"", 4, absl::nullopt},
- {"0x16 in string", "\"\\\026\"", 4, absl::nullopt},
- {"0x17 in string", "\"\\\027\"", 4, absl::nullopt},
- {"0x18 in string", "\"\\\030\"", 4, absl::nullopt},
- {"0x19 in string", "\"\\\031\"", 4, absl::nullopt},
- {"0x1a in string", "\"\\\032\"", 4, absl::nullopt},
- {"0x1b in string", "\"\\\033\"", 4, absl::nullopt},
- {"0x1c in string", "\"\\\034\"", 4, absl::nullopt},
- {"0x1d in string", "\"\\\035\"", 4, absl::nullopt},
- {"0x1e in string", "\"\\\036\"", 4, absl::nullopt},
- {"0x1f in string", "\"\\\037\"", 4, absl::nullopt},
- {"0x20 in string", "\"\\ \"", 4, absl::nullopt},
- {"0x21 in string", "\"\\!\"", 4, absl::nullopt},
- {"0x22 in string", "\"\\\"\"", 4, {{Item("\""), {}}}},
- {"0x23 in string", "\"\\#\"", 4, absl::nullopt},
- {"0x24 in string", "\"\\$\"", 4, absl::nullopt},
- {"0x25 in string", "\"\\%\"", 4, absl::nullopt},
- {"0x26 in string", "\"\\&\"", 4, absl::nullopt},
- {"0x27 in string", "\"\\'\"", 4, absl::nullopt},
- {"0x28 in string", "\"\\(\"", 4, absl::nullopt},
- {"0x29 in string", "\"\\)\"", 4, absl::nullopt},
- {"0x2a in string", "\"\\*\"", 4, absl::nullopt},
- {"0x2b in string", "\"\\+\"", 4, absl::nullopt},
- {"0x2c in string", "\"\\,\"", 4, absl::nullopt},
- {"0x2d in string", "\"\\-\"", 4, absl::nullopt},
- {"0x2e in string", "\"\\.\"", 4, absl::nullopt},
- {"0x2f in string", "\"\\/\"", 4, absl::nullopt},
- {"0x30 in string", "\"\\0\"", 4, absl::nullopt},
- {"0x31 in string", "\"\\1\"", 4, absl::nullopt},
- {"0x32 in string", "\"\\2\"", 4, absl::nullopt},
- {"0x33 in string", "\"\\3\"", 4, absl::nullopt},
- {"0x34 in string", "\"\\4\"", 4, absl::nullopt},
- {"0x35 in string", "\"\\5\"", 4, absl::nullopt},
- {"0x36 in string", "\"\\6\"", 4, absl::nullopt},
- {"0x37 in string", "\"\\7\"", 4, absl::nullopt},
- {"0x38 in string", "\"\\8\"", 4, absl::nullopt},
- {"0x39 in string", "\"\\9\"", 4, absl::nullopt},
- {"0x3a in string", "\"\\:\"", 4, absl::nullopt},
- {"0x3b in string", "\"\\;\"", 4, absl::nullopt},
- {"0x3c in string", "\"\\<\"", 4, absl::nullopt},
- {"0x3d in string", "\"\\=\"", 4, absl::nullopt},
- {"0x3e in string", "\"\\>\"", 4, absl::nullopt},
- {"0x3f in string", "\"\\?\"", 4, absl::nullopt},
- {"0x40 in string", "\"\\@\"", 4, absl::nullopt},
- {"0x41 in string", "\"\\A\"", 4, absl::nullopt},
- {"0x42 in string", "\"\\B\"", 4, absl::nullopt},
- {"0x43 in string", "\"\\C\"", 4, absl::nullopt},
- {"0x44 in string", "\"\\D\"", 4, absl::nullopt},
- {"0x45 in string", "\"\\E\"", 4, absl::nullopt},
- {"0x46 in string", "\"\\F\"", 4, absl::nullopt},
- {"0x47 in string", "\"\\G\"", 4, absl::nullopt},
- {"0x48 in string", "\"\\H\"", 4, absl::nullopt},
- {"0x49 in string", "\"\\I\"", 4, absl::nullopt},
- {"0x4a in string", "\"\\J\"", 4, absl::nullopt},
- {"0x4b in string", "\"\\K\"", 4, absl::nullopt},
- {"0x4c in string", "\"\\L\"", 4, absl::nullopt},
- {"0x4d in string", "\"\\M\"", 4, absl::nullopt},
- {"0x4e in string", "\"\\N\"", 4, absl::nullopt},
- {"0x4f in string", "\"\\O\"", 4, absl::nullopt},
- {"0x50 in string", "\"\\P\"", 4, absl::nullopt},
- {"0x51 in string", "\"\\Q\"", 4, absl::nullopt},
- {"0x52 in string", "\"\\R\"", 4, absl::nullopt},
- {"0x53 in string", "\"\\S\"", 4, absl::nullopt},
- {"0x54 in string", "\"\\T\"", 4, absl::nullopt},
- {"0x55 in string", "\"\\U\"", 4, absl::nullopt},
- {"0x56 in string", "\"\\V\"", 4, absl::nullopt},
- {"0x57 in string", "\"\\W\"", 4, absl::nullopt},
- {"0x58 in string", "\"\\X\"", 4, absl::nullopt},
- {"0x59 in string", "\"\\Y\"", 4, absl::nullopt},
- {"0x5a in string", "\"\\Z\"", 4, absl::nullopt},
- {"0x5b in string", "\"\\[\"", 4, absl::nullopt},
- {"0x5c in string", "\"\\\\\"", 4, {{Item("\\"), {}}}},
- {"0x5d in string", "\"\\]\"", 4, absl::nullopt},
- {"0x5e in string", "\"\\^\"", 4, absl::nullopt},
- {"0x5f in string", "\"\\_\"", 4, absl::nullopt},
- {"0x60 in string", "\"\\`\"", 4, absl::nullopt},
- {"0x61 in string", "\"\\a\"", 4, absl::nullopt},
- {"0x62 in string", "\"\\b\"", 4, absl::nullopt},
- {"0x63 in string", "\"\\c\"", 4, absl::nullopt},
- {"0x64 in string", "\"\\d\"", 4, absl::nullopt},
- {"0x65 in string", "\"\\e\"", 4, absl::nullopt},
- {"0x66 in string", "\"\\f\"", 4, absl::nullopt},
- {"0x67 in string", "\"\\g\"", 4, absl::nullopt},
- {"0x68 in string", "\"\\h\"", 4, absl::nullopt},
- {"0x69 in string", "\"\\i\"", 4, absl::nullopt},
- {"0x6a in string", "\"\\j\"", 4, absl::nullopt},
- {"0x6b in string", "\"\\k\"", 4, absl::nullopt},
- {"0x6c in string", "\"\\l\"", 4, absl::nullopt},
- {"0x6d in string", "\"\\m\"", 4, absl::nullopt},
- {"0x6e in string", "\"\\n\"", 4, absl::nullopt},
- {"0x6f in string", "\"\\o\"", 4, absl::nullopt},
- {"0x70 in string", "\"\\p\"", 4, absl::nullopt},
- {"0x71 in string", "\"\\q\"", 4, absl::nullopt},
- {"0x72 in string", "\"\\r\"", 4, absl::nullopt},
- {"0x73 in string", "\"\\s\"", 4, absl::nullopt},
- {"0x74 in string", "\"\\t\"", 4, absl::nullopt},
- {"0x75 in string", "\"\\u\"", 4, absl::nullopt},
- {"0x76 in string", "\"\\v\"", 4, absl::nullopt},
- {"0x77 in string", "\"\\w\"", 4, absl::nullopt},
- {"0x78 in string", "\"\\x\"", 4, absl::nullopt},
- {"0x79 in string", "\"\\y\"", 4, absl::nullopt},
- {"0x7a in string", "\"\\z\"", 4, absl::nullopt},
- {"0x7b in string", "\"\\{\"", 4, absl::nullopt},
- {"0x7c in string", "\"\\|\"", 4, absl::nullopt},
- {"0x7d in string", "\"\\}\"", 4, absl::nullopt},
- {"0x7e in string", "\"\\~\"", 4, absl::nullopt},
- {"0x7f in string", "\"\\\177\"", 4, 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(""), {}}}},
@@ -1453,8 +1452,6 @@ const struct ListTestCase {
// format is identical to raw.
} list_test_cases[] = {
- // dictionary.json
- {"tab separated dictionary", "a=1\t,\tb=2", 9, absl::nullopt},
// examples.json
{"Example-StrListHeader",
"\"foo\", \"bar\", \"It was the best of times.\"",
@@ -2073,7 +2070,11 @@ const struct ListTestCase {
6,
{{{Integer(1), {}}, {Integer(42), {}}}},
"1, 42"},
- {"tab separated list", "1\t,\t42", 6, absl::nullopt},
+ {"tab separated list",
+ "1\t,\t42",
+ 6,
+ {{{Integer(1), {}}, {Integer(42), {}}}},
+ "1, 42"},
{"two line list",
"1, 42",
5,
@@ -2081,6 +2082,7 @@ const struct ListTestCase {
"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)",
@@ -2110,6 +2112,7 @@ const struct ListTestCase {
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\"",
@@ -2167,6 +2170,24 @@ const struct ListTestCase {
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/*",
@@ -2227,6 +2248,11 @@ const struct DictionaryTestCase {
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,
@@ -2325,6 +2351,215 @@ const struct DictionaryTestCase {
{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},
diff --git a/chromium/net/http/structured_headers_unittest.cc b/chromium/net/http/structured_headers_unittest.cc
index 62b53b0c67e..d2848b2b523 100644
--- a/chromium/net/http/structured_headers_unittest.cc
+++ b/chromium/net/http/structured_headers_unittest.cc
@@ -236,7 +236,10 @@ const struct DictionaryTestCase {
"en=\"Applepie\", da=:aGVsbG8=:",
{Dictionary{{{"en", {Item("Applepie"), {}}},
{"da", {Item("hello", Item::kByteSequenceType), {}}}}}}},
- {"tab separated dictionary", "a=1\t,\tb=2", absl::nullopt},
+ {"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), {}}},
diff --git a/chromium/net/http/transport_security_persister.cc b/chromium/net/http/transport_security_persister.cc
index 0554f03cf62..2b3d0dc57d5 100644
--- a/chromium/net/http/transport_security_persister.cc
+++ b/chromium/net/http/transport_security_persister.cc
@@ -9,6 +9,7 @@
#include "base/base64.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc
index 873c2bf85b6..340b2e49df2 100644
--- a/chromium/net/http/transport_security_state.cc
+++ b/chromium/net/http/transport_security_state.cc
@@ -431,9 +431,7 @@ TransportSecurityState::TransportSecurityState(
bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) {
STSState unused_sts;
PKPState unused_pkp;
- return GetDynamicSTSState(host, &unused_sts) ||
- GetDynamicPKPState(host, &unused_pkp) ||
- GetStaticDomainState(host, &unused_sts, &unused_pkp);
+ return GetSTSState(host, &unused_sts) || GetPKPState(host, &unused_pkp);
}
base::Value TransportSecurityState::NetLogUpgradeToSSLParam(
@@ -637,6 +635,29 @@ void TransportSecurityState::SetCTLogListUpdateTime(base::Time update_time) {
ct_log_list_last_update_time_ = update_time;
}
+void TransportSecurityState::UpdatePinList(
+ const std::vector<PinSet>& pinsets,
+ const std::vector<PinSetInfo>& host_pins,
+ base::Time update_time) {
+ pinsets_ = pinsets;
+ key_pins_list_last_update_time_ = update_time;
+ host_pins_ = absl::make_optional(
+ std::map<std::string, std::pair<PinSet const*, bool>>());
+ std::map<std::string, PinSet const*> pinset_names_map;
+ for (const auto& pinset : pinsets_) {
+ pinset_names_map[pinset.name()] = &pinset;
+ }
+ for (const auto& pin : host_pins) {
+ if (!base::Contains(pinset_names_map, pin.pinset_name_)) {
+ // This should never happen, but if the component is bad and missing an
+ // entry, we will ignore that particular pin.
+ continue;
+ }
+ host_pins_.value()[pin.hostname_] = std::make_pair(
+ pinset_names_map[pin.pinset_name_], pin.include_subdomains_);
+ }
+}
+
void TransportSecurityState::AddHSTSInternal(
const std::string& host,
TransportSecurityState::STSState::UpgradeMode upgrade_mode,
@@ -1133,27 +1154,64 @@ TransportSecurityState::CheckPublicKeyPinsImpl(
network_isolation_key, failure_log);
}
-bool TransportSecurityState::GetStaticDomainState(const std::string& host,
- STSState* sts_result,
- PKPState* pkp_result) const {
+bool TransportSecurityState::GetStaticSTSState(const std::string& host,
+ STSState* sts_result) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!IsBuildTimely())
return false;
PreloadResult result;
- if (!DecodeHSTSPreload(host, &result))
- return false;
-
- if (hsts_host_bypass_list_.find(host) == hsts_host_bypass_list_.end() &&
+ if (DecodeHSTSPreload(host, &result) &&
+ hsts_host_bypass_list_.find(host) == hsts_host_bypass_list_.end() &&
result.force_https) {
sts_result->domain = host.substr(result.hostname_offset);
sts_result->include_subdomains = result.sts_include_subdomains;
sts_result->last_observed = base::GetBuildTime();
sts_result->upgrade_mode = STSState::MODE_FORCE_HTTPS;
+ return true;
}
- if (enable_static_pins_ && result.has_pins) {
+ return false;
+}
+
+bool TransportSecurityState::GetStaticPKPState(const std::string& host,
+ PKPState* pkp_result) const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (!enable_static_pins_ || !IsStaticPKPListTimely())
+ return false;
+
+ PreloadResult result;
+ if (host_pins_.has_value()) {
+ auto iter = host_pins_->find(host);
+ if (iter != host_pins_->end()) {
+ pkp_result->domain = host;
+ pkp_result->last_observed = key_pins_list_last_update_time_;
+ pkp_result->include_subdomains = iter->second.second;
+ const PinSet* pinset = iter->second.first;
+ if (!pinset->report_uri().empty()) {
+ pkp_result->report_uri = GURL(pinset->report_uri());
+ }
+ for (auto hash : pinset->static_spki_hashes()) {
+ // If the update is malformed, it's preferable to skip the hash than
+ // crash.
+ if (hash.size() == 32) {
+ AddHash(reinterpret_cast<const char*>(hash.data()),
+ &pkp_result->spki_hashes);
+ }
+ }
+ for (auto hash : pinset->bad_static_spki_hashes()) {
+ // If the update is malformed, it's preferable to skip the hash than
+ // crash.
+ if (hash.size() == 32) {
+ AddHash(reinterpret_cast<const char*>(hash.data()),
+ &pkp_result->bad_spki_hashes);
+ }
+ }
+ return true;
+ }
+ } else if (DecodeHSTSPreload(host, &result) && result.has_pins) {
if (result.pinset_id >= g_hsts_source->pinsets_count)
return false;
@@ -1180,23 +1238,20 @@ bool TransportSecurityState::GetStaticDomainState(const std::string& host,
sha256_hash++;
}
}
+ return true;
}
- return true;
+ return false;
}
bool TransportSecurityState::GetSTSState(const std::string& host,
STSState* result) {
- PKPState unused;
- return GetDynamicSTSState(host, result) ||
- GetStaticDomainState(host, result, &unused);
+ return GetDynamicSTSState(host, result) || GetStaticSTSState(host, result);
}
bool TransportSecurityState::GetPKPState(const std::string& host,
PKPState* result) {
- STSState unused;
- return GetDynamicPKPState(host, result) ||
- GetStaticDomainState(host, &unused, result);
+ return GetDynamicPKPState(host, result) || GetStaticPKPState(host, result);
}
bool TransportSecurityState::GetDynamicSTSState(const std::string& host,
@@ -1380,6 +1435,26 @@ TransportSecurityState::ExpectCTStateIterator::ExpectCTStateIterator(
TransportSecurityState::ExpectCTStateIterator::~ExpectCTStateIterator() =
default;
+TransportSecurityState::PinSet::PinSet(
+ std::string name,
+ std::vector<std::vector<uint8_t>> static_spki_hashes,
+ std::vector<std::vector<uint8_t>> bad_static_spki_hashes,
+ std::string report_uri)
+ : name_(std::move(name)),
+ static_spki_hashes_(std::move(static_spki_hashes)),
+ bad_static_spki_hashes_(std::move(bad_static_spki_hashes)),
+ report_uri_(std::move(report_uri)) {}
+
+TransportSecurityState::PinSet::PinSet(const PinSet& other) = default;
+TransportSecurityState::PinSet::~PinSet() = default;
+
+TransportSecurityState::PinSetInfo::PinSetInfo(std::string hostname,
+ std::string pinset_name,
+ bool include_subdomains)
+ : hostname_(std::move(hostname)),
+ pinset_name_(std::move(pinset_name)),
+ include_subdomains_(std::move(include_subdomains)) {}
+
bool TransportSecurityState::PKPState::CheckPublicKeyPins(
const HashValueVector& hashes,
std::string* failure_log) const {
@@ -1565,4 +1640,16 @@ bool TransportSecurityState::IsCTLogListTimely() const {
70 /* 10 weeks */;
}
+bool TransportSecurityState::IsStaticPKPListTimely() const {
+ // If the list has not been updated via component updater, freshness depends
+ // on build freshness.
+ if (!host_pins_.has_value()) {
+ return IsBuildTimely();
+ }
+ DCHECK(!key_pins_list_last_update_time_.is_null());
+ // Else, we use the last update time.
+ return (base::Time::Now() - key_pins_list_last_update_time_).InDays() <
+ 70 /* 10 weeks */;
+}
+
} // namespace net
diff --git a/chromium/net/http/transport_security_state.h b/chromium/net/http/transport_security_state.h
index 73f539e38c3..e8d50dbf23a 100644
--- a/chromium/net/http/transport_security_state.h
+++ b/chromium/net/http/transport_security_state.h
@@ -25,6 +25,7 @@
#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/http/transport_security_state_source.h"
#include "net/log/net_log_with_source.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace net {
@@ -334,6 +335,41 @@ class NET_EXPORT TransportSecurityState {
virtual ~ExpectCTReporter() {}
};
+ class NET_EXPORT PinSet {
+ public:
+ PinSet(std::string name,
+ std::vector<std::vector<uint8_t>> static_spki_hashes,
+ std::vector<std::vector<uint8_t>> bad_static_spki_hashes,
+ std::string report_uri);
+ PinSet(const PinSet& other);
+ ~PinSet();
+
+ const std::string& name() const { return name_; }
+ const std::vector<std::vector<uint8_t>>& static_spki_hashes() const {
+ return static_spki_hashes_;
+ }
+ const std::vector<std::vector<uint8_t>>& bad_static_spki_hashes() const {
+ return bad_static_spki_hashes_;
+ }
+ const std::string& report_uri() const { return report_uri_; }
+
+ private:
+ std::string name_;
+ std::vector<std::vector<uint8_t>> static_spki_hashes_;
+ std::vector<std::vector<uint8_t>> bad_static_spki_hashes_;
+ std::string report_uri_;
+ };
+
+ struct NET_EXPORT PinSetInfo {
+ std::string hostname_;
+ std::string pinset_name_;
+ bool include_subdomains_;
+
+ PinSetInfo(std::string hostname,
+ std::string pinset_name,
+ bool include_subdomains);
+ };
+
// Indicates whether or not a public key pin check should send a
// report if a violation is detected.
enum PublicKeyPinReportStatus { ENABLE_PIN_REPORTS, DISABLE_PIN_REPORTS };
@@ -451,8 +487,19 @@ class NET_EXPORT TransportSecurityState {
ct_emergency_disable_ = emergency_disable;
}
+ bool is_ct_emergency_disabled_for_testing() const {
+ return ct_emergency_disable_;
+ }
+
void SetCTLogListUpdateTime(base::Time update_time);
+ // |pinsets| should include all known pinsets, |host_pins| the information
+ // related to each hostname's pin, and |update_time| the time at which this
+ // list was known to be up to date.
+ void UpdatePinList(const std::vector<PinSet>& pinsets,
+ const std::vector<PinSetInfo>& host_pins,
+ base::Time update_time);
+
// Clears all dynamic data (e.g. HSTS and HPKP data).
//
// Does NOT persist changes using the Delegate, as this function is only
@@ -503,15 +550,14 @@ class NET_EXPORT TransportSecurityState {
//
// Note that these methods are not const because they opportunistically remove
// entries that have expired.
- bool GetSTSState(const std::string& host, STSState* result);
- bool GetPKPState(const std::string& host, PKPState* result);
+ bool GetSTSState(const std::string& host, STSState* sts_result);
+ bool GetPKPState(const std::string& host, PKPState* pkp_result);
- // Returns true and updates |*sts_result| and/or |*pkp_result| if there is
- // static (built-in) state for |host|. If multiple entries match |host|,
- // the most specific match determines the return value.
- bool GetStaticDomainState(const std::string& host,
- STSState* sts_result,
- PKPState* pkp_result) const;
+ // Returns true and updates |*result| iff |host| has static HSTS/HPKP
+ // (respectively) state. If multiple entries match |host|, the most specific
+ // match determines the return value.
+ bool GetStaticSTSState(const std::string& host, STSState* sts_result) const;
+ bool GetStaticPKPState(const std::string& host, PKPState* pkp_result) const;
// Returns true and updates |*result| iff |host| has dynamic
// HSTS/HPKP/Expect-CT (respectively) state. If multiple entries match |host|,
@@ -709,6 +755,10 @@ class NET_EXPORT TransportSecurityState {
// Returns true if the CT log list has been updated in the last 10 weeks.
bool IsCTLogListTimely() const;
+ // Returns true if the static key pinning list has been updated in the last 10
+ // weeks.
+ bool IsStaticPKPListTimely() const;
+
// The sets of hosts that have enabled TransportSecurity. |domain| will always
// be empty for a STSState, PKPState, or ExpectCTState in these maps; the
// domain comes from the map keys instead. In addition, |upgrade_mode| in the
@@ -756,6 +806,13 @@ class NET_EXPORT TransportSecurityState {
base::Time ct_log_list_last_update_time_;
+ // The values in host_pins_ maps are references to PinSet objects in the
+ // pinsets_ vector.
+ absl::optional<std::map<std::string, std::pair<const PinSet*, bool>>>
+ host_pins_;
+ base::Time key_pins_list_last_update_time_;
+ std::vector<PinSet> pinsets_;
+
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 93565f19e71..37ad27c8277 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.template b/chromium/net/http/transport_security_state_static.template
index 21542f9b7ce..ba40b5bfefc 100644
--- a/chromium/net/http/transport_security_state_static.template
+++ b/chromium/net/http/transport_security_state_static.template
@@ -9,7 +9,8 @@
#include <stdint.h>
-#include "base/cxx17_backports.h"
+#include <iterator>
+
#include "net/http/transport_security_state_source.h"
// These are SubjectPublicKeyInfo hashes for public key pinning. The
@@ -47,7 +48,7 @@ static const net::TransportSecurityStateSource kHSTSSource = {
kHSTSRootPosition,
kExpectCTReportURIs,
kPinsets,
- base::size(kPinsets)
+ std::size(kPinsets)
};
#endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/chromium/net/http/transport_security_state_static_fuzzer.cc b/chromium/net/http/transport_security_state_static_fuzzer.cc
index af5d1ef7a35..6b3e7a02edb 100644
--- a/chromium/net/http/transport_security_state_static_fuzzer.cc
+++ b/chromium/net/http/transport_security_state_static_fuzzer.cc
@@ -15,7 +15,8 @@ class TransportSecurityStateStaticFuzzer {
state->enable_static_pins_ = true;
TransportSecurityState::STSState sts_result;
TransportSecurityState::PKPState pkp_result;
- return state->GetStaticDomainState(input, &sts_result, &pkp_result);
+ return state->GetStaticSTSState(input, &sts_result) ||
+ state->GetStaticPKPState(input, &pkp_result);
}
bool FuzzStaticExpectCTState(TransportSecurityState* state,
diff --git a/chromium/net/http/transport_security_state_static_unittest.template b/chromium/net/http/transport_security_state_static_unittest.template
index dfb4a331e29..8d08caa1872 100644
--- a/chromium/net/http/transport_security_state_static_unittest.template
+++ b/chromium/net/http/transport_security_state_static_unittest.template
@@ -6,7 +6,7 @@
// See transport_security_state_static.template for more information on the data
// in this file.
-// Note that consumers must include <stdint.h>, "base/cxx17_backports.h", and
+// Note that consumers must include <stdint.h>, "<iterator>", and
// "net/http/transport_security_state_source.h", which this file cannot do
// itself, since it's always included in a nested namespace.
@@ -15,7 +15,7 @@
static const char* const kExpectCTReportURIs[] = [[EXPECT_CT_REPORT_URIS]];
static const char* const kNoRejectedPublicKeys[] = {
- NULL,
+ nullptr,
};
[[ACCEPTABLE_CERTS]]
@@ -37,5 +37,5 @@ static const net::TransportSecurityStateSource kHSTSSource = {
kHSTSRootPosition,
kExpectCTReportURIs,
kPinsets,
- base::size(kPinsets)
+ std::size(kPinsets)
};
diff --git a/chromium/net/http/transport_security_state_test_util.cc b/chromium/net/http/transport_security_state_test_util.cc
index d0d05bb4d33..248a004747d 100644
--- a/chromium/net/http/transport_security_state_test_util.cc
+++ b/chromium/net/http/transport_security_state_test_util.cc
@@ -4,6 +4,8 @@
#include "net/http/transport_security_state_test_util.h"
+#include <iterator>
+
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "net/http/transport_security_state.h"
diff --git a/chromium/net/http/transport_security_state_unittest.cc b/chromium/net/http/transport_security_state_unittest.cc
index 228405ee883..ba3b4e3c3b2 100644
--- a/chromium/net/http/transport_security_state_unittest.cc
+++ b/chromium/net/http/transport_security_state_unittest.cc
@@ -7,13 +7,13 @@
#include <stdint.h>
#include <algorithm>
+#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include "base/base64.h"
#include "base/callback_helpers.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/memory/raw_ptr.h"
@@ -26,6 +26,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "crypto/openssl_util.h"
@@ -405,7 +406,10 @@ class TransportSecurityStateTest : public ::testing::Test,
const std::string& host,
TransportSecurityState::STSState* sts_result,
TransportSecurityState::PKPState* pkp_result) {
- return state->GetStaticDomainState(host, sts_result, pkp_result);
+ bool ret = state->GetStaticSTSState(host, sts_result);
+ if (state->GetStaticPKPState(host, pkp_result))
+ ret = true;
+ return ret;
}
bool GetExpectCTState(TransportSecurityState* state,
@@ -885,8 +889,9 @@ TEST_F(TransportSecurityStateTest, LongNames) {
"WaveletIdDomainAndBlipBlipid";
TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- // Just checks that we don't hit a NOTREACHED.
- EXPECT_FALSE(state.GetStaticDomainState(kLongName, &sts_state, &pkp_state));
+ // Just checks that we don't hit a NOTREACHED
+ EXPECT_FALSE(state.GetStaticSTSState(kLongName, &sts_state));
+ EXPECT_FALSE(state.GetStaticPKPState(kLongName, &pkp_state));
EXPECT_FALSE(state.GetDynamicSTSState(kLongName, &sts_state));
EXPECT_FALSE(state.GetDynamicPKPState(kLongName, &pkp_state));
}
@@ -913,10 +918,9 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
TransportSecurityState state;
EnableStaticPins(&state);
- TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- EXPECT_TRUE(state.GetStaticDomainState("no-rejected-pins-pkp.preloaded.test",
- &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("no-rejected-pins-pkp.preloaded.test",
+ &pkp_state));
EXPECT_TRUE(pkp_state.HasPublicKeyPins());
std::string failure_log;
@@ -939,9 +943,7 @@ TEST_F(TransportSecurityStateTest, PreloadedPKPReportUri) {
EnableStaticPins(&state);
TransportSecurityState::PKPState pkp_state;
- TransportSecurityState::STSState unused_sts_state;
- ASSERT_TRUE(state.GetStaticDomainState(kPreloadedPinDomain, &unused_sts_state,
- &pkp_state));
+ ASSERT_TRUE(state.GetStaticPKPState(kPreloadedPinDomain, &pkp_state));
ASSERT_TRUE(pkp_state.HasPublicKeyPins());
GURL report_uri = pkp_state.report_uri;
@@ -1435,8 +1437,8 @@ TEST_F(TransportSecurityStateTest, DecodePreloadedMultiplePrefix) {
sts_state = TransportSecurityState::STSState();
pkp_state = TransportSecurityState::PKPState();
ct_state = TransportSecurityState::ExpectCTState();
- EXPECT_TRUE(GetStaticDomainState(&state, "expect-ct.example.com", &sts_state,
- &pkp_state));
+ EXPECT_FALSE(GetStaticDomainState(&state, "expect-ct.example.com", &sts_state,
+ &pkp_state));
EXPECT_TRUE(sts_state == TransportSecurityState::STSState());
EXPECT_TRUE(pkp_state == TransportSecurityState::PKPState());
EXPECT_TRUE(GetExpectCTState(&state, "expect-ct.example.com", &ct_state));
@@ -1746,9 +1748,35 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) {
}
}
-// Tests that the emergency disable flag causes CT to stop being required
+enum class CTEmergencyDisableSwitchKind {
+ kFinchDrivenFeature,
+ kComponentUpdaterDrivenSwitch,
+};
+
+class CTEmergencyDisableTest
+ : public TransportSecurityStateTest,
+ public testing::WithParamInterface<CTEmergencyDisableSwitchKind> {
+ public:
+ void SetUp() override {
+ if (GetParam() ==
+ CTEmergencyDisableSwitchKind::kComponentUpdaterDrivenSwitch) {
+ state_.SetCTEmergencyDisabled(true);
+ scoped_feature_list_.Init();
+ } else {
+ ASSERT_EQ(GetParam(), CTEmergencyDisableSwitchKind::kFinchDrivenFeature);
+ scoped_feature_list_.InitAndDisableFeature(
+ TransportSecurityState::kCertificateTransparencyEnforcement);
+ }
+ }
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ TransportSecurityState state_;
+};
+
+// Tests that the emergency disable flags cause CT to stop being required
// regardless of host or delegate status.
-TEST_F(TransportSecurityStateTest, CTEmergencyDisable) {
+TEST_P(CTEmergencyDisableTest, CTEmergencyDisable) {
using ::testing::_;
using ::testing::Return;
using CTRequirementLevel =
@@ -1763,47 +1791,42 @@ TEST_F(TransportSecurityStateTest, CTEmergencyDisable) {
hashes.push_back(
HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer())));
- TransportSecurityState state;
-
- // Set CT emergency disable flag.
- state.SetCTEmergencyDisabled(true);
-
MockRequireCTDelegate always_require_delegate;
EXPECT_CALL(always_require_delegate, IsCTRequiredForHost(_, _, _))
.WillRepeatedly(Return(CTRequirementLevel::REQUIRED));
- state.SetRequireCTDelegate(&always_require_delegate);
+ state_.SetRequireCTDelegate(&always_require_delegate);
EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
- state.CheckCTRequirements(
+ state_.CheckCTRequirements(
HostPortPair("www.example.com", 443), true, hashes, cert.get(),
cert.get(), SignedCertificateTimestampAndStatusList(),
TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
NetworkIsolationKey()));
EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
- state.CheckCTRequirements(
+ state_.CheckCTRequirements(
HostPortPair("www.example.com", 443), true, hashes, cert.get(),
cert.get(), SignedCertificateTimestampAndStatusList(),
TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
NetworkIsolationKey()));
EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
- state.CheckCTRequirements(
+ state_.CheckCTRequirements(
HostPortPair("www.example.com", 443), true, hashes, cert.get(),
cert.get(), SignedCertificateTimestampAndStatusList(),
TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
NetworkIsolationKey()));
EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
- state.CheckCTRequirements(
+ state_.CheckCTRequirements(
HostPortPair("www.example.com", 443), true, hashes, cert.get(),
cert.get(), SignedCertificateTimestampAndStatusList(),
TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY,
NetworkIsolationKey()));
- state.SetRequireCTDelegate(nullptr);
+ state_.SetRequireCTDelegate(nullptr);
EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
- state.CheckCTRequirements(
+ state_.CheckCTRequirements(
HostPortPair("www.example.com", 443), true, hashes, cert.get(),
cert.get(), SignedCertificateTimestampAndStatusList(),
TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
@@ -1811,6 +1834,12 @@ TEST_F(TransportSecurityStateTest, CTEmergencyDisable) {
NetworkIsolationKey()));
}
+INSTANTIATE_TEST_SUITE_P(
+ CTEmergencyDisable,
+ CTEmergencyDisableTest,
+ testing::Values(CTEmergencyDisableSwitchKind::kComponentUpdaterDrivenSwitch,
+ CTEmergencyDisableSwitchKind::kFinchDrivenFeature));
+
// Tests that the if the CT log list last update time is set, it is used for
// enforcement decisions.
TEST_F(TransportSecurityStateTest, CTTimestampUpdate) {
@@ -2668,8 +2697,7 @@ class TransportSecurityStateStaticTest : public TransportSecurityStateTest {
static bool StaticShouldRedirect(const char* hostname) {
TransportSecurityState state;
TransportSecurityState::STSState sts_state;
- TransportSecurityState::PKPState pkp_state;
- return state.GetStaticDomainState(hostname, &sts_state, &pkp_state) &&
+ return state.GetStaticSTSState(hostname, &sts_state) &&
sts_state.ShouldUpgradeToSSL();
}
@@ -2677,15 +2705,15 @@ static bool HasStaticState(const char* hostname) {
TransportSecurityState state;
TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- return state.GetStaticDomainState(hostname, &sts_state, &pkp_state);
+ return state.GetStaticSTSState(hostname, &sts_state) ||
+ state.GetStaticPKPState(hostname, &pkp_state);
}
static bool HasStaticPublicKeyPins(const char* hostname) {
TransportSecurityState state;
TransportSecurityStateTest::EnableStaticPins(&state);
- TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- if (!state.GetStaticDomainState(hostname, &sts_state, &pkp_state))
+ if (!state.GetStaticPKPState(hostname, &pkp_state))
return false;
return pkp_state.HasPublicKeyPins();
@@ -2696,34 +2724,25 @@ static bool OnlyPinningInStaticState(const char* hostname) {
TransportSecurityStateTest::EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- if (!state.GetStaticDomainState(hostname, &sts_state, &pkp_state))
- return false;
-
- return (pkp_state.spki_hashes.size() > 0 ||
- pkp_state.bad_spki_hashes.size() > 0) &&
- !sts_state.ShouldUpgradeToSSL();
+ return HasStaticPublicKeyPins(hostname) && !StaticShouldRedirect(hostname);
}
TEST_F(TransportSecurityStateStaticTest, EnableStaticPins) {
TransportSecurityState state;
- TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
EnableStaticPins(&state);
- EXPECT_TRUE(
- state.GetStaticDomainState("chrome.google.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("chrome.google.com", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
}
TEST_F(TransportSecurityStateStaticTest, DisableStaticPins) {
TransportSecurityState state;
- TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
DisableStaticPins(&state);
- EXPECT_TRUE(
- state.GetStaticDomainState("chrome.google.com", &sts_state, &pkp_state));
+ EXPECT_FALSE(state.GetStaticPKPState("chrome.google.com", &pkp_state));
EXPECT_TRUE(pkp_state.spki_hashes.empty());
}
@@ -2771,24 +2790,25 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedDomainSet) {
// The domain wasn't being set, leading to a blank string in the
// chrome://net-internals/#hsts UI. So test that.
- EXPECT_TRUE(
- state.GetStaticDomainState("market.android.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("market.android.com", &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("market.android.com", &sts_state));
EXPECT_EQ(sts_state.domain, "market.android.com");
EXPECT_EQ(pkp_state.domain, "market.android.com");
- EXPECT_TRUE(state.GetStaticDomainState("sub.market.android.com", &sts_state,
- &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("sub.market.android.com", &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("sub.market.android.com", &sts_state));
EXPECT_EQ(sts_state.domain, "market.android.com");
EXPECT_EQ(pkp_state.domain, "market.android.com");
}
TEST_F(TransportSecurityStateStaticTest, Preloaded) {
TransportSecurityState state;
+ EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
// We do more extensive checks for the first domain.
- EXPECT_TRUE(
- state.GetStaticDomainState("www.paypal.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("www.paypal.com", &sts_state));
+ EXPECT_FALSE(state.GetStaticPKPState("www.paypal.com", &pkp_state));
EXPECT_EQ(sts_state.upgrade_mode,
TransportSecurityState::STSState::MODE_FORCE_HTTPS);
EXPECT_FALSE(sts_state.include_subdomains);
@@ -2837,13 +2857,14 @@ TEST_F(TransportSecurityStateStaticTest, Preloaded) {
EXPECT_TRUE(StaticShouldRedirect("youtube.com"));
// These domains used to be only HSTS when SNI was available.
- EXPECT_TRUE(state.GetStaticDomainState("gmail.com", &sts_state, &pkp_state));
- EXPECT_TRUE(
- state.GetStaticDomainState("www.gmail.com", &sts_state, &pkp_state));
- EXPECT_TRUE(
- state.GetStaticDomainState("googlemail.com", &sts_state, &pkp_state));
- EXPECT_TRUE(
- state.GetStaticDomainState("www.googlemail.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("gmail.com", &sts_state));
+ EXPECT_TRUE(state.GetStaticPKPState("gmail.com", &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("www.gmail.com", &sts_state));
+ EXPECT_TRUE(state.GetStaticPKPState("www.gmail.com", &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("googlemail.com", &sts_state));
+ EXPECT_TRUE(state.GetStaticPKPState("googlemail.com", &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("www.googlemail.com", &sts_state));
+ EXPECT_TRUE(state.GetStaticPKPState("www.googlemail.com", &pkp_state));
// fi.g.co should not force HTTPS because there are still HTTP-only services
// on it.
@@ -3002,8 +3023,8 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedPins) {
TransportSecurityState::PKPState pkp_state;
// We do more extensive checks for the first domain.
- EXPECT_TRUE(
- state.GetStaticDomainState("www.paypal.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticSTSState("www.paypal.com", &sts_state));
+ EXPECT_FALSE(state.GetStaticPKPState("www.paypal.com", &pkp_state));
EXPECT_EQ(sts_state.upgrade_mode,
TransportSecurityState::STSState::MODE_FORCE_HTTPS);
EXPECT_FALSE(sts_state.include_subdomains);
@@ -3030,39 +3051,33 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedPins) {
EXPECT_TRUE(HasStaticPublicKeyPins("blog.torproject.org"));
EXPECT_FALSE(HasStaticState("foo.torproject.org"));
- EXPECT_TRUE(
- state.GetStaticDomainState("torproject.org", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("torproject.org", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
- EXPECT_TRUE(
- state.GetStaticDomainState("www.torproject.org", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("www.torproject.org", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
- EXPECT_TRUE(state.GetStaticDomainState("check.torproject.org", &sts_state,
- &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("check.torproject.org", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
- EXPECT_TRUE(state.GetStaticDomainState("blog.torproject.org", &sts_state,
- &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("blog.torproject.org", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
EXPECT_TRUE(HasStaticPublicKeyPins("www.twitter.com"));
- // Check that Facebook subdomains have pinning but not HSTS.
- EXPECT_TRUE(
- state.GetStaticDomainState("facebook.com", &sts_state, &pkp_state));
+ // Facebook has pinning and hsts on facebook.com, but only pinning on
+ // subdomains.
+ EXPECT_TRUE(state.GetStaticPKPState("facebook.com", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("facebook.com"));
- EXPECT_TRUE(
- state.GetStaticDomainState("foo.facebook.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("foo.facebook.com", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
EXPECT_FALSE(StaticShouldRedirect("foo.facebook.com"));
- EXPECT_TRUE(
- state.GetStaticDomainState("www.facebook.com", &sts_state, &pkp_state));
+ // www.facebook.com and subdomains have both pinning and hsts.
+ EXPECT_TRUE(state.GetStaticPKPState("www.facebook.com", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("www.facebook.com"));
- EXPECT_TRUE(state.GetStaticDomainState("foo.www.facebook.com", &sts_state,
- &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("foo.www.facebook.com", &pkp_state));
EXPECT_FALSE(pkp_state.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("foo.www.facebook.com"));
}
@@ -3070,11 +3085,9 @@ TEST_F(TransportSecurityStateStaticTest, PreloadedPins) {
TEST_F(TransportSecurityStateStaticTest, BuiltinCertPins) {
TransportSecurityState state;
EnableStaticPins(&state);
- TransportSecurityState::STSState sts_state;
TransportSecurityState::PKPState pkp_state;
- EXPECT_TRUE(
- state.GetStaticDomainState("chrome.google.com", &sts_state, &pkp_state));
+ EXPECT_TRUE(state.GetStaticPKPState("chrome.google.com", &pkp_state));
EXPECT_TRUE(HasStaticPublicKeyPins("chrome.google.com"));
HashValueVector hashes;
@@ -3868,4 +3881,225 @@ TEST_F(TransportSecurityStateTest, PruneExpectCTNetworkIsolationKeyLimit) {
}
}
+TEST_F(TransportSecurityStateTest, UpdateKeyPinsListValidPin) {
+ 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;
+
+ // Prior to updating the list, bad_hashes should be rejected.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+
+ // Update the pins list, adding bad_hashes to the accepted hashes for this
+ // host.
+ std::vector<std::vector<uint8_t>> accepted_hashes;
+ for (size_t i = 0; kBadPath[i]; i++) {
+ HashValue hash;
+ ASSERT_TRUE(hash.FromString(kBadPath[i]));
+ accepted_hashes.emplace_back(hash.data(), hash.data() + hash.size());
+ }
+ TransportSecurityState::PinSet test_pinset(
+ /*name=*/"test",
+ /*static_spki_hashes=*/accepted_hashes,
+ /*bad_static_spki_hashes=*/{},
+ /*report_uri=*/kReportUri);
+ TransportSecurityState::PinSetInfo test_pinsetinfo(
+ /*hostname=*/kHost, /*pinset_name=*/"test",
+ /*include_subdomains=*/false);
+ state.UpdatePinList({test_pinset}, {test_pinsetinfo}, base::Time::Now());
+
+ // Hashes should now be accepted.
+ 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));
+}
+
+TEST_F(TransportSecurityStateTest, UpdateKeyPinsListNotValidPin) {
+ 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 good_hashes;
+
+ for (size_t i = 0; kGoodPath[i]; i++)
+ EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes));
+
+ TransportSecurityState state;
+ EnableStaticPins(&state);
+ std::string unused_failure_log;
+
+ // Prior to updating the list, good_hashes should be accepted
+ EXPECT_EQ(TransportSecurityState::PKPStatus::OK,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, good_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+
+ // Update the pins list, adding good_hashes to the rejected hashes for this
+ // host.
+ std::vector<std::vector<uint8_t>> rejected_hashes;
+ for (size_t i = 0; kGoodPath[i]; i++) {
+ HashValue hash;
+ ASSERT_TRUE(hash.FromString(kGoodPath[i]));
+ rejected_hashes.emplace_back(hash.data(), hash.data() + hash.size());
+ }
+ TransportSecurityState::PinSet test_pinset(
+ /*name=*/"test",
+ /*static_spki_hashes=*/{},
+ /*bad_static_spki_hashes=*/rejected_hashes,
+ /*report_uri=*/kReportUri);
+ TransportSecurityState::PinSetInfo test_pinsetinfo(
+ /*hostname=*/kHost, /* pinset_name=*/"test",
+ /*include_subdomains=*/false);
+ state.UpdatePinList({test_pinset}, {test_pinsetinfo}, base::Time::Now());
+
+ // Hashes should now be rejected.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, good_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+}
+
+TEST_F(TransportSecurityStateTest, UpdateKeyPinsEmptyList) {
+ 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;
+
+ // Prior to updating the list, bad_hashes should be rejected.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+
+ // Update the pins list with an empty list.
+ state.UpdatePinList({}, {}, base::Time::Now());
+
+ // Hashes should now be accepted.
+ 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));
+}
+
+TEST_F(TransportSecurityStateTest, UpdateKeyPinsListTimestamp) {
+ 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;
+
+ // Prior to updating the list, bad_hashes should be rejected.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+
+ // Update the pins list, with bad hashes as rejected, but a timestamp >70 days
+ // old.
+ std::vector<std::vector<uint8_t>> rejected_hashes;
+ for (size_t i = 0; kBadPath[i]; i++) {
+ HashValue hash;
+ ASSERT_TRUE(hash.FromString(kBadPath[i]));
+ rejected_hashes.emplace_back(hash.data(), hash.data() + hash.size());
+ }
+ TransportSecurityState::PinSet test_pinset(
+ /*name=*/"test",
+ /*static_spki_hashes=*/{},
+ /*bad_static_spki_hashes=*/rejected_hashes,
+ /*report_uri=*/kReportUri);
+ TransportSecurityState::PinSetInfo test_pinsetinfo(
+ /*hostname=*/kHost, /* pinset_name=*/"test",
+ /*include_subdomains=*/false);
+ state.UpdatePinList({test_pinset}, {test_pinsetinfo},
+ base::Time::Now() - base::Days(70));
+
+ // Hashes should now be accepted.
+ 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));
+
+ // Update the pins list again, with a timestamp <70 days old.
+ state.UpdatePinList({test_pinset}, {test_pinsetinfo},
+ base::Time::Now() - base::Days(69));
+
+ // Hashes should now be rejected.
+ EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
+ state.CheckPublicKeyPins(
+ host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ network_isolation_key, &unused_failure_log));
+}
+
} // namespace net
diff --git a/chromium/net/http/url_security_manager_unittest.cc b/chromium/net/http/url_security_manager_unittest.cc
index 834f559fdf5..672425027c3 100644
--- a/chromium/net/http/url_security_manager_unittest.cc
+++ b/chromium/net/http/url_security_manager_unittest.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/cxx17_backports.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_filter.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -56,7 +55,7 @@ TEST(URLSecurityManager, UseDefaultCredentials) {
url_security_manager->SetDefaultAllowlist(std::move(auth_filter));
ASSERT_TRUE(url_security_manager.get());
- for (size_t i = 0; i < base::size(kTestDataList); ++i) {
+ for (size_t i = 0; i < std::size(kTestDataList); ++i) {
url::SchemeHostPort scheme_host_port(
GURL(kTestDataList[i].scheme_host_port));
bool can_use_default =
@@ -78,7 +77,7 @@ TEST(URLSecurityManager, CanDelegate) {
url_security_manager->SetDelegateAllowlist(std::move(auth_filter));
ASSERT_TRUE(url_security_manager.get());
- for (size_t i = 0; i < base::size(kTestDataList); ++i) {
+ for (size_t i = 0; i < std::size(kTestDataList); ++i) {
url::SchemeHostPort scheme_host_port(
GURL(kTestDataList[i].scheme_host_port));
bool can_delegate = url_security_manager->CanDelegate(scheme_host_port);
@@ -94,7 +93,7 @@ TEST(URLSecurityManager, CanDelegate_NoAllowlist) {
URLSecurityManager::Create());
ASSERT_TRUE(url_security_manager.get());
- for (size_t i = 0; i < base::size(kTestDataList); ++i) {
+ for (size_t i = 0; i < std::size(kTestDataList); ++i) {
url::SchemeHostPort scheme_host_port(
GURL(kTestDataList[i].scheme_host_port));
bool can_delegate = url_security_manager->CanDelegate(scheme_host_port);