blob: 9fe3dfd98228b5dcb4bc7f6b9a80d399b1e0669d [file] [log] [blame]
vasilvvd88f1622019-11-04 13:50:53 -08001// Copyright (c) 2019 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#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h"
6
7#include <memory>
8
9#include "url/gurl.h"
10#include "url/origin.h"
11#include "net/third_party/quiche/src/quic/core/quic_types.h"
12#include "net/third_party/quiche/src/quic/core/quic_versions.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
vasilvvd88f1622019-11-04 13:50:53 -080015#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h"
16#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
17
18namespace quic {
19
20namespace {
21
22// Discards any incoming data.
23class DiscardVisitor : public QuicTransportStream::Visitor {
24 public:
25 DiscardVisitor(QuicTransportStream* stream) : stream_(stream) {}
26
27 void OnCanRead() override {
28 std::string buffer;
29 size_t bytes_read = stream_->Read(&buffer);
30 QUIC_DVLOG(2) << "Read " << bytes_read << " bytes from stream "
31 << stream_->id();
32 }
33
34 void OnFinRead() override {}
35 void OnCanWrite() override {}
36
37 private:
38 QuicTransportStream* stream_;
39};
40
41// Echoes any incoming data back on the same stream.
42class BidirectionalEchoVisitor : public QuicTransportStream::Visitor {
43 public:
44 BidirectionalEchoVisitor(QuicTransportStream* stream) : stream_(stream) {}
45
46 void OnCanRead() override {
47 stream_->Read(&buffer_);
48 OnCanWrite();
49 }
50
51 void OnFinRead() override {
52 bool success = stream_->SendFin();
53 DCHECK(success);
54 }
55
56 void OnCanWrite() override {
57 if (buffer_.empty()) {
58 return;
59 }
60
61 bool success = stream_->Write(buffer_);
62 if (success) {
63 buffer_ = "";
64 }
65 }
66
67 private:
68 QuicTransportStream* stream_;
69 std::string buffer_;
70};
71
72// Buffers all of the data and calls EchoStreamBack() on the parent session.
73class UnidirectionalEchoReadVisitor : public QuicTransportStream::Visitor {
74 public:
75 UnidirectionalEchoReadVisitor(QuicTransportSimpleServerSession* session,
76 QuicTransportStream* stream)
77 : session_(session), stream_(stream) {}
78
79 void OnCanRead() override {
80 bool success = stream_->Read(&buffer_);
81 DCHECK(success);
82 }
83
84 void OnFinRead() override {
85 QUIC_DVLOG(1) << "Finished receiving data on stream " << stream_->id()
86 << ", queueing up the echo";
87 session_->EchoStreamBack(buffer_);
88 }
89
90 void OnCanWrite() override { QUIC_NOTREACHED(); }
91
92 private:
93 QuicTransportSimpleServerSession* session_;
94 QuicTransportStream* stream_;
95 std::string buffer_;
96};
97
98// Sends supplied data.
99class UnidirectionalEchoWriteVisitor : public QuicTransportStream::Visitor {
100 public:
101 UnidirectionalEchoWriteVisitor(QuicTransportStream* stream,
102 const std::string& data)
103 : stream_(stream), data_(data) {}
104
105 void OnCanRead() override { QUIC_NOTREACHED(); }
106 void OnFinRead() override { QUIC_NOTREACHED(); }
107 void OnCanWrite() override {
108 if (data_.empty()) {
109 return;
110 }
111 if (!stream_->Write(data_)) {
112 return;
113 }
114 data_ = "";
115 bool fin_sent = stream_->SendFin();
116 DCHECK(fin_sent);
117 }
118
119 private:
120 QuicTransportStream* stream_;
121 std::string data_;
122};
123
124} // namespace
125
126QuicTransportSimpleServerSession::QuicTransportSimpleServerSession(
127 QuicConnection* connection,
128 bool owns_connection,
129 Visitor* owner,
130 const QuicConfig& config,
131 const ParsedQuicVersionVector& supported_versions,
132 const QuicCryptoServerConfig* crypto_config,
133 QuicCompressedCertsCache* compressed_certs_cache,
vasilvvd88f1622019-11-04 13:50:53 -0800134 std::vector<url::Origin> accepted_origins)
135 : QuicTransportServerSession(connection,
136 owner,
137 config,
138 supported_versions,
139 crypto_config,
140 compressed_certs_cache,
141 this),
vasilvvd88f1622019-11-04 13:50:53 -0800142 owns_connection_(owns_connection),
vasilvvd7692cd2019-12-06 08:06:31 -0800143 mode_(DISCARD),
wub50c6a372019-11-25 05:34:56 -0800144 accepted_origins_(accepted_origins) {}
vasilvvd88f1622019-11-04 13:50:53 -0800145
146QuicTransportSimpleServerSession::~QuicTransportSimpleServerSession() {
147 if (owns_connection_) {
ianswett6aefa0b2019-12-10 07:26:15 -0800148 DeleteConnection();
vasilvvd88f1622019-11-04 13:50:53 -0800149 }
150}
151
152void QuicTransportSimpleServerSession::OnIncomingDataStream(
153 QuicTransportStream* stream) {
154 switch (mode_) {
155 case DISCARD:
156 stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
157 break;
158
159 case ECHO:
160 switch (stream->type()) {
161 case BIDIRECTIONAL:
162 QUIC_DVLOG(1) << "Opening bidirectional echo stream " << stream->id();
163 stream->set_visitor(
164 std::make_unique<BidirectionalEchoVisitor>(stream));
165 break;
166 case READ_UNIDIRECTIONAL:
167 QUIC_DVLOG(1)
168 << "Started receiving data on unidirectional echo stream "
169 << stream->id();
170 stream->set_visitor(
171 std::make_unique<UnidirectionalEchoReadVisitor>(this, stream));
172 break;
173 default:
174 QUIC_NOTREACHED();
175 break;
176 }
177 break;
178 }
179}
180
181void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream(
182 bool unidirectional) {
183 if (mode_ == ECHO && unidirectional) {
184 MaybeEchoStreamsBack();
185 }
186}
187
188bool QuicTransportSimpleServerSession::CheckOrigin(url::Origin origin) {
189 if (accepted_origins_.empty()) {
190 return true;
191 }
192
193 for (const url::Origin& accepted_origin : accepted_origins_) {
194 if (origin.IsSameOriginWith(accepted_origin)) {
195 return true;
196 }
197 }
198 return false;
199}
200
vasilvv78571892019-12-06 07:14:57 -0800201bool QuicTransportSimpleServerSession::ProcessPath(const GURL& url) {
vasilvvd7692cd2019-12-06 08:06:31 -0800202 if (url.path() == "/discard") {
203 mode_ = DISCARD;
204 return true;
205 }
206 if (url.path() == "/echo") {
207 mode_ = ECHO;
208 return true;
209 }
210
211 QUIC_DLOG(WARNING) << "Unknown path requested: " << url.path();
212 return false;
vasilvv78571892019-12-06 07:14:57 -0800213}
214
vasilvvd88f1622019-11-04 13:50:53 -0800215void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() {
216 while (!streams_to_echo_back_.empty() &&
217 CanOpenNextOutgoingUnidirectionalStream()) {
218 // Remove the stream from the queue first, in order to avoid accidentally
219 // entering an infinite loop in case any of the following code calls
220 // OnCanCreateNewOutgoingStream().
221 std::string data = std::move(streams_to_echo_back_.front());
222 streams_to_echo_back_.pop_front();
223
224 auto stream_owned = std::make_unique<QuicTransportStream>(
225 GetNextOutgoingUnidirectionalStreamId(), this, this);
226 QuicTransportStream* stream = stream_owned.get();
227 ActivateStream(std::move(stream_owned));
228 QUIC_DVLOG(1) << "Opened echo response stream " << stream->id();
229
230 stream->set_visitor(
231 std::make_unique<UnidirectionalEchoWriteVisitor>(stream, data));
232 stream->visitor()->OnCanWrite();
233 }
234}
235
236} // namespace quic