1 // 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 #include "quiche/quic/test_tools/web_transport_resets_backend.h"
6 
7 #include <memory>
8 
9 #include "quiche/quic/core/web_transport_interface.h"
10 #include "quiche/quic/tools/web_transport_test_visitors.h"
11 #include "quiche/common/quiche_circular_deque.h"
12 
13 namespace quic {
14 namespace test {
15 
16 namespace {
17 
18 class ResetsVisitor;
19 
20 class BidirectionalEchoVisitorWithLogging
21     : public WebTransportBidirectionalEchoVisitor {
22  public:
BidirectionalEchoVisitorWithLogging(WebTransportStream * stream,ResetsVisitor * session_visitor)23   BidirectionalEchoVisitorWithLogging(WebTransportStream* stream,
24                                       ResetsVisitor* session_visitor)
25       : WebTransportBidirectionalEchoVisitor(stream),
26         session_visitor_(session_visitor) {}
27 
28   void OnResetStreamReceived(WebTransportStreamError error) override;
29   void OnStopSendingReceived(WebTransportStreamError error) override;
30 
31  private:
32   ResetsVisitor* session_visitor_;  // Not owned.
33 };
34 
35 class ResetsVisitor : public WebTransportVisitor {
36  public:
ResetsVisitor(WebTransportSession * session)37   ResetsVisitor(WebTransportSession* session) : session_(session) {}
38 
OnSessionReady()39   void OnSessionReady() override {}
OnSessionClosed(WebTransportSessionError,const std::string &)40   void OnSessionClosed(WebTransportSessionError /*error_code*/,
41                        const std::string& /*error_message*/) override {}
42 
OnIncomingBidirectionalStreamAvailable()43   void OnIncomingBidirectionalStreamAvailable() override {
44     while (true) {
45       WebTransportStream* stream =
46           session_->AcceptIncomingBidirectionalStream();
47       if (stream == nullptr) {
48         return;
49       }
50       stream->SetVisitor(
51           std::make_unique<BidirectionalEchoVisitorWithLogging>(stream, this));
52       stream->visitor()->OnCanRead();
53     }
54   }
OnIncomingUnidirectionalStreamAvailable()55   void OnIncomingUnidirectionalStreamAvailable() override {}
56 
OnDatagramReceived(absl::string_view)57   void OnDatagramReceived(absl::string_view /*datagram*/) override {}
58 
OnCanCreateNewOutgoingBidirectionalStream()59   void OnCanCreateNewOutgoingBidirectionalStream() override {}
OnCanCreateNewOutgoingUnidirectionalStream()60   void OnCanCreateNewOutgoingUnidirectionalStream() override {
61     MaybeSendLogsBack();
62   }
63 
Log(std::string line)64   void Log(std::string line) {
65     log_.push_back(std::move(line));
66     MaybeSendLogsBack();
67   }
68 
69  private:
MaybeSendLogsBack()70   void MaybeSendLogsBack() {
71     while (!log_.empty() &&
72            session_->CanOpenNextOutgoingUnidirectionalStream()) {
73       WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream();
74       stream->SetVisitor(
75           std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(
76               stream, log_.front()));
77       log_.pop_front();
78       stream->visitor()->OnCanWrite();
79     }
80   }
81 
82   WebTransportSession* session_;  // Not owned.
83   quiche::QuicheCircularDeque<std::string> log_;
84 };
85 
OnResetStreamReceived(WebTransportStreamError error)86 void BidirectionalEchoVisitorWithLogging::OnResetStreamReceived(
87     WebTransportStreamError error) {
88   session_visitor_->Log(absl::StrCat("Received reset for stream ",
89                                      stream()->GetStreamId(),
90                                      " with error code ", error));
91   WebTransportBidirectionalEchoVisitor::OnResetStreamReceived(error);
92 }
OnStopSendingReceived(WebTransportStreamError error)93 void BidirectionalEchoVisitorWithLogging::OnStopSendingReceived(
94     WebTransportStreamError error) {
95   session_visitor_->Log(absl::StrCat("Received stop sending for stream ",
96                                      stream()->GetStreamId(),
97                                      " with error code ", error));
98   WebTransportBidirectionalEchoVisitor::OnStopSendingReceived(error);
99 }
100 
101 }  // namespace
102 
WebTransportResetsBackend(const spdy::Http2HeaderBlock &,WebTransportSession * session)103 QuicSimpleServerBackend::WebTransportResponse WebTransportResetsBackend(
104     const spdy::Http2HeaderBlock& /*request_headers*/,
105     WebTransportSession* session) {
106   QuicSimpleServerBackend::WebTransportResponse response;
107   response.response_headers[":status"] = "200";
108   response.visitor = std::make_unique<ResetsVisitor>(session);
109   return response;
110 }
111 
112 }  // namespace test
113 }  // namespace quic
114