summaryrefslogtreecommitdiff
path: root/chromium/net/spdy
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/net/spdy
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/spdy')
-rw-r--r--chromium/net/spdy/OWNERS1
-rw-r--r--chromium/net/spdy/platform/impl/spdy_logging_impl.h2
-rw-r--r--chromium/net/spdy/platform/impl/spdy_macros_impl.h1
-rw-r--r--chromium/net/spdy/spdy_network_transaction_unittest.cc99
-rw-r--r--chromium/net/spdy/spdy_session.cc156
-rw-r--r--chromium/net/spdy/spdy_session.h7
-rw-r--r--chromium/net/spdy/spdy_session_unittest.cc212
-rw-r--r--chromium/net/spdy/spdy_stream.cc13
-rw-r--r--chromium/net/spdy/spdy_stream.h4
-rw-r--r--chromium/net/spdy/spdy_stream_test_util.cc6
-rw-r--r--chromium/net/spdy/spdy_stream_test_util.h6
-rw-r--r--chromium/net/spdy/spdy_stream_unittest.cc63
12 files changed, 431 insertions, 139 deletions
diff --git a/chromium/net/spdy/OWNERS b/chromium/net/spdy/OWNERS
index b608e73eafc..e041764c5b6 100644
--- a/chromium/net/spdy/OWNERS
+++ b/chromium/net/spdy/OWNERS
@@ -2,7 +2,6 @@ birenroy@chromium.org
bnc@chromium.org
dahollings@chromium.org
diannahu@chromium.org
-rch@chromium.org
yasong@chromium.org
# COMPONENT: Internals>Network>HTTP2
diff --git a/chromium/net/spdy/platform/impl/spdy_logging_impl.h b/chromium/net/spdy/platform/impl/spdy_logging_impl.h
index cc79854df01..a9ba72bbb76 100644
--- a/chromium/net/spdy/platform/impl/spdy_logging_impl.h
+++ b/chromium/net/spdy/platform/impl/spdy_logging_impl.h
@@ -5,7 +5,9 @@
#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_LOGGING_IMPL_H_
#define NET_SPDY_PLATFORM_IMPL_SPDY_LOGGING_IMPL_H_
+#include "base/check_op.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "build/build_config.h"
#include "net/base/net_export.h"
diff --git a/chromium/net/spdy/platform/impl/spdy_macros_impl.h b/chromium/net/spdy/platform/impl/spdy_macros_impl.h
index fb286bc9ab0..3c1da5102c3 100644
--- a/chromium/net/spdy/platform/impl/spdy_macros_impl.h
+++ b/chromium/net/spdy/platform/impl/spdy_macros_impl.h
@@ -6,7 +6,6 @@
#define NET_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_
#include "base/compiler_specific.h"
-#include "base/logging.h"
#define SPDY_MUST_USE_RESULT_IMPL WARN_UNUSED_RESULT
#define SPDY_UNUSED_IMPL ALLOW_UNUSED_TYPE
diff --git a/chromium/net/spdy/spdy_network_transaction_unittest.cc b/chromium/net/spdy/spdy_network_transaction_unittest.cc
index 1da839038e0..0caead021a1 100644
--- a/chromium/net/spdy/spdy_network_transaction_unittest.cc
+++ b/chromium/net/spdy/spdy_network_transaction_unittest.cc
@@ -41,6 +41,8 @@
#include "net/http/http_response_info.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_transaction_test_util.h"
+#include "net/http/test_upload_data_stream_not_allow_http1.h"
+#include "net/http/transport_security_state.h"
#include "net/log/net_log_event_type.h"
#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
@@ -411,7 +413,8 @@ class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
SpdySessionKey key(HostPortPair::FromURL(request_.url),
ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), false /* disable_secure_dns */);
+ request_.network_isolation_key,
+ false /* disable_secure_dns */);
HttpNetworkSession* session = helper.session();
base::WeakPtr<SpdySession> spdy_session =
session->spdy_session_pool()->FindAvailableSession(
@@ -5177,7 +5180,7 @@ TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) {
NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_THAT(out.rv, IsError(ERR_ABORTED));
+ EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
}
// Request should be retried on a new connection upon receiving a GOAWAY frame
@@ -6414,28 +6417,53 @@ struct PushUrlTestParams {
const char* url_to_fetch;
const char* url_to_push;
bool client_cert_sent;
+ bool expect_ct_error;
SpdyPushedStreamFate expected_fate;
} push_url_test_cases[] = {
// http scheme cannot be pushed (except by trusted proxy).
- {"https://www.example.org/foo.html", "http://www.example.org/foo.js", false,
+ {"https://www.example.org/foo.html", "http://www.example.org/foo.js",
+ false /* client_cert_sent */, false /* expect_ct_error */,
SpdyPushedStreamFate::kNonHttpsPushedScheme},
// ftp scheme cannot be pushed.
- {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js", false,
+ {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js",
+ false /* client_cert_sent */, false /* expect_ct_error */,
SpdyPushedStreamFate::kInvalidUrl},
// Cross subdomain, certificate not valid.
{"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js",
- false, SpdyPushedStreamFate::kCertificateMismatch},
+ false /* client_cert_sent */, false /* expect_ct_error */,
+ SpdyPushedStreamFate::kCertificateMismatch},
// Cross domain, certificate not valid.
- {"https://www.example.org/foo.html", "https://www.foo.com/foo.js", false,
+ {"https://www.example.org/foo.html", "https://www.foo.com/foo.js",
+ false /* client_cert_sent */, false /* expect_ct_error */,
SpdyPushedStreamFate::kCertificateMismatch},
// Cross domain, certificate valid, but cross-origin push is rejected on a
// connection with client certificate.
{"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
- true, SpdyPushedStreamFate::kCertificateMismatch}};
+ true /* client_cert_sent */, false /* expect_ct_error */,
+ SpdyPushedStreamFate::kCertificateMismatch},
+ // Cross domain, certificate valid, but cross-origin push is rejected on a
+ // connection with an Expect-CT error.
+ {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
+ false /* client_cert_sent */, true /* expect_ct_error */,
+ SpdyPushedStreamFate::kCertificateMismatch}};
class SpdyNetworkTransactionPushUrlTest
: public SpdyNetworkTransactionTest,
public ::testing::WithParamInterface<PushUrlTestParams> {
+ public:
+ SpdyNetworkTransactionPushUrlTest() {
+ // Set features needed for the |expect_ct_error| case, where it's important
+ // to check that NetworkIsolationKeys are respected.
+ feature_list_.InitWithFeatures(
+ /* enabled_features */
+ {TransportSecurityState::kDynamicExpectCTFeature,
+ features::kPartitionExpectCTStateByNetworkIsolationKey,
+ features::kPartitionConnectionsByNetworkIsolationKey,
+ features::kPartitionSSLSessionsByNetworkIsolationKey},
+ /* disabled_features */
+ {});
+ }
+
protected:
// In this test we want to verify that we can't accidentally push content
// which can't be pushed by this content server.
@@ -6478,6 +6506,9 @@ class SpdyNetworkTransactionPushUrlTest
SequencedSocketData data(reads, writes);
request_.url = GURL(GetParam().url_to_fetch);
+ // Set a NetworkIsolationKey for the |expect_ct_error| case, to make sure
+ // NetworkIsolationKeys are respected.
+ request_.network_isolation_key = NetworkIsolationKey::CreateTransient();
// Enable cross-origin push. Since we are not using a proxy, this should
// not actually enable cross-origin SPDY push.
@@ -6487,15 +6518,33 @@ class SpdyNetworkTransactionPushUrlTest
"https://123.45.67.89:443", net::ProxyServer::SCHEME_HTTP));
session_deps->proxy_resolution_service->SetProxyDelegate(
proxy_delegate.get());
- NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
- std::move(session_deps));
-
- helper.RunPreTestSetup();
auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent;
ssl_provider->ssl_info.cert =
ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ if (GetParam().expect_ct_error) {
+ ssl_provider->ssl_info.ct_policy_compliance =
+ ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ ssl_provider->ssl_info.is_issued_by_known_root = true;
+
+ session_deps->transport_security_state->AddExpectCT(
+ "mail.example.org",
+ base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true,
+ GURL(), request_.network_isolation_key);
+ }
+
+ NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
+ std::move(session_deps));
+
+ helper.RunPreTestSetup();
+
+ if (GetParam().expect_ct_error) {
+ ssl_provider->ssl_info.ct_policy_compliance =
+ ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ ssl_provider->ssl_info.is_issued_by_known_root = true;
+ }
+
helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
HttpNetworkTransaction* trans = helper.trans();
@@ -6533,6 +6582,8 @@ class SpdyNetworkTransactionPushUrlTest
1);
histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
}
+
+ base::test::ScopedFeatureList feature_list_;
};
INSTANTIATE_TEST_SUITE_P(All,
@@ -10438,4 +10489,30 @@ TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
helper.VerifyDataConsumed();
}
+TEST_F(SpdyNetworkTransactionTest, NotAllowHTTP1NotBlockH2Post) {
+ spdy::SpdySerializedFrame req(
+ spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
+ };
+ spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
+ MockRead reads[] = {
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
+ MockRead(ASYNC, 0, 4) // EOF
+ };
+ SequencedSocketData data(reads, writes);
+
+ request_.method = "POST";
+ UploadDataStreamNotAllowHTTP1 upload_data(kUploadData);
+ request_.upload_data_stream = &upload_data;
+
+ NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
+ helper.RunToCompletion(&data);
+ TransactionHelperResult out = helper.output();
+ EXPECT_THAT(out.rv, IsOk());
+ EXPECT_EQ("HTTP/1.1 200", out.status_line);
+ EXPECT_EQ("hello!", out.response_data);
+}
+
} // namespace net
diff --git a/chromium/net/spdy/spdy_session.cc b/chromium/net/spdy/spdy_session.cc
index b61963f6716..eef09df91ed 100644
--- a/chromium/net/spdy/spdy_session.cc
+++ b/chromium/net/spdy/spdy_session.cc
@@ -27,6 +27,7 @@
#include "base/trace_event/memory_usage_estimator.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
+#include "net/base/features.h"
#include "net/base/url_util.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_verify_result.h"
@@ -836,11 +837,13 @@ void SpdyStreamRequest::OnConfirmHandshakeComplete(int rv) {
}
// static
-bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
- const SSLInfo& ssl_info,
- const SSLConfigService& ssl_config_service,
- const std::string& old_hostname,
- const std::string& new_hostname) {
+bool SpdySession::CanPool(
+ TransportSecurityState* transport_security_state,
+ const SSLInfo& ssl_info,
+ const SSLConfigService& ssl_config_service,
+ const std::string& old_hostname,
+ const std::string& new_hostname,
+ const net::NetworkIsolationKey& network_isolation_key) {
// Pooling is prohibited if the server cert is not valid for the new domain,
// and for connections on which client certs were sent. It is also prohibited
// when channel ID was sent if the hosts are from different eTLDs+1.
@@ -875,7 +878,7 @@ bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
ssl_info.public_key_hashes, ssl_info.cert.get(),
ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps,
TransportSecurityState::DISABLE_EXPECT_CT_REPORTS,
- ssl_info.ct_policy_compliance)) {
+ ssl_info.ct_policy_compliance, network_isolation_key)) {
case TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
return false;
case TransportSecurityState::CT_REQUIREMENTS_MET:
@@ -1098,7 +1101,8 @@ bool SpdySession::VerifyDomainAuthentication(const std::string& domain) const {
return true; // This is not a secure session, so all domains are okay.
return CanPool(transport_security_state_, ssl_info, *ssl_config_service_,
- host_port_pair().host(), domain);
+ host_port_pair().host(), domain,
+ spdy_session_key_.network_isolation_key());
}
void SpdySession::EnqueueStreamWrite(
@@ -1165,15 +1169,13 @@ std::unique_ptr<spdy::SpdySerializedFrame> SpdySession::CreateHeaders(
priority_dependency_state_.OnStreamCreation(
stream_id, spdy_priority, &parent_stream_id, &weight, &exclusive);
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
- [&](NetLogCaptureMode capture_mode) {
- return NetLogSpdyHeadersSentParams(
- &block, (flags & spdy::CONTROL_FLAG_FIN) != 0,
- stream_id, has_priority, weight, parent_stream_id,
- exclusive, source_dependency, capture_mode);
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
+ [&](NetLogCaptureMode capture_mode) {
+ return NetLogSpdyHeadersSentParams(
+ &block, (flags & spdy::CONTROL_FLAG_FIN) != 0,
+ stream_id, has_priority, weight, parent_stream_id,
+ exclusive, source_dependency, capture_mode);
+ });
spdy::SpdyHeadersIR headers(stream_id, std::move(block));
headers.set_has_priority(has_priority);
@@ -1241,7 +1243,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
// Even though we're currently stalled only by the stream, we
// might end up being stalled by the session also.
QueueSendStalledStream(*stream);
- net_log().AddEventWithIntParams(
+ net_log_.AddEventWithIntParams(
NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
"stream_id", stream_id);
return std::unique_ptr<SpdyBuffer>();
@@ -1253,7 +1255,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
if (send_stalled_by_session) {
stream->set_send_stalled_by_flow_control(true);
QueueSendStalledStream(*stream);
- net_log().AddEventWithIntParams(
+ net_log_.AddEventWithIntParams(
NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
"stream_id", stream_id);
return std::unique_ptr<SpdyBuffer>();
@@ -1268,12 +1270,10 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
if (effective_len < len)
flags = static_cast<spdy::SpdyDataFlags>(flags & ~spdy::DATA_FLAG_FIN);
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA, [&] {
- return NetLogSpdyDataParams(stream_id, effective_len,
- (flags & spdy::DATA_FLAG_FIN) != 0);
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA, [&] {
+ return NetLogSpdyDataParams(stream_id, effective_len,
+ (flags & spdy::DATA_FLAG_FIN) != 0);
+ });
// Send PrefacePing for DATA_FRAMEs with nonzero payload size.
if (effective_len > 0)
@@ -1316,6 +1316,9 @@ void SpdySession::UpdateStreamPriority(SpdyStream* stream,
DCHECK(IsStreamActive(stream_id));
+ if (base::FeatureList::IsEnabled(features::kAvoidH2Reprioritization))
+ return;
+
auto updates = priority_dependency_state_.OnStreamUpdate(
stream_id, ConvertRequestPriorityToSpdyPriority(new_priority));
for (auto u : updates) {
@@ -1745,13 +1748,12 @@ int SpdySession::TryCreateStream(
return CreateStream(*request, stream);
}
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, [&] {
- return NetLogSpdySessionStalledParams(
- active_streams_.size(), created_streams_.size(), num_pushed_streams_,
- max_concurrent_streams_, request->url().spec());
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, [&] {
+ return NetLogSpdySessionStalledParams(
+ active_streams_.size(), created_streams_.size(), num_pushed_streams_,
+ max_concurrent_streams_, request->url().spec());
+ });
+
RequestPriority priority = request->priority();
CHECK_GE(priority, MINIMUM_PRIORITY);
CHECK_LE(priority, MAXIMUM_PRIORITY);
@@ -1999,7 +2001,8 @@ void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id,
SSLInfo ssl_info;
CHECK(GetSSLInfo(&ssl_info));
if (!CanPool(transport_security_state_, ssl_info, *ssl_config_service_,
- associated_url.host(), gurl.host())) {
+ associated_url.host(), gurl.host(),
+ spdy_session_key_.network_isolation_key())) {
RecordSpdyPushedStreamFateHistogram(
SpdyPushedStreamFate::kCertificateMismatch);
EnqueueResetStreamFrame(stream_id, request_priority,
@@ -2167,7 +2170,7 @@ void SpdySession::EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id,
const std::string& description) {
DCHECK_NE(stream_id, 0u);
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM, [&] {
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM, [&] {
return NetLogSpdySendRstStreamParams(stream_id, error_code, description);
});
@@ -2184,7 +2187,7 @@ void SpdySession::EnqueuePriorityFrame(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId dependency_id,
int weight,
bool exclusive) {
- net_log().AddEvent(NetLogEventType::HTTP2_STREAM_SEND_PRIORITY, [&] {
+ net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_SEND_PRIORITY, [&] {
return NetLogSpdyPriorityParams(stream_id, dependency_id, weight,
exclusive);
});
@@ -2600,7 +2603,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
break;
case spdy::SETTINGS_INITIAL_WINDOW_SIZE: {
if (value > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
- net_log().AddEventWithIntParams(
+ net_log_.AddEventWithIntParams(
NetLogEventType::HTTP2_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
"initial_window_size", value);
return;
@@ -2612,7 +2615,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
static_cast<int32_t>(value) - stream_initial_send_window_size_;
stream_initial_send_window_size_ = static_cast<int32_t>(value);
UpdateStreamsSendWindowSize(delta_window_size);
- net_log().AddEventWithIntParams(
+ net_log_.AddEventWithIntParams(
NetLogEventType::HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
"delta_window_size", delta_window_size);
break;
@@ -2697,11 +2700,10 @@ void SpdySession::WritePingFrame(spdy::SpdyPingId unique_id, bool is_ack) {
EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::PING,
std::move(ping_frame));
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] {
- return NetLogSpdyPingParams(unique_id, is_ack, "sent");
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] {
+ return NetLogSpdyPingParams(unique_id, is_ack, "sent");
+ });
+
if (!is_ack) {
DCHECK(!ping_in_flight_);
@@ -3078,7 +3080,7 @@ void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id,
spdy::SpdyErrorCode error_code) {
CHECK(in_io_loop_);
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, [&] {
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, [&] {
return NetLogSpdyRecvRstStreamParams(stream_id, error_code);
});
@@ -3101,19 +3103,15 @@ void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id,
CloseActiveStreamIterator(it, ERR_HTTP2_SERVER_REFUSED_STREAM);
} else if (error_code == spdy::ERROR_CODE_HTTP_1_1_REQUIRED) {
// TODO(bnc): Record histogram with number of open streams capped at 50.
- if (net_log().IsCapturing()) {
- it->second->LogStreamError(ERR_HTTP_1_1_REQUIRED,
- "Closing session because server reset stream "
- "with ERR_HTTP_1_1_REQUIRED.");
- }
+ it->second->LogStreamError(ERR_HTTP_1_1_REQUIRED,
+ "Closing session because server reset stream "
+ "with ERR_HTTP_1_1_REQUIRED.");
DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream.");
} else {
RecordProtocolErrorHistogram(
PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM);
- if (net_log().IsCapturing()) {
- it->second->LogStreamError(ERR_HTTP2_PROTOCOL_ERROR,
- "Server reset stream.");
- }
+ it->second->LogStreamError(ERR_HTTP2_PROTOCOL_ERROR,
+ "Server reset stream.");
// TODO(mbelshe): Map from Spdy-protocol errors to something sensical.
// For now, it doesn't matter much - it is a protocol error.
CloseActiveStreamIterator(it, ERR_HTTP2_PROTOCOL_ERROR);
@@ -3142,7 +3140,7 @@ void SpdySession::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
} else if (error_code == spdy::ERROR_CODE_NO_ERROR) {
StartGoingAway(last_accepted_stream_id, ERR_HTTP2_SERVER_REFUSED_STREAM);
} else {
- StartGoingAway(last_accepted_stream_id, ERR_ABORTED);
+ StartGoingAway(last_accepted_stream_id, ERR_HTTP2_PROTOCOL_ERROR);
}
// This is to handle the case when we already don't have any active
// streams (i.e., StartGoingAway() did nothing). Otherwise, we have
@@ -3174,11 +3172,10 @@ void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id,
size_t len) {
CHECK(in_io_loop_);
DCHECK_LT(len, 1u << 24);
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] {
- return NetLogSpdyDataParams(stream_id, len, false);
- });
- }
+
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] {
+ return NetLogSpdyDataParams(stream_id, len, false);
+ });
// Build the buffer as early as possible so that we go through the
// session flow control checks and update
@@ -3213,11 +3210,8 @@ void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id,
void SpdySession::OnStreamEnd(spdy::SpdyStreamId stream_id) {
CHECK(in_io_loop_);
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] {
- return NetLogSpdyDataParams(stream_id, 0, true);
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA,
+ [&] { return NetLogSpdyDataParams(stream_id, 0, true); });
auto it = active_streams_.find(stream_id);
// By the time data comes in, the stream may already be inactive.
@@ -3249,10 +3243,8 @@ void SpdySession::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) {
void SpdySession::OnSettings() {
CHECK(in_io_loop_);
- if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS);
- net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK);
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS);
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK);
// Send an acknowledgment of the setting.
spdy::SpdySettingsIR settings_ir;
@@ -3265,8 +3257,7 @@ void SpdySession::OnSettings() {
void SpdySession::OnSettingsAck() {
CHECK(in_io_loop_);
- if (net_log_.IsCapturing())
- net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK);
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK);
}
void SpdySession::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
@@ -3329,14 +3320,12 @@ void SpdySession::OnPushPromise(spdy::SpdyStreamId stream_id,
spdy::SpdyHeaderBlock headers) {
CHECK(in_io_loop_);
- if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE,
- [&](NetLogCaptureMode capture_mode) {
- return NetLogSpdyPushPromiseReceivedParams(
- &headers, stream_id, promised_stream_id,
- capture_mode);
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE,
+ [&](NetLogCaptureMode capture_mode) {
+ return NetLogSpdyPushPromiseReceivedParams(
+ &headers, stream_id, promised_stream_id,
+ capture_mode);
+ });
TryCreatePushStream(promised_stream_id, stream_id, std::move(headers));
}
@@ -3351,13 +3340,11 @@ void SpdySession::OnHeaders(spdy::SpdyStreamId stream_id,
base::TimeTicks recv_first_byte_time) {
CHECK(in_io_loop_);
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS,
- [&](NetLogCaptureMode capture_mode) {
- return NetLogSpdyHeadersReceivedParams(
- &headers, fin, stream_id, capture_mode);
- });
- }
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS,
+ [&](NetLogCaptureMode capture_mode) {
+ return NetLogSpdyHeadersReceivedParams(
+ &headers, fin, stream_id, capture_mode);
+ });
auto it = active_streams_.find(stream_id);
if (it == active_streams_.end()) {
@@ -3412,7 +3399,8 @@ void SpdySession::OnAltSvc(
if (!GetSSLInfo(&ssl_info))
return;
if (!CanPool(transport_security_state_, ssl_info, *ssl_config_service_,
- host_port_pair().host(), gurl.host())) {
+ host_port_pair().host(), gurl.host(),
+ spdy_session_key_.network_isolation_key())) {
return;
}
scheme_host_port = url::SchemeHostPort(gurl);
diff --git a/chromium/net/spdy/spdy_session.h b/chromium/net/spdy/spdy_session.h
index 9c1c504859f..35bb0836e02 100644
--- a/chromium/net/spdy/spdy_session.h
+++ b/chromium/net/spdy/spdy_session.h
@@ -329,7 +329,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
const SSLInfo& ssl_info,
const SSLConfigService& ssl_config_service,
const std::string& old_hostname,
- const std::string& new_hostname);
+ const std::string& new_hostname,
+ const net::NetworkIsolationKey& network_isolation_key);
// Create a new SpdySession.
// |spdy_session_key| is the host/port that this session connects to, privacy
@@ -1106,8 +1107,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// and maximum HPACK dynamic table size.
const spdy::SettingsMap initial_settings_;
- // If set, an HTTP/2 frame with a reserved frame type will be sent after every
- // valid HTTP/2 frame. See
+ // If set, an HTTP/2 frame with a reserved frame type will be sent after
+ // every HTTP/2 SETTINGS frame and before every HTTP/2 DATA frame. See
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
const base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame_;
diff --git a/chromium/net/spdy/spdy_session_unittest.cc b/chromium/net/spdy/spdy_session_unittest.cc
index bffd8d2f7d3..65c23fa9999 100644
--- a/chromium/net/spdy/spdy_session_unittest.cc
+++ b/chromium/net/spdy/spdy_session_unittest.cc
@@ -22,6 +22,7 @@
#include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/network_isolation_key.h"
#include "net/base/privacy_mode.h"
#include "net/base/proxy_delegate.h"
#include "net/base/proxy_server.h"
@@ -2778,6 +2779,63 @@ TEST_F(SpdySessionTest, VerifyDomainAuthentication) {
EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com"));
}
+// Check that VerifyDomainAuthentication respects Expect-CT failures, and uses
+// the correct NetworkIsolationKey.
+TEST_F(SpdySessionTest, VerifyDomainAuthenticationExpectCT) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ /* enabled_features */
+ {TransportSecurityState::kDynamicExpectCTFeature,
+ features::kPartitionExpectCTStateByNetworkIsolationKey,
+ features::kPartitionConnectionsByNetworkIsolationKey,
+ features::kPartitionSSLSessionsByNetworkIsolationKey},
+ /* disabled_features */
+ {});
+
+ key_ = SpdySessionKey(HostPortPair::FromURL(test_url_), ProxyServer::Direct(),
+ PRIVACY_MODE_DISABLED,
+ SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+ NetworkIsolationKey::CreateTransient(),
+ false /* disable_secure_dns */);
+ ssl_.ssl_info.ct_policy_compliance =
+ ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ ssl_.ssl_info.is_issued_by_known_root = true;
+
+ // Need to create this after enabling features.
+ session_deps_.transport_security_state =
+ std::make_unique<TransportSecurityState>();
+
+ SequencedSocketData data;
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ AddSSLSocketData();
+
+ CreateNetworkSession();
+ CreateSpdySession();
+
+ EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org"));
+ EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.org"));
+ EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.com"));
+ EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com"));
+
+ // Add Expect-CT data for all three hosts that passed the above checks, using
+ // different NetworkIsolationKeys.
+ const base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1);
+ session_deps_.transport_security_state->AddExpectCT(
+ "www.example.org", expiry, true, GURL(), NetworkIsolationKey());
+ session_deps_.transport_security_state->AddExpectCT(
+ "mail.example.org", expiry, true, GURL(), key_.network_isolation_key());
+ session_deps_.transport_security_state->AddExpectCT(
+ "mail.example.com", expiry, true, GURL(),
+ NetworkIsolationKey::CreateTransient());
+
+ // The host with the Expect-CT data that matches the SpdySession's should fail
+ // the check now.
+ EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org"));
+ EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.example.org"));
+ EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.com"));
+}
+
TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) {
// TODO(rtenneti): Define a helper class/methods and move the common code in
// this file.
@@ -6232,7 +6290,11 @@ class AltSvcFrameTest : public SpdySessionTest {
"alternative.example.org",
443,
86400,
- spdy::SpdyAltSvcWireFormat::VersionVector()) {}
+ spdy::SpdyAltSvcWireFormat::VersionVector()) {
+ // Since the default |alternative_service_| is QUIC, need to enable QUIC for
+ // the not added tests to be meaningful.
+ session_deps_.enable_quic = true;
+ }
void AddSocketData(const spdy::SpdyAltSvcIR& altsvc_ir) {
altsvc_frame_ = spdy_util_.SerializeFrame(altsvc_ir);
@@ -6258,8 +6320,6 @@ class AltSvcFrameTest : public SpdySessionTest {
};
TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) {
- session_deps_.enable_quic = true;
-
const char origin[] = "https://mail.example.org";
spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0);
altsvc_ir.add_altsvc(alternative_service_);
@@ -6290,15 +6350,14 @@ TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) {
// Regression test for https://crbug.com/736063.
TEST_F(AltSvcFrameTest, IgnoreQuicAltSvcWithUnsupportedVersion) {
+ session_deps_.enable_quic = true;
+
+ // Note that this test only uses the legacy Google-specific Alt-Svc format.
const char origin[] = "https://mail.example.org";
spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0);
spdy::SpdyAltSvcWireFormat::AlternativeService quic_alternative_service(
"quic", "alternative.example.org", 443, 86400,
spdy::SpdyAltSvcWireFormat::VersionVector());
- // TODO(zhongyi): spdy::SpdyAltSvcWireFormat::ParseHeaderFieldValue expects
- // positve versions while VersionVector allows nonnegative verisons. Fix the
- // parse function and change the hardcoded invalid version to
- // quic::QUIC_VERSION_UNSUPPORTED.
quic_alternative_service.version.push_back(/* invalid QUIC version */ 1);
altsvc_ir.add_altsvc(quic_alternative_service);
altsvc_ir.set_origin(origin);
@@ -6323,7 +6382,64 @@ TEST_F(AltSvcFrameTest, IgnoreQuicAltSvcWithUnsupportedVersion) {
ASSERT_EQ(0u, altsvc_info_vector.size());
}
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameWithExpectCTError) {
+ const char origin[] = "https://mail.example.org";
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ /* enabled_features */
+ {TransportSecurityState::kDynamicExpectCTFeature,
+ features::kPartitionExpectCTStateByNetworkIsolationKey,
+ features::kPartitionConnectionsByNetworkIsolationKey,
+ features::kPartitionSSLSessionsByNetworkIsolationKey},
+ /* disabled_features */
+ {});
+
+ key_ = SpdySessionKey(HostPortPair::FromURL(test_url_), ProxyServer::Direct(),
+ PRIVACY_MODE_DISABLED,
+ SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+ NetworkIsolationKey::CreateTransient(),
+ false /* disable_secure_dns */);
+ ssl_.ssl_info.ct_policy_compliance =
+ ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ ssl_.ssl_info.is_issued_by_known_root = true;
+
+ // Need to create this after enabling features.
+ session_deps_.transport_security_state =
+ std::make_unique<TransportSecurityState>();
+ session_deps_.transport_security_state->AddExpectCT(
+ GURL(origin).host(),
+ base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true,
+ GURL(), key_.network_isolation_key());
+
+ spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0);
+ altsvc_ir.add_altsvc(alternative_service_);
+ altsvc_ir.set_origin(origin);
+ AddSocketData(altsvc_ir);
+ AddSSLSocketData();
+
+ CreateNetworkSession();
+ CreateSpdySession();
+
+ base::RunLoop().RunUntilIdle();
+
+ const url::SchemeHostPort session_origin("https", test_url_.host(),
+ test_url_.EffectiveIntPort());
+ ASSERT_TRUE(spdy_session_pool_->http_server_properties()
+ ->GetAlternativeServiceInfos(session_origin,
+ key_.network_isolation_key())
+ .empty());
+
+ ASSERT_TRUE(
+ spdy_session_pool_->http_server_properties()
+ ->GetAlternativeServiceInfos(url::SchemeHostPort(GURL(origin)),
+ key_.network_isolation_key())
+ .empty());
+}
+
TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) {
+ session_deps_.enable_quic = true;
+
const char origin[] = "https://invalid.example.org";
spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0);
altsvc_ir.add_altsvc(alternative_service_);
@@ -6394,8 +6510,6 @@ TEST_F(AltSvcFrameTest,
}
TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
- session_deps_.enable_quic = true;
-
spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1);
altsvc_ir.add_altsvc(alternative_service_);
@@ -6453,8 +6567,6 @@ TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
TEST_F(AltSvcFrameTest,
ProcessAltSvcFrameOnActiveStreamWithNetworkIsolationKey) {
- session_deps_.enable_quic = true;
-
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
// enabled_features
@@ -6761,19 +6873,27 @@ TEST(CanPoolTest, CanPool) {
"spdy_pooling.pem");
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "www.example.org"));
+ "www.example.org", "www.example.org",
+ NetworkIsolationKey()));
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.com"));
+ "www.example.org", "mail.example.com",
+ NetworkIsolationKey()));
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.google.com"));
+ "www.example.org", "mail.google.com",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanPoolExpectCT) {
base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- TransportSecurityState::kDynamicExpectCTFeature);
+ feature_list.InitWithFeatures(
+ /* enabled_features */
+ {TransportSecurityState::kDynamicExpectCTFeature,
+ features::kPartitionExpectCTStateByNetworkIsolationKey},
+ /* disabled_features */
+ {});
// Load a cert that is valid for:
// www.example.org
// mail.example.org
@@ -6789,8 +6909,11 @@ TEST(CanPoolTest, CanPoolExpectCT) {
ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
ssl_info.is_issued_by_known_root = true;
+ net::NetworkIsolationKey network_isolation_key =
+ NetworkIsolationKey::CreateTransient();
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "www.example.org"));
+ "www.example.org", "www.example.org",
+ network_isolation_key));
const base::Time current_time(base::Time::Now());
const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
@@ -6798,20 +6921,31 @@ TEST(CanPoolTest, CanPoolExpectCT) {
ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
// A different Expect-CT enabled host should not be allowed to pool.
- tss.AddExpectCT("mail.example.org", expiry, true, GURL());
+ tss.AddExpectCT("mail.example.org", expiry, true, GURL(),
+ network_isolation_key);
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ network_isolation_key));
// A report-only Expect-CT configuration should not prevent pooling.
tss.AddExpectCT("mail.example.org", expiry, false,
- GURL("https://report.test"));
+ GURL("https://report.test"), network_isolation_key);
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ network_isolation_key));
// If Expect-CT becomes enabled for the same host for which the connection was
// already made, subsequent connections to that host should not be allowed to
// pool.
- tss.AddExpectCT("www.example.org", expiry, true, GURL());
+ tss.AddExpectCT("www.example.org", expiry, true, GURL(),
+ network_isolation_key);
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "www.example.org"));
+ "www.example.org", "www.example.org",
+ network_isolation_key));
+
+ // With a different NetworkIsolationKey, CanPool() should still return true,
+ // as CT information is scoped to a single NetworkIsolationKey.
+ EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
+ "www.example.org", "www.example.org",
+ NetworkIsolationKey::CreateTransient()));
}
TEST(CanPoolTest, CanNotPoolWithCertErrors) {
@@ -6828,7 +6962,8 @@ TEST(CanPoolTest, CanNotPoolWithCertErrors) {
ssl_info.cert_status = CERT_STATUS_REVOKED;
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanNotPoolWithClientCerts) {
@@ -6845,7 +6980,8 @@ TEST(CanPoolTest, CanNotPoolWithClientCerts) {
ssl_info.client_cert_sent = true;
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanNotPoolWithBadPins) {
@@ -6862,7 +6998,8 @@ TEST(CanPoolTest, CanNotPoolWithBadPins) {
ssl_info.public_key_hashes.push_back(test::GetTestHashValue(bad_pin));
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "example.test"));
+ "www.example.org", "example.test",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanNotPoolWithBadCTWhenCTRequired) {
@@ -6890,7 +7027,8 @@ TEST(CanPoolTest, CanNotPoolWithBadCTWhenCTRequired) {
tss.SetRequireCTDelegate(&require_ct_delegate);
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanPoolWithBadCTWhenCTNotRequired) {
@@ -6918,7 +7056,8 @@ TEST(CanPoolTest, CanPoolWithBadCTWhenCTNotRequired) {
tss.SetRequireCTDelegate(&require_ct_delegate);
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanPoolWithGoodCTWhenCTRequired) {
@@ -6946,7 +7085,8 @@ TEST(CanPoolTest, CanPoolWithGoodCTWhenCTRequired) {
tss.SetRequireCTDelegate(&require_ct_delegate);
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanPoolWithAcceptablePins) {
@@ -6966,7 +7106,8 @@ TEST(CanPoolTest, CanPoolWithAcceptablePins) {
ssl_info.public_key_hashes.push_back(hash);
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
}
TEST(CanPoolTest, CanPoolWithClientCertsAndPolicy) {
@@ -6986,11 +7127,14 @@ TEST(CanPoolTest, CanPoolWithClientCertsAndPolicy) {
// CanShareConnectionWithClientCerts returns true for both hostnames, but not
// just one hostname.
EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.org"));
+ "www.example.org", "mail.example.org",
+ NetworkIsolationKey()));
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "www.example.org", "mail.example.com"));
+ "www.example.org", "mail.example.com",
+ NetworkIsolationKey()));
EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service,
- "mail.example.com", "www.example.org"));
+ "mail.example.com", "www.example.org",
+ NetworkIsolationKey()));
}
TEST(RecordPushedStreamHistogramTest, VaryResponseHeader) {
diff --git a/chromium/net/spdy/spdy_stream.cc b/chromium/net/spdy/spdy_stream.cc
index ba8ffe66aff..0c28112f6e5 100644
--- a/chromium/net/spdy/spdy_stream.cc
+++ b/chromium/net/spdy/spdy_stream.cc
@@ -35,11 +35,11 @@ namespace {
base::Value NetLogSpdyStreamErrorParams(spdy::SpdyStreamId stream_id,
int net_error,
- const std::string* description) {
+ base::StringPiece description) {
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetIntKey("stream_id", static_cast<int>(stream_id));
dict.SetStringKey("net_error", ErrorToShortString(net_error));
- dict.SetStringKey("description", *description);
+ dict.SetStringKey("description", description);
return dict;
}
@@ -412,6 +412,10 @@ void SpdyStream::OnHeadersReceived(
// in which case it needs to pass through so that the WebSocket layer
// can signal an error.
if (status / 100 == 1 && status != 101) {
+ // Record the timing of the 103 Early Hints response for the experiment
+ // (https://crbug.com/1093693).
+ if (status == 103 && first_early_hints_time_.is_null())
+ first_early_hints_time_ = recv_first_byte_time;
return;
}
@@ -660,9 +664,9 @@ int SpdyStream::OnDataSent(size_t frame_size) {
}
}
-void SpdyStream::LogStreamError(int error, const std::string& description) {
+void SpdyStream::LogStreamError(int error, base::StringPiece description) {
net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, [&] {
- return NetLogSpdyStreamErrorParams(stream_id_, error, &description);
+ return NetLogSpdyStreamErrorParams(stream_id_, error, description);
});
}
@@ -816,6 +820,7 @@ bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
// first bytes of the HEADERS frame were received to BufferedSpdyFramer
// (https://crbug.com/568024).
load_timing_info->receive_headers_start = recv_first_byte_time_;
+ load_timing_info->first_early_hints_time = first_early_hints_time_;
return result;
}
diff --git a/chromium/net/spdy/spdy_stream.h b/chromium/net/spdy/spdy_stream.h
index e9245b01b6f..922c43fefc1 100644
--- a/chromium/net/spdy/spdy_stream.h
+++ b/chromium/net/spdy/spdy_stream.h
@@ -301,7 +301,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
void OnClose(int status);
// Called by the SpdySession to log stream related errors.
- void LogStreamError(int error, const std::string& description);
+ void LogStreamError(int error, base::StringPiece description);
// If this stream is active, reset it, and close it otherwise. In
// either case the stream is deleted.
@@ -515,6 +515,8 @@ class NET_EXPORT_PRIVATE SpdyStream {
base::TimeTicks send_time_;
base::TimeTicks recv_first_byte_time_;
base::TimeTicks recv_last_byte_time_;
+ // The time at which the first 103 Early Hints response is received.
+ base::TimeTicks first_early_hints_time_;
// Number of bytes that have been received on this stream, including frame
// overhead and headers.
diff --git a/chromium/net/spdy/spdy_stream_test_util.cc b/chromium/net/spdy/spdy_stream_test_util.cc
index 8307e999c69..b8309626edb 100644
--- a/chromium/net/spdy/spdy_stream_test_util.cc
+++ b/chromium/net/spdy/spdy_stream_test_util.cc
@@ -83,6 +83,7 @@ void StreamDelegateBase::OnClose(int status) {
if (!stream_.get())
return;
stream_id_ = stream_->stream_id();
+ stream_->GetLoadTimingInfo(&load_timing_info_);
stream_.reset();
callback_.callback().Run(status);
}
@@ -118,6 +119,11 @@ std::string StreamDelegateBase::GetResponseHeaderValue(
: it->second.as_string();
}
+const LoadTimingInfo& StreamDelegateBase::GetLoadTimingInfo() {
+ DCHECK(StreamIsClosed());
+ return load_timing_info_;
+}
+
StreamDelegateDoNothing::StreamDelegateDoNothing(
const base::WeakPtr<SpdyStream>& stream)
: StreamDelegateBase(stream) {}
diff --git a/chromium/net/spdy/spdy_stream_test_util.h b/chromium/net/spdy/spdy_stream_test_util.h
index cb1dd50875d..2453c78bd41 100644
--- a/chromium/net/spdy/spdy_stream_test_util.h
+++ b/chromium/net/spdy/spdy_stream_test_util.h
@@ -12,6 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h"
#include "net/base/io_buffer.h"
+#include "net/base/load_timing_info.h"
#include "net/base/test_completion_callback.h"
#include "net/log/net_log_source.h"
#include "net/spdy/spdy_read_queue.h"
@@ -83,6 +84,10 @@ class StreamDelegateBase : public SpdyStream::Delegate {
std::string GetResponseHeaderValue(const std::string& name) const;
bool send_headers_completed() const { return send_headers_completed_; }
+ // Returns the load timing info on the stream. This must be called after the
+ // stream is closed in order to get the up-to-date information.
+ const LoadTimingInfo& GetLoadTimingInfo();
+
protected:
const base::WeakPtr<SpdyStream>& stream() { return stream_; }
@@ -93,6 +98,7 @@ class StreamDelegateBase : public SpdyStream::Delegate {
bool send_headers_completed_;
spdy::SpdyHeaderBlock response_headers_;
SpdyReadQueue received_data_queue_;
+ LoadTimingInfo load_timing_info_;
};
// Test delegate that does nothing. Used to capture data about the
diff --git a/chromium/net/spdy/spdy_stream_unittest.cc b/chromium/net/spdy/spdy_stream_unittest.cc
index 0f56bcdb5a8..c3fad7a4173 100644
--- a/chromium/net/spdy/spdy_stream_unittest.cc
+++ b/chromium/net/spdy/spdy_stream_unittest.cc
@@ -1084,6 +1084,69 @@ TEST_F(SpdyStreamTest, InformationalHeaders) {
EXPECT_TRUE(data.AllReadDataConsumed());
}
+// 103 Early Hints hasn't been implemented yet, but we collect timing
+// information for the experiment (https://crbug.com/1093693). This tests it.
+TEST_F(SpdyStreamTest, EarlyHints) {
+ spdy::SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
+ AddWrite(req);
+
+ // Serve the early hints.
+ spdy::SpdyHeaderBlock informational_headers;
+ informational_headers[":status"] = "103";
+ spdy::SpdySerializedFrame informational_response(
+ spdy_util_.ConstructSpdyResponseHeaders(
+ 1, std::move(informational_headers), false));
+ AddRead(informational_response);
+
+ spdy::SpdySerializedFrame reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ AddRead(reply);
+
+ spdy::SpdySerializedFrame body(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBodyStringPiece, true));
+ AddRead(body);
+
+ AddReadEOF();
+
+ SequencedSocketData data(GetReads(), GetWrites());
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ data.set_connect_data(connect_data);
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ AddSSLSocketData();
+
+ base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
+
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource());
+ ASSERT_TRUE(stream);
+ EXPECT_EQ(kDefaultUrl, stream->url().spec());
+
+ StreamDelegateDoNothing delegate(stream);
+ stream->SetDelegate(&delegate);
+
+ spdy::SpdyHeaderBlock headers(
+ spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
+ NO_MORE_DATA_TO_SEND));
+
+ EXPECT_THAT(delegate.WaitForClose(), IsOk());
+ EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy::kHttp2StatusHeader));
+ EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
+ delegate.TakeReceivedData());
+
+ // Check if the timing of the early hints response is captured.
+ const LoadTimingInfo& load_timing_info = delegate.GetLoadTimingInfo();
+ EXPECT_FALSE(load_timing_info.first_early_hints_time.is_null());
+
+ // Finish async network reads and writes.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(data.AllWriteDataConsumed());
+ EXPECT_TRUE(data.AllReadDataConsumed());
+}
+
TEST_F(SpdyStreamTest, StatusMustBeNumber) {
spdy::SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));