Implement the QuicTransport server session subclass.
This currently does not handle incoming streams, as those require special logic to prevent access to application data before the indication is received.
gfe-relnote: n/a (not used in production)
PiperOrigin-RevId: 274228824
Change-Id: Ie1cd37ecfb739d1242a3cdc40186bca00f8373fd
diff --git a/quic/quic_transport/quic_transport_server_session.cc b/quic/quic_transport/quic_transport_server_session.cc
new file mode 100644
index 0000000..de4db0f
--- /dev/null
+++ b/quic/quic_transport/quic_transport_server_session.cc
@@ -0,0 +1,164 @@
+// 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_server_session.h"
+
+#include <memory>
+
+#include "url/gurl.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h"
+
+namespace quic {
+
+namespace {
+class QuicTransportServerCryptoHelper : public QuicCryptoServerStream::Helper {
+ public:
+ bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/,
+ const QuicSocketAddress& /*client_address*/,
+ const QuicSocketAddress& /*peer_address*/,
+ const QuicSocketAddress& /*self_address*/,
+ std::string* /*error_details*/) const override {
+ return true;
+ }
+};
+} // namespace
+
+QuicTransportServerSession::QuicTransportServerSession(
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ ServerVisitor* visitor)
+ : QuicSession(connection,
+ owner,
+ config,
+ supported_versions,
+ /*num_expected_unidirectional_static_streams*/ 0),
+ visitor_(visitor) {
+ for (const ParsedQuicVersion& version : supported_versions) {
+ QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3)
+ << "QuicTransport requires TLS 1.3 handshake";
+ }
+
+ static QuicTransportServerCryptoHelper* helper =
+ new QuicTransportServerCryptoHelper();
+ crypto_stream_ = std::make_unique<QuicCryptoServerStream>(
+ crypto_config, compressed_certs_cache, this, helper);
+}
+
+QuicStream* QuicTransportServerSession::CreateIncomingStream(QuicStreamId id) {
+ if (id == ClientIndicationStream()) {
+ auto indication = std::make_unique<ClientIndication>(this);
+ ClientIndication* indication_ptr = indication.get();
+ ActivateStream(std::move(indication));
+ return indication_ptr;
+ }
+
+ // TODO(vasilvv): implement incoming data streams.
+ QUIC_BUG << "Not implemented";
+ return nullptr;
+}
+
+QuicTransportServerSession::ClientIndication::ClientIndication(
+ QuicTransportServerSession* session)
+ : QuicStream(ClientIndicationStream(),
+ session,
+ /* is_static= */ false,
+ StreamType::READ_UNIDIRECTIONAL),
+ session_(session) {}
+
+void QuicTransportServerSession::ClientIndication::OnDataAvailable() {
+ sequencer()->Read(&buffer_);
+ if (buffer_.size() > ClientIndicationMaxSize()) {
+ session_->connection()->CloseConnection(
+ QUIC_TRANSPORT_INVALID_CLIENT_INDICATION,
+ QuicStrCat("Client indication size exceeds ", ClientIndicationMaxSize(),
+ " bytes"),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ if (sequencer()->IsClosed()) {
+ session_->ProcessClientIndication(buffer_);
+ OnFinRead();
+ }
+}
+
+bool QuicTransportServerSession::ClientIndicationParser::Parse() {
+ bool origin_received = false;
+ while (!reader_.IsDoneReading()) {
+ uint16_t key;
+ if (!reader_.ReadUInt16(&key)) {
+ ParseError("Expected 16-bit key");
+ return false;
+ }
+
+ QuicStringPiece value;
+ if (!reader_.ReadStringPiece16(&value)) {
+ ParseError(QuicStrCat("Failed to read value for key ", key));
+ return false;
+ }
+
+ switch (static_cast<QuicTransportClientIndicationKeys>(key)) {
+ case QuicTransportClientIndicationKeys::kOrigin: {
+ GURL origin_url{std::string(value)};
+ if (!origin_url.is_valid()) {
+ Error("Unable to parse the specified origin");
+ return false;
+ }
+
+ url::Origin origin = url::Origin::Create(origin_url);
+ QUIC_DLOG(INFO) << "QuicTransport server received origin " << origin;
+ if (!session_->visitor_->CheckOrigin(origin)) {
+ Error("Origin check failed");
+ return false;
+ }
+ origin_received = true;
+ break;
+ }
+
+ default:
+ QUIC_DLOG(INFO) << "Unknown client indication key: " << key;
+ break;
+ }
+ }
+
+ if (!origin_received) {
+ Error("No origin received");
+ return false;
+ }
+
+ return true;
+}
+
+void QuicTransportServerSession::ClientIndicationParser::Error(
+ const std::string& error_message) {
+ session_->connection()->CloseConnection(
+ QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, error_message,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
+void QuicTransportServerSession::ClientIndicationParser::ParseError(
+ QuicStringPiece error_message) {
+ Error(QuicStrCat("Failed to parse the client indication stream: ",
+ error_message, reader_.DebugString()));
+}
+
+void QuicTransportServerSession::ProcessClientIndication(
+ QuicStringPiece indication) {
+ ClientIndicationParser parser(this, indication);
+ if (!parser.Parse()) {
+ return;
+ }
+ client_indication_processed_ = true;
+}
+
+} // namespace quic