blob: e348750a474d724a2ec2247d9fe145335d49f762 [file] [log] [blame]
vasilvv316f3762021-03-31 13:49:30 -07001// Copyright (c) 2021 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_
6#define QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_
7
8#include <string>
9
QUICHE team59de4b02021-04-27 02:46:00 -070010#include "quic/core/quic_simple_buffer_allocator.h"
vasilvv316f3762021-03-31 13:49:30 -070011#include "quic/core/web_transport_interface.h"
12#include "quic/platform/api/quic_logging.h"
bnc08fc2ae2021-04-27 14:57:51 -070013#include "common/quiche_circular_deque.h"
vasilvv316f3762021-03-31 13:49:30 -070014
15namespace quic {
16
17// Discards any incoming data.
18class WebTransportDiscardVisitor : public WebTransportStreamVisitor {
19 public:
20 WebTransportDiscardVisitor(WebTransportStream* stream) : stream_(stream) {}
21
22 void OnCanRead() override {
23 std::string buffer;
vasilvve7534342021-04-05 10:30:41 -070024 WebTransportStream::ReadResult result = stream_->Read(&buffer);
25 QUIC_DVLOG(2) << "Read " << result.bytes_read
26 << " bytes from WebTransport stream "
27 << stream_->GetStreamId() << ", fin: " << result.fin;
vasilvv316f3762021-03-31 13:49:30 -070028 }
29
vasilvv316f3762021-03-31 13:49:30 -070030 void OnCanWrite() override {}
31
32 private:
33 WebTransportStream* stream_;
34};
35
36// Echoes any incoming data back on the same stream.
37class WebTransportBidirectionalEchoVisitor : public WebTransportStreamVisitor {
38 public:
39 WebTransportBidirectionalEchoVisitor(WebTransportStream* stream)
40 : stream_(stream) {}
41
42 void OnCanRead() override {
vasilvve7534342021-04-05 10:30:41 -070043 WebTransportStream::ReadResult result = stream_->Read(&buffer_);
vasilvv20d73c42021-04-06 20:14:52 -070044 QUIC_DVLOG(1) << "Attempted reading on WebTransport bidirectional stream "
45 << stream_->GetStreamId()
46 << ", bytes read: " << result.bytes_read;
vasilvve7534342021-04-05 10:30:41 -070047 if (result.fin) {
48 send_fin_ = true;
49 }
vasilvv316f3762021-03-31 13:49:30 -070050 OnCanWrite();
51 }
52
vasilvv316f3762021-03-31 13:49:30 -070053 void OnCanWrite() override {
vasilvve7534342021-04-05 10:30:41 -070054 if (!buffer_.empty()) {
55 bool success = stream_->Write(buffer_);
vasilvv20d73c42021-04-06 20:14:52 -070056 QUIC_DVLOG(1) << "Attempted writing on WebTransport bidirectional stream "
57 << stream_->GetStreamId()
58 << ", success: " << (success ? "yes" : "no");
vasilvve7534342021-04-05 10:30:41 -070059 if (!success) {
60 return;
61 }
62
63 buffer_ = "";
vasilvv316f3762021-03-31 13:49:30 -070064 }
65
vasilvve7534342021-04-05 10:30:41 -070066 if (send_fin_) {
67 bool success = stream_->SendFin();
68 QUICHE_DCHECK(success);
vasilvv316f3762021-03-31 13:49:30 -070069 }
70 }
71
72 private:
73 WebTransportStream* stream_;
74 std::string buffer_;
vasilvve7534342021-04-05 10:30:41 -070075 bool send_fin_ = false;
vasilvv316f3762021-03-31 13:49:30 -070076};
77
78// Buffers all of the data and calls |callback| with the entirety of the stream
79// data.
80class WebTransportUnidirectionalEchoReadVisitor
81 : public WebTransportStreamVisitor {
82 public:
83 using Callback = std::function<void(const std::string&)>;
84
85 WebTransportUnidirectionalEchoReadVisitor(WebTransportStream* stream,
86 Callback callback)
87 : stream_(stream), callback_(std::move(callback)) {}
88
89 void OnCanRead() override {
vasilvve7534342021-04-05 10:30:41 -070090 WebTransportStream::ReadResult result = stream_->Read(&buffer_);
vasilvv316f3762021-03-31 13:49:30 -070091 QUIC_DVLOG(1) << "Attempted reading on WebTransport unidirectional stream "
vasilvve7534342021-04-05 10:30:41 -070092 << stream_->GetStreamId()
93 << ", bytes read: " << result.bytes_read;
94 if (result.fin) {
95 QUIC_DVLOG(1) << "Finished receiving data on a WebTransport stream "
96 << stream_->GetStreamId() << ", queueing up the echo";
97 callback_(buffer_);
98 }
vasilvv316f3762021-03-31 13:49:30 -070099 }
100
101 void OnCanWrite() override { QUIC_NOTREACHED(); }
102
103 private:
104 WebTransportStream* stream_;
105 std::string buffer_;
106 Callback callback_;
107};
108
109// Sends supplied data.
110class WebTransportUnidirectionalEchoWriteVisitor
111 : public WebTransportStreamVisitor {
112 public:
113 WebTransportUnidirectionalEchoWriteVisitor(WebTransportStream* stream,
114 const std::string& data)
115 : stream_(stream), data_(data) {}
116
117 void OnCanRead() override { QUIC_NOTREACHED(); }
vasilvv316f3762021-03-31 13:49:30 -0700118 void OnCanWrite() override {
119 if (data_.empty()) {
120 return;
121 }
122 if (!stream_->Write(data_)) {
123 return;
124 }
125 data_ = "";
126 bool fin_sent = stream_->SendFin();
127 QUICHE_DVLOG(1)
128 << "WebTransportUnidirectionalEchoWriteVisitor finished sending data.";
129 QUICHE_DCHECK(fin_sent);
130 }
131
132 private:
133 WebTransportStream* stream_;
134 std::string data_;
135};
136
QUICHE team59de4b02021-04-27 02:46:00 -0700137// A session visitor which sets unidirectional or bidirectional stream visitors
138// to echo.
139class EchoWebTransportSessionVisitor : public WebTransportVisitor {
140 public:
141 EchoWebTransportSessionVisitor(WebTransportSession* session)
142 : session_(session) {}
143
144 void OnSessionReady() override {
145 if (session_->CanOpenNextOutgoingBidirectionalStream()) {
146 OnCanCreateNewOutgoingBidirectionalStream();
147 }
148 }
149
150 void OnIncomingBidirectionalStreamAvailable() override {
151 while (true) {
152 WebTransportStream* stream =
153 session_->AcceptIncomingBidirectionalStream();
154 if (stream == nullptr) {
155 return;
156 }
157 QUIC_DVLOG(1)
158 << "EchoWebTransportSessionVisitor received a bidirectional stream "
159 << stream->GetStreamId();
160 stream->SetVisitor(
161 std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
162 stream->visitor()->OnCanRead();
163 }
164 }
165
166 void OnIncomingUnidirectionalStreamAvailable() override {
167 while (true) {
168 WebTransportStream* stream =
169 session_->AcceptIncomingUnidirectionalStream();
170 if (stream == nullptr) {
171 return;
172 }
173 QUIC_DVLOG(1)
174 << "EchoWebTransportSessionVisitor received a unidirectional stream";
175 stream->SetVisitor(
176 std::make_unique<WebTransportUnidirectionalEchoReadVisitor>(
177 stream, [this](const std::string& data) {
178 streams_to_echo_back_.push_back(data);
179 TrySendingUnidirectionalStreams();
180 }));
181 stream->visitor()->OnCanRead();
182 }
183 }
184
185 void OnDatagramReceived(absl::string_view datagram) override {
186 auto buffer = MakeUniqueBuffer(&allocator_, datagram.size());
187 memcpy(buffer.get(), datagram.data(), datagram.size());
188 QuicMemSlice slice(std::move(buffer), datagram.size());
189 session_->SendOrQueueDatagram(std::move(slice));
190 }
191
192 void OnCanCreateNewOutgoingBidirectionalStream() override {
193 if (!echo_stream_opened_) {
194 WebTransportStream* stream = session_->OpenOutgoingBidirectionalStream();
195 stream->SetVisitor(
196 std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
197 echo_stream_opened_ = true;
198 }
199 }
200 void OnCanCreateNewOutgoingUnidirectionalStream() override {
201 TrySendingUnidirectionalStreams();
202 }
203
204 void TrySendingUnidirectionalStreams() {
205 while (!streams_to_echo_back_.empty() &&
206 session_->CanOpenNextOutgoingUnidirectionalStream()) {
207 QUIC_DVLOG(1)
208 << "EchoWebTransportServer echoed a unidirectional stream back";
209 WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream();
210 stream->SetVisitor(
211 std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(
212 stream, streams_to_echo_back_.front()));
213 streams_to_echo_back_.pop_front();
214 stream->visitor()->OnCanWrite();
215 }
216 }
217
218 private:
219 WebTransportSession* session_;
220 SimpleBufferAllocator allocator_;
221 bool echo_stream_opened_ = false;
222
bnc08fc2ae2021-04-27 14:57:51 -0700223 quiche::QuicheCircularDeque<std::string> streams_to_echo_back_;
QUICHE team59de4b02021-04-27 02:46:00 -0700224};
225
vasilvv316f3762021-03-31 13:49:30 -0700226} // namespace quic
227
228#endif // QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_