Add a simple QuicTransport server for testing and demo purposes.

The server currently has two modes, echo and discard.  I've changed the integration test to use the simple server instead of a session with a mock visitor.

This CL also adds some of the missing APIs and fixes some of the bugs I've found while doing this.

gfe-relnote: n/a (code not used)
PiperOrigin-RevId: 278456752
Change-Id: Idf9aa654aa0d66673f300f2f5425f0716d6c3e14
diff --git a/quic/tools/quic_transport_simple_server_dispatcher.cc b/quic/tools/quic_transport_simple_server_dispatcher.cc
new file mode 100644
index 0000000..da9899f
--- /dev/null
+++ b/quic/tools/quic_transport_simple_server_dispatcher.cc
@@ -0,0 +1,52 @@
+// 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/tools/quic_transport_simple_server_dispatcher.h"
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.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/tools/quic_transport_simple_server_session.h"
+
+namespace quic {
+
+QuicTransportSimpleServerDispatcher::QuicTransportSimpleServerDispatcher(
+    const QuicConfig* config,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicVersionManager* version_manager,
+    std::unique_ptr<QuicConnectionHelperInterface> helper,
+    std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+    std::unique_ptr<QuicAlarmFactory> alarm_factory,
+    uint8_t expected_server_connection_id_length,
+    QuicTransportSimpleServerSession::Mode mode,
+    std::vector<url::Origin> accepted_origins)
+    : QuicDispatcher(config,
+                     crypto_config,
+                     version_manager,
+                     std::move(helper),
+                     std::move(session_helper),
+                     std::move(alarm_factory),
+                     expected_server_connection_id_length),
+      mode_(mode),
+      accepted_origins_(accepted_origins) {}
+
+QuicSession* QuicTransportSimpleServerDispatcher::CreateQuicSession(
+    QuicConnectionId server_connection_id,
+    const QuicSocketAddress& peer_address,
+    QuicStringPiece /*alpn*/,
+    const ParsedQuicVersion& version) {
+  auto connection = std::make_unique<QuicConnection>(
+      server_connection_id, peer_address, helper(), alarm_factory(), writer(),
+      /*owns_writer=*/false, Perspective::IS_SERVER,
+      ParsedQuicVersionVector{version});
+  return new QuicTransportSimpleServerSession(
+      connection.release(), /*owns_connection=*/true, this, config(),
+      GetSupportedVersions(), crypto_config(), compressed_certs_cache(), mode_,
+      accepted_origins_);
+}
+
+}  // namespace quic
diff --git a/quic/tools/quic_transport_simple_server_dispatcher.h b/quic/tools/quic_transport_simple_server_dispatcher.h
new file mode 100644
index 0000000..ea4eb8b
--- /dev/null
+++ b/quic/tools/quic_transport_simple_server_dispatcher.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_
+#define QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_
+
+#include "url/origin.h"
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h"
+
+namespace quic {
+
+// Dispatcher that creates a QuicTransportSimpleServerSession for every incoming
+// connection.
+class QuicTransportSimpleServerDispatcher : public QuicDispatcher {
+ public:
+  QuicTransportSimpleServerDispatcher(
+      const QuicConfig* config,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicVersionManager* version_manager,
+      std::unique_ptr<QuicConnectionHelperInterface> helper,
+      std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+      std::unique_ptr<QuicAlarmFactory> alarm_factory,
+      uint8_t expected_server_connection_id_length,
+      QuicTransportSimpleServerSession::Mode mode,
+      std::vector<url::Origin> accepted_origins);
+
+ protected:
+  QuicSession* CreateQuicSession(QuicConnectionId server_connection_id,
+                                 const QuicSocketAddress& peer_address,
+                                 QuicStringPiece alpn,
+                                 const ParsedQuicVersion& version) override;
+
+  QuicTransportSimpleServerSession::Mode mode_;
+  std::vector<url::Origin> accepted_origins_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_
diff --git a/quic/tools/quic_transport_simple_server_session.cc b/quic/tools/quic_transport_simple_server_session.cc
new file mode 100644
index 0000000..273a9ae
--- /dev/null
+++ b/quic/tools/quic_transport_simple_server_session.cc
@@ -0,0 +1,228 @@
+// 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/tools/quic_transport_simple_server_session.h"
+
+#include <memory>
+
+#include "url/gurl.h"
+#include "url/origin.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_flags.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_protocol.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
+
+namespace quic {
+
+namespace {
+
+// Discards any incoming data.
+class DiscardVisitor : public QuicTransportStream::Visitor {
+ public:
+  DiscardVisitor(QuicTransportStream* stream) : stream_(stream) {}
+
+  void OnCanRead() override {
+    std::string buffer;
+    size_t bytes_read = stream_->Read(&buffer);
+    QUIC_DVLOG(2) << "Read " << bytes_read << " bytes from stream "
+                  << stream_->id();
+  }
+
+  void OnFinRead() override {}
+  void OnCanWrite() override {}
+
+ private:
+  QuicTransportStream* stream_;
+};
+
+// Echoes any incoming data back on the same stream.
+class BidirectionalEchoVisitor : public QuicTransportStream::Visitor {
+ public:
+  BidirectionalEchoVisitor(QuicTransportStream* stream) : stream_(stream) {}
+
+  void OnCanRead() override {
+    stream_->Read(&buffer_);
+    OnCanWrite();
+  }
+
+  void OnFinRead() override {
+    bool success = stream_->SendFin();
+    DCHECK(success);
+  }
+
+  void OnCanWrite() override {
+    if (buffer_.empty()) {
+      return;
+    }
+
+    bool success = stream_->Write(buffer_);
+    if (success) {
+      buffer_ = "";
+    }
+  }
+
+ private:
+  QuicTransportStream* stream_;
+  std::string buffer_;
+};
+
+// Buffers all of the data and calls EchoStreamBack() on the parent session.
+class UnidirectionalEchoReadVisitor : public QuicTransportStream::Visitor {
+ public:
+  UnidirectionalEchoReadVisitor(QuicTransportSimpleServerSession* session,
+                                QuicTransportStream* stream)
+      : session_(session), stream_(stream) {}
+
+  void OnCanRead() override {
+    bool success = stream_->Read(&buffer_);
+    DCHECK(success);
+  }
+
+  void OnFinRead() override {
+    QUIC_DVLOG(1) << "Finished receiving data on stream " << stream_->id()
+                  << ", queueing up the echo";
+    session_->EchoStreamBack(buffer_);
+  }
+
+  void OnCanWrite() override { QUIC_NOTREACHED(); }
+
+ private:
+  QuicTransportSimpleServerSession* session_;
+  QuicTransportStream* stream_;
+  std::string buffer_;
+};
+
+// Sends supplied data.
+class UnidirectionalEchoWriteVisitor : public QuicTransportStream::Visitor {
+ public:
+  UnidirectionalEchoWriteVisitor(QuicTransportStream* stream,
+                                 const std::string& data)
+      : stream_(stream), data_(data) {}
+
+  void OnCanRead() override { QUIC_NOTREACHED(); }
+  void OnFinRead() override { QUIC_NOTREACHED(); }
+  void OnCanWrite() override {
+    if (data_.empty()) {
+      return;
+    }
+    if (!stream_->Write(data_)) {
+      return;
+    }
+    data_ = "";
+    bool fin_sent = stream_->SendFin();
+    DCHECK(fin_sent);
+  }
+
+ private:
+  QuicTransportStream* stream_;
+  std::string data_;
+};
+
+}  // namespace
+
+QuicTransportSimpleServerSession::QuicTransportSimpleServerSession(
+    QuicConnection* connection,
+    bool owns_connection,
+    Visitor* owner,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicCompressedCertsCache* compressed_certs_cache,
+    Mode mode,
+    std::vector<url::Origin> accepted_origins)
+    : QuicTransportServerSession(connection,
+                                 owner,
+                                 config,
+                                 supported_versions,
+                                 crypto_config,
+                                 compressed_certs_cache,
+                                 this),
+      connection_(connection),
+      owns_connection_(owns_connection),
+      mode_(mode),
+      accepted_origins_(accepted_origins) {
+  Initialize();
+}
+
+QuicTransportSimpleServerSession::~QuicTransportSimpleServerSession() {
+  if (owns_connection_) {
+    delete connection_;
+  }
+}
+
+void QuicTransportSimpleServerSession::OnIncomingDataStream(
+    QuicTransportStream* stream) {
+  switch (mode_) {
+    case DISCARD:
+      stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
+      break;
+
+    case ECHO:
+      switch (stream->type()) {
+        case BIDIRECTIONAL:
+          QUIC_DVLOG(1) << "Opening bidirectional echo stream " << stream->id();
+          stream->set_visitor(
+              std::make_unique<BidirectionalEchoVisitor>(stream));
+          break;
+        case READ_UNIDIRECTIONAL:
+          QUIC_DVLOG(1)
+              << "Started receiving data on unidirectional echo stream "
+              << stream->id();
+          stream->set_visitor(
+              std::make_unique<UnidirectionalEchoReadVisitor>(this, stream));
+          break;
+        default:
+          QUIC_NOTREACHED();
+          break;
+      }
+      break;
+  }
+}
+
+void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream(
+    bool unidirectional) {
+  if (mode_ == ECHO && unidirectional) {
+    MaybeEchoStreamsBack();
+  }
+}
+
+bool QuicTransportSimpleServerSession::CheckOrigin(url::Origin origin) {
+  if (accepted_origins_.empty()) {
+    return true;
+  }
+
+  for (const url::Origin& accepted_origin : accepted_origins_) {
+    if (origin.IsSameOriginWith(accepted_origin)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() {
+  while (!streams_to_echo_back_.empty() &&
+         CanOpenNextOutgoingUnidirectionalStream()) {
+    // Remove the stream from the queue first, in order to avoid accidentally
+    // entering an infinite loop in case any of the following code calls
+    // OnCanCreateNewOutgoingStream().
+    std::string data = std::move(streams_to_echo_back_.front());
+    streams_to_echo_back_.pop_front();
+
+    auto stream_owned = std::make_unique<QuicTransportStream>(
+        GetNextOutgoingUnidirectionalStreamId(), this, this);
+    QuicTransportStream* stream = stream_owned.get();
+    ActivateStream(std::move(stream_owned));
+    QUIC_DVLOG(1) << "Opened echo response stream " << stream->id();
+
+    stream->set_visitor(
+        std::make_unique<UnidirectionalEchoWriteVisitor>(stream, data));
+    stream->visitor()->OnCanWrite();
+  }
+}
+
+}  // namespace quic
diff --git a/quic/tools/quic_transport_simple_server_session.h b/quic/tools/quic_transport_simple_server_session.h
new file mode 100644
index 0000000..11f82f2
--- /dev/null
+++ b/quic/tools/quic_transport_simple_server_session.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_
+#define QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_
+
+#include <memory>
+#include <vector>
+
+#include "url/origin.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_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
+
+namespace quic {
+
+// QuicTransport simple server is a non-production server that can be used for
+// testing QuicTransport.  It has two modes that can be changed using the
+// command line flags, "echo" and "discard".
+class QuicTransportSimpleServerSession
+    : public QuicTransportServerSession,
+      QuicTransportServerSession::ServerVisitor {
+ public:
+  enum Mode {
+    // In DISCARD mode, any data on incoming streams is discarded and no
+    // outgoing streams are initiated.
+    DISCARD,
+    // In ECHO mode, any data sent on a bidirectional stream is echoed back.
+    // Any data sent on a unidirectional stream is buffered, and echoed back on
+    // a server-initiated unidirectional stream that is sent as soon as a FIN is
+    // received on the incoming stream.
+    ECHO,
+  };
+
+  QuicTransportSimpleServerSession(
+      QuicConnection* connection,
+      bool owns_connection,
+      Visitor* owner,
+      const QuicConfig& config,
+      const ParsedQuicVersionVector& supported_versions,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicCompressedCertsCache* compressed_certs_cache,
+      Mode mode,
+      std::vector<url::Origin> accepted_origins);
+  ~QuicTransportSimpleServerSession();
+
+  void OnIncomingDataStream(QuicTransportStream* stream) override;
+  void OnCanCreateNewOutgoingStream(bool unidirectional) override;
+  bool CheckOrigin(url::Origin origin) override;
+
+  void EchoStreamBack(const std::string& data) {
+    streams_to_echo_back_.push_back(data);
+    MaybeEchoStreamsBack();
+  }
+
+ private:
+  void MaybeEchoStreamsBack();
+
+  QuicConnection* connection_;
+  const bool owns_connection_;
+  Mode mode_;
+  std::vector<url::Origin> accepted_origins_;
+  QuicDeque<std::string> streams_to_echo_back_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_