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