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 @@ ...@@ -5,6 +5,7 @@
#include "net/quic/quic_transport_client.h" #include "net/quic/quic_transport_client.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/proxy_resolution/proxy_resolution_request.h" #include "net/proxy_resolution/proxy_resolution_request.h"
...@@ -58,9 +59,6 @@ std::unique_ptr<quic::ProofVerifier> CreateProofVerifier( ...@@ -58,9 +59,6 @@ std::unique_ptr<quic::ProofVerifier> CreateProofVerifier(
} }
} // namespace } // namespace
constexpr quic::ParsedQuicVersion
QuicTransportClient::kQuicVersionForOriginTrial;
QuicTransportClient::Parameters::Parameters() = default; QuicTransportClient::Parameters::Parameters() = default;
QuicTransportClient::Parameters::~Parameters() = default; QuicTransportClient::Parameters::~Parameters() = default;
...@@ -168,13 +166,13 @@ int QuicTransportClient::DoInit() { ...@@ -168,13 +166,13 @@ int QuicTransportClient::DoInit() {
// Ensure that for the duration of the origin trial, a fixed QUIC transport // Ensure that for the duration of the origin trial, a fixed QUIC transport
// version is available. // version is available.
supported_versions_.push_back(kQuicVersionForOriginTrial); supported_versions_ = QuicVersionsForWebTransportOriginTrial();
// Add other supported versions if available. // Add other supported versions if available.
for (quic::ParsedQuicVersion& version : for (quic::ParsedQuicVersion& version :
quic_context_->params()->supported_versions) { quic_context_->params()->supported_versions) {
if (!quic::IsVersionValidForQuicTransport(version)) if (!quic::IsVersionValidForQuicTransport(version))
continue; continue;
if (version == kQuicVersionForOriginTrial) if (base::Contains(supported_versions_, version))
continue; // Skip as we've already added it above. continue; // Skip as we've already added it above.
supported_versions_.push_back(version); supported_versions_.push_back(version);
} }
...@@ -256,6 +254,20 @@ int QuicTransportClient::DoConnect() { ...@@ -256,6 +254,20 @@ int QuicTransportClient::DoConnect() {
if (rv != OK) if (rv != OK)
return rv; 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::QuicConnectionId connection_id =
quic::QuicUtils::CreateRandomConnectionId( quic::QuicUtils::CreateRandomConnectionId(
quic_context_->random_generator()); quic_context_->random_generator());
...@@ -280,9 +292,6 @@ int QuicTransportClient::DoConnect() { ...@@ -280,9 +292,6 @@ int QuicTransportClient::DoConnect() {
session_->Initialize(); session_->Initialize();
packet_reader_->StartReading(); packet_reader_->StartReading();
session_->CryptoConnect(); session_->CryptoConnect();
next_connect_state_ = CONNECT_STATE_CONFIRM_CONNECTION;
return ERR_IO_PENDING;
} }
int QuicTransportClient::DoConfirmConnection() { int QuicTransportClient::DoConfirmConnection() {
...@@ -414,6 +423,26 @@ void QuicTransportClient::OnConnectionClosed( ...@@ -414,6 +423,26 @@ void QuicTransportClient::OnConnectionClosed(
quic::QuicErrorCode error, quic::QuicErrorCode error,
const std::string& error_details, const std::string& error_details,
quic::ConnectionCloseSource source) { 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; std::string histogram_name;
switch (source) { switch (source) {
case quic::ConnectionCloseSource::FROM_SELF: case quic::ConnectionCloseSource::FROM_SELF:
......
...@@ -93,9 +93,14 @@ class NET_EXPORT QuicTransportClient ...@@ -93,9 +93,14 @@ class NET_EXPORT QuicTransportClient
std::vector<quic::CertificateFingerprint> server_certificate_fingerprints; std::vector<quic::CertificateFingerprint> server_certificate_fingerprints;
}; };
// QUIC protocol version that is used in the origin trial. // QUIC protocol versions that are used in the origin trial.
static constexpr quic::ParsedQuicVersion kQuicVersionForOriginTrial = static quic::ParsedQuicVersionVector
quic::ParsedQuicVersion::Draft27(); QuicVersionsForWebTransportOriginTrial() {
return quic::ParsedQuicVersionVector{
quic::ParsedQuicVersion::Draft29(), // Enabled in M85.
quic::ParsedQuicVersion::Draft27() // Enabled in M84.
};
}
// |visitor| and |context| must outlive this object. // |visitor| and |context| must outlive this object.
QuicTransportClient(const GURL& url, QuicTransportClient(const GURL& url,
...@@ -180,6 +185,7 @@ class NET_EXPORT QuicTransportClient ...@@ -180,6 +185,7 @@ class NET_EXPORT QuicTransportClient
int DoResolveHostComplete(int rv); int DoResolveHostComplete(int rv);
// Establishes the QUIC connection. // Establishes the QUIC connection.
int DoConnect(); int DoConnect();
void CreateConnection();
// Verifies that the connection has succeeded. // Verifies that the connection has succeeded.
int DoConfirmConnection(); int DoConfirmConnection();
...@@ -204,6 +210,7 @@ class NET_EXPORT QuicTransportClient ...@@ -204,6 +210,7 @@ class NET_EXPORT QuicTransportClient
State state_ = NEW; State state_ = NEW;
ConnectState next_connect_state_ = CONNECT_STATE_NONE; ConnectState next_connect_state_ = CONNECT_STATE_NONE;
QuicTransportError error_; QuicTransportError error_;
bool retried_with_new_version_ = false;
ProxyInfo proxy_info_; ProxyInfo proxy_info_;
std::unique_ptr<ProxyResolutionRequest> proxy_resolution_request_; std::unique_ptr<ProxyResolutionRequest> proxy_resolution_request_;
......
...@@ -76,7 +76,8 @@ class TestConnectionHelper : public quic::QuicConnectionHelperInterface { ...@@ -76,7 +76,8 @@ class TestConnectionHelper : public quic::QuicConnectionHelperInterface {
class QuicTransportEndToEndTest : public TestWithTaskEnvironment { class QuicTransportEndToEndTest : public TestWithTaskEnvironment {
public: public:
QuicTransportEndToEndTest() { QuicTransportEndToEndTest() {
quic::QuicEnableVersion(QuicTransportClient::kQuicVersionForOriginTrial); quic::QuicEnableVersion(
QuicTransportClient::QuicVersionsForWebTransportOriginTrial()[0]);
origin_ = url::Origin::Create(GURL{"https://example.org"}); origin_ = url::Origin::Create(GURL{"https://example.org"});
isolation_key_ = NetworkIsolationKey(origin_, origin_); isolation_key_ = NetworkIsolationKey(origin_, origin_);
...@@ -263,6 +264,35 @@ TEST_F(QuicTransportEndToEndTest, CertificateFingerprintMismatch) { ...@@ -263,6 +264,35 @@ TEST_F(QuicTransportEndToEndTest, CertificateFingerprintMismatch) {
EXPECT_EQ(client_->error().quic_error, quic::QUIC_HANDSHAKE_FAILED); 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
} // namespace test } // namespace test
} // namespace net } // 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