Commit b944c280 authored by Victor Vasiliev's avatar Victor Vasiliev Committed by Commit Bot

Support version negotiation in QuicTransport.

This adds support for QUIC draft29 into QuicTransport, and the machinery
required to use more than one version at a time.

Bug: 1011392
Change-Id: I99e4906a5e0ddd2ef04f7eb238b634e993075845
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2246071
Commit-Queue: Victor Vasiliev <vasilvv@chromium.org>
Reviewed-by: default avatarDavid Schinazi <dschinazi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#778614}
parent 52d225d7
......@@ -5,6 +5,7 @@
#include "net/quic/quic_transport_client.h"
#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/proxy_resolution/proxy_resolution_request.h"
......@@ -58,9 +59,6 @@ std::unique_ptr<quic::ProofVerifier> CreateProofVerifier(
}
} // namespace
constexpr quic::ParsedQuicVersion
QuicTransportClient::kQuicVersionForOriginTrial;
QuicTransportClient::Parameters::Parameters() = default;
QuicTransportClient::Parameters::~Parameters() = default;
......@@ -168,13 +166,13 @@ int QuicTransportClient::DoInit() {
// Ensure that for the duration of the origin trial, a fixed QUIC transport
// version is available.
supported_versions_.push_back(kQuicVersionForOriginTrial);
supported_versions_ = QuicVersionsForWebTransportOriginTrial();
// Add other supported versions if available.
for (quic::ParsedQuicVersion& version :
quic_context_->params()->supported_versions) {
if (!quic::IsVersionValidForQuicTransport(version))
continue;
if (version == kQuicVersionForOriginTrial)
if (base::Contains(supported_versions_, version))
continue; // Skip as we've already added it above.
supported_versions_.push_back(version);
}
......@@ -256,6 +254,20 @@ int QuicTransportClient::DoConnect() {
if (rv != OK)
return rv;
CreateConnection();
next_connect_state_ = CONNECT_STATE_CONFIRM_CONNECTION;
return ERR_IO_PENDING;
}
void QuicTransportClient::CreateConnection() {
// Delete the objects in the same order they would be normally deleted by the
// destructor.
packet_reader_ = nullptr;
session_ = nullptr;
connection_ = nullptr;
IPEndPoint server_address =
*resolve_host_request_->GetAddressResults()->begin();
quic::QuicConnectionId connection_id =
quic::QuicUtils::CreateRandomConnectionId(
quic_context_->random_generator());
......@@ -280,9 +292,6 @@ int QuicTransportClient::DoConnect() {
session_->Initialize();
packet_reader_->StartReading();
session_->CryptoConnect();
next_connect_state_ = CONNECT_STATE_CONFIRM_CONNECTION;
return ERR_IO_PENDING;
}
int QuicTransportClient::DoConfirmConnection() {
......@@ -414,6 +423,26 @@ void QuicTransportClient::OnConnectionClosed(
quic::QuicErrorCode error,
const std::string& error_details,
quic::ConnectionCloseSource source) {
if (!retried_with_new_version_ &&
session_->error() == quic::QUIC_INVALID_VERSION) {
retried_with_new_version_ = true;
base::EraseIf(
supported_versions_, [this](const quic::ParsedQuicVersion& version) {
return !base::Contains(
session_->connection()->server_supported_versions(), version);
});
if (!supported_versions_.empty()) {
// Since this is a callback from QuicConnection, we can't replace the
// connection object in this method; do it from the top of the event loop
// instead.
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&QuicTransportClient::CreateConnection,
weak_factory_.GetWeakPtr()));
return;
}
// If there are no supported versions, treat this as a regular error.
}
std::string histogram_name;
switch (source) {
case quic::ConnectionCloseSource::FROM_SELF:
......
......@@ -93,9 +93,14 @@ class NET_EXPORT QuicTransportClient
std::vector<quic::CertificateFingerprint> server_certificate_fingerprints;
};
// QUIC protocol version that is used in the origin trial.
static constexpr quic::ParsedQuicVersion kQuicVersionForOriginTrial =
quic::ParsedQuicVersion::Draft27();
// QUIC protocol versions that are used in the origin trial.
static quic::ParsedQuicVersionVector
QuicVersionsForWebTransportOriginTrial() {
return quic::ParsedQuicVersionVector{
quic::ParsedQuicVersion::Draft29(), // Enabled in M85.
quic::ParsedQuicVersion::Draft27() // Enabled in M84.
};
}
// |visitor| and |context| must outlive this object.
QuicTransportClient(const GURL& url,
......@@ -180,6 +185,7 @@ class NET_EXPORT QuicTransportClient
int DoResolveHostComplete(int rv);
// Establishes the QUIC connection.
int DoConnect();
void CreateConnection();
// Verifies that the connection has succeeded.
int DoConfirmConnection();
......@@ -204,6 +210,7 @@ class NET_EXPORT QuicTransportClient
State state_ = NEW;
ConnectState next_connect_state_ = CONNECT_STATE_NONE;
QuicTransportError error_;
bool retried_with_new_version_ = false;
ProxyInfo proxy_info_;
std::unique_ptr<ProxyResolutionRequest> proxy_resolution_request_;
......
......@@ -76,7 +76,8 @@ class TestConnectionHelper : public quic::QuicConnectionHelperInterface {
class QuicTransportEndToEndTest : public TestWithTaskEnvironment {
public:
QuicTransportEndToEndTest() {
quic::QuicEnableVersion(QuicTransportClient::kQuicVersionForOriginTrial);
quic::QuicEnableVersion(
QuicTransportClient::QuicVersionsForWebTransportOriginTrial()[0]);
origin_ = url::Origin::Create(GURL{"https://example.org"});
isolation_key_ = NetworkIsolationKey(origin_, origin_);
......@@ -263,6 +264,35 @@ TEST_F(QuicTransportEndToEndTest, CertificateFingerprintMismatch) {
EXPECT_EQ(client_->error().quic_error, quic::QUIC_HANDSHAKE_FAILED);
}
TEST_F(QuicTransportEndToEndTest, OldVersion) {
SetQuicReloadableFlag(quic_enable_version_draft_29, false);
SetQuicReloadableFlag(quic_enable_version_draft_27, true);
StartServer();
client_ = std::make_unique<QuicTransportClient>(
GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get(),
QuicTransportClient::Parameters());
client_->Connect();
EXPECT_CALL(visitor_, OnConnected()).WillOnce(StopRunning());
Run();
ASSERT_TRUE(client_->session() != nullptr);
EXPECT_TRUE(client_->session()->IsSessionReady());
}
TEST_F(QuicTransportEndToEndTest, NoCommonVersion) {
SetQuicReloadableFlag(quic_enable_version_draft_29, false);
SetQuicReloadableFlag(quic_enable_version_draft_27, false);
StartServer();
client_ = std::make_unique<QuicTransportClient>(
GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get(),
QuicTransportClient::Parameters());
client_->Connect();
EXPECT_CALL(visitor_, OnConnectionFailed()).WillOnce(StopRunning());
Run();
EXPECT_TRUE(client_->session() == nullptr);
EXPECT_EQ(client_->error().quic_error, quic::QUIC_INVALID_VERSION);
}
} // namespace
} // namespace test
} // namespace net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment