blob: 157c16c158f38acd2ae0548ecdc4fef00c318a88 [file] [log] [blame]
// 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 "quic/tools/quic_transport_simple_server_session.h"
#include <memory>
#include "url/gurl.h"
#include "url/origin.h"
#include "quic/core/quic_buffer_allocator.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/quic_transport/quic_transport_protocol.h"
#include "quic/quic_transport/quic_transport_stream.h"
#include "quic/tools/web_transport_test_visitors.h"
#include "common/platform/api/quiche_mem_slice.h"
namespace quic {
QuicTransportSimpleServerSession::QuicTransportSimpleServerSession(
QuicConnection* connection,
bool owns_connection,
Visitor* owner,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
std::vector<url::Origin> accepted_origins)
: QuicTransportServerSession(connection,
owner,
config,
supported_versions,
crypto_config,
compressed_certs_cache,
this),
owns_connection_(owns_connection),
mode_(DISCARD),
accepted_origins_(accepted_origins) {}
QuicTransportSimpleServerSession::~QuicTransportSimpleServerSession() {
if (owns_connection_) {
DeleteConnection();
}
}
void QuicTransportSimpleServerSession::OnIncomingDataStream(
QuicTransportStream* stream) {
switch (mode_) {
case DISCARD:
stream->SetVisitor(std::make_unique<WebTransportDiscardVisitor>(stream));
break;
case ECHO:
switch (stream->type()) {
case BIDIRECTIONAL:
QUIC_DVLOG(1) << "Opening bidirectional echo stream " << stream->id();
stream->SetVisitor(
std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
break;
case READ_UNIDIRECTIONAL:
QUIC_DVLOG(1)
<< "Started receiving data on unidirectional echo stream "
<< stream->id();
stream->SetVisitor(
std::make_unique<WebTransportUnidirectionalEchoReadVisitor>(
stream,
[this](const std::string& s) { this->EchoStreamBack(s); }));
break;
default:
QUIC_NOTREACHED();
break;
}
break;
case OUTGOING_BIDIRECTIONAL:
stream->SetVisitor(std::make_unique<WebTransportDiscardVisitor>(stream));
++pending_outgoing_bidirectional_streams_;
MaybeCreateOutgoingBidirectionalStream();
break;
}
}
void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream(
bool unidirectional) {
if (mode_ == ECHO && unidirectional) {
MaybeEchoStreamsBack();
} else if (mode_ == OUTGOING_BIDIRECTIONAL && !unidirectional) {
MaybeCreateOutgoingBidirectionalStream();
}
}
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;
}
bool QuicTransportSimpleServerSession::ProcessPath(const GURL& url) {
if (url.path() == "/discard") {
mode_ = DISCARD;
return true;
}
if (url.path() == "/echo") {
mode_ = ECHO;
return true;
}
if (url.path() == "/receive-bidirectional") {
mode_ = OUTGOING_BIDIRECTIONAL;
return true;
}
QUIC_DLOG(WARNING) << "Unknown path requested: " << url.path();
return false;
}
void QuicTransportSimpleServerSession::OnMessageReceived(
absl::string_view message) {
if (mode_ != ECHO) {
return;
}
datagram_queue()->SendOrQueueDatagram(quiche::QuicheMemSlice(QuicBuffer::Copy(
connection()->helper()->GetStreamSendBufferAllocator(), message)));
}
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->SetVisitor(
std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(stream,
data));
stream->visitor()->OnCanWrite();
}
}
void QuicTransportSimpleServerSession::
MaybeCreateOutgoingBidirectionalStream() {
while (pending_outgoing_bidirectional_streams_ > 0 &&
CanOpenNextOutgoingBidirectionalStream()) {
auto stream_owned = std::make_unique<QuicTransportStream>(
GetNextOutgoingBidirectionalStreamId(), this, this);
QuicTransportStream* stream = stream_owned.get();
ActivateStream(std::move(stream_owned));
QUIC_DVLOG(1) << "Opened outgoing bidirectional stream " << stream->id();
stream->SetVisitor(
std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
if (!stream->Write("hello")) {
QUIC_DVLOG(1) << "Write failed.";
}
--pending_outgoing_bidirectional_streams_;
}
}
} // namespace quic