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_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