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_