blob: f73837182c01d63622d75c1d3e1b78ff20143a3d [file] [log] [blame]
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h"
#include <cstdint>
#include <limits>
#include <memory>
#include <utility>
#include "url/gurl.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
namespace quic {
namespace {
// ProofHandler is primarily used by QUIC crypto to persist QUIC server configs
// and perform some of related debug logging. QuicTransport does not support
// QUIC crypto, so those methods are not called.
class DummyProofHandler : public QuicCryptoClientStream::ProofHandler {
public:
void OnProofValid(
const QuicCryptoClientConfig::CachedState& /*cached*/) override {}
void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& /*verify_details*/) override {}
};
} // namespace
QuicTransportClientSession::QuicTransportClientSession(
QuicConnection* connection,
Visitor* owner,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config,
url::Origin origin,
ClientVisitor* visitor)
: QuicSession(connection,
owner,
config,
supported_versions,
/*num_expected_unidirectional_static_streams*/ 0),
origin_(origin),
visitor_(visitor) {
for (const ParsedQuicVersion& version : supported_versions) {
QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3)
<< "QuicTransport requires TLS 1.3 handshake";
}
// ProofHandler API is not used by TLS 1.3.
static DummyProofHandler* proof_handler = new DummyProofHandler();
crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
server_id, this, crypto_config->proof_verifier()->CreateDefaultContext(),
crypto_config, proof_handler);
}
QuicStream* QuicTransportClientSession::CreateIncomingStream(QuicStreamId id) {
QUIC_DVLOG(1) << "Creating incoming QuicTransport stream " << id;
auto stream = std::make_unique<QuicTransportStream>(id, this, this);
QuicTransportStream* stream_ptr = stream.get();
ActivateStream(std::move(stream));
if (stream_ptr->type() == BIDIRECTIONAL) {
incoming_bidirectional_streams_.push_back(stream_ptr);
visitor_->OnIncomingBidirectionalStreamAvailable();
} else {
incoming_unidirectional_streams_.push_back(stream_ptr);
visitor_->OnIncomingUnidirectionalStreamAvailable();
}
return stream_ptr;
}
void QuicTransportClientSession::OnCryptoHandshakeEvent(
CryptoHandshakeEvent event) {
QuicSession::OnCryptoHandshakeEvent(event);
if (event != HANDSHAKE_CONFIRMED) {
return;
}
SendClientIndication();
}
QuicTransportStream*
QuicTransportClientSession::AcceptIncomingBidirectionalStream() {
if (incoming_bidirectional_streams_.empty()) {
return nullptr;
}
QuicTransportStream* stream = incoming_bidirectional_streams_.front();
incoming_bidirectional_streams_.pop_front();
return stream;
}
QuicTransportStream*
QuicTransportClientSession::AcceptIncomingUnidirectionalStream() {
if (incoming_unidirectional_streams_.empty()) {
return nullptr;
}
QuicTransportStream* stream = incoming_unidirectional_streams_.front();
incoming_unidirectional_streams_.pop_front();
return stream;
}
std::string QuicTransportClientSession::SerializeClientIndication() {
std::string serialized_origin = origin_.Serialize();
if (serialized_origin.size() > std::numeric_limits<uint16_t>::max()) {
QUIC_BUG << "Client origin too long";
connection()->CloseConnection(
QUIC_INTERNAL_ERROR, "Client origin too long",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return "";
}
QUIC_DLOG(INFO) << "Sending client indication with origin "
<< serialized_origin;
std::string buffer;
buffer.resize(/* key */ sizeof(QuicTransportClientIndicationKeys) +
/* length */ sizeof(uint16_t) + serialized_origin.size());
QuicDataWriter writer(buffer.size(), &buffer[0]);
writer.WriteUInt16(
static_cast<uint16_t>(QuicTransportClientIndicationKeys::kOrigin));
writer.WriteUInt16(serialized_origin.size());
writer.WriteStringPiece(serialized_origin);
buffer.resize(writer.length());
return buffer;
}
void QuicTransportClientSession::SendClientIndication() {
if (!crypto_stream_->encryption_established()) {
QUIC_BUG << "Client indication may only be sent once the encryption is "
"established.";
connection()->CloseConnection(
QUIC_INTERNAL_ERROR, "Attempted to send client indication unencrypted",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
if (ready_) {
QUIC_BUG << "Client indication may only be sent once.";
connection()->CloseConnection(
QUIC_INTERNAL_ERROR, "Attempted to send client indication twice",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
auto client_indication_owned = std::make_unique<ClientIndication>(
/*stream_id=*/ClientIndicationStream(), this, /*is_static=*/false,
WRITE_UNIDIRECTIONAL);
ClientIndication* client_indication = client_indication_owned.get();
ActivateStream(std::move(client_indication_owned));
client_indication->WriteOrBufferData(SerializeClientIndication(),
/*fin=*/true, nullptr);
client_indication_sent_ = true;
// Don't set the ready bit if we closed the connection due to any error
// beforehand.
if (!connection()->connected()) {
return;
}
ready_ = true;
}
} // namespace quic