| // Copyright (c) 2015 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 "quiche/quic/test_tools/quic_test_server.h" | |
| #include <utility> | |
| #include "absl/memory/memory.h" | |
| #include "absl/strings/string_view.h" | |
| #include "quiche/quic/core/io/quic_default_event_loop.h" | |
| #include "quiche/quic/core/quic_default_connection_helper.h" | |
| #include "quiche/quic/tools/quic_simple_crypto_server_stream_helper.h" | |
| #include "quiche/quic/tools/quic_simple_dispatcher.h" | |
| #include "quiche/quic/tools/quic_simple_server_session.h" | |
| namespace quic { | |
| namespace test { | |
| class CustomStreamSession : public QuicSimpleServerSession { | |
| public: | |
| CustomStreamSession( | |
| const QuicConfig& config, | |
| const ParsedQuicVersionVector& supported_versions, | |
| QuicConnection* connection, QuicSession::Visitor* visitor, | |
| QuicCryptoServerStreamBase::Helper* helper, | |
| const QuicCryptoServerConfig* crypto_config, | |
| QuicCompressedCertsCache* compressed_certs_cache, | |
| QuicTestServer::StreamFactory* stream_factory, | |
| QuicTestServer::CryptoStreamFactory* crypto_stream_factory, | |
| QuicSimpleServerBackend* quic_simple_server_backend) | |
| : QuicSimpleServerSession(config, supported_versions, connection, visitor, | |
| helper, crypto_config, compressed_certs_cache, | |
| quic_simple_server_backend), | |
| stream_factory_(stream_factory), | |
| crypto_stream_factory_(crypto_stream_factory) {} | |
| QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override { | |
| if (!ShouldCreateIncomingStream(id)) { | |
| return nullptr; | |
| } | |
| if (stream_factory_) { | |
| QuicSpdyStream* stream = | |
| stream_factory_->CreateStream(id, this, server_backend()); | |
| ActivateStream(absl::WrapUnique(stream)); | |
| return stream; | |
| } | |
| return QuicSimpleServerSession::CreateIncomingStream(id); | |
| } | |
| std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream( | |
| const QuicCryptoServerConfig* crypto_config, | |
| QuicCompressedCertsCache* compressed_certs_cache) override { | |
| if (crypto_stream_factory_) { | |
| return crypto_stream_factory_->CreateCryptoStream(crypto_config, this); | |
| } | |
| return QuicSimpleServerSession::CreateQuicCryptoServerStream( | |
| crypto_config, compressed_certs_cache); | |
| } | |
| private: | |
| QuicTestServer::StreamFactory* stream_factory_; // Not owned. | |
| QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned. | |
| }; | |
| class QuicTestDispatcher : public QuicSimpleDispatcher { | |
| public: | |
| QuicTestDispatcher( | |
| const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, | |
| QuicVersionManager* version_manager, | |
| std::unique_ptr<QuicConnectionHelperInterface> helper, | |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper, | |
| std::unique_ptr<QuicAlarmFactory> alarm_factory, | |
| QuicSimpleServerBackend* quic_simple_server_backend, | |
| uint8_t expected_server_connection_id_length, | |
| ConnectionIdGeneratorInterface& generator) | |
| : QuicSimpleDispatcher(config, crypto_config, version_manager, | |
| std::move(helper), std::move(session_helper), | |
| std::move(alarm_factory), | |
| quic_simple_server_backend, | |
| expected_server_connection_id_length, generator), | |
| session_factory_(nullptr), | |
| stream_factory_(nullptr), | |
| crypto_stream_factory_(nullptr) {} | |
| std::unique_ptr<QuicSession> CreateQuicSession( | |
| QuicConnectionId id, const QuicSocketAddress& self_address, | |
| const QuicSocketAddress& peer_address, absl::string_view /*alpn*/, | |
| const ParsedQuicVersion& version, | |
| const ParsedClientHello& /*parsed_chlo*/) override { | |
| QuicReaderMutexLock lock(&factory_lock_); | |
| // The QuicServerSessionBase takes ownership of |connection| below. | |
| QuicConnection* connection = new QuicConnection( | |
| id, self_address, peer_address, helper(), alarm_factory(), writer(), | |
| /* owns_writer= */ false, Perspective::IS_SERVER, | |
| ParsedQuicVersionVector{version}, connection_id_generator()); | |
| std::unique_ptr<QuicServerSessionBase> session; | |
| if (session_factory_ == nullptr && stream_factory_ == nullptr && | |
| crypto_stream_factory_ == nullptr) { | |
| session = std::make_unique<QuicSimpleServerSession>( | |
| config(), GetSupportedVersions(), connection, this, session_helper(), | |
| crypto_config(), compressed_certs_cache(), server_backend()); | |
| } else if (stream_factory_ != nullptr || | |
| crypto_stream_factory_ != nullptr) { | |
| session = std::make_unique<CustomStreamSession>( | |
| config(), GetSupportedVersions(), connection, this, session_helper(), | |
| crypto_config(), compressed_certs_cache(), stream_factory_, | |
| crypto_stream_factory_, server_backend()); | |
| } else { | |
| session = session_factory_->CreateSession( | |
| config(), connection, this, session_helper(), crypto_config(), | |
| compressed_certs_cache(), server_backend()); | |
| } | |
| if (VersionUsesHttp3(version.transport_version) && | |
| GetQuicReloadableFlag(quic_verify_request_headers_2)) { | |
| QUICHE_DCHECK(session->allow_extended_connect()); | |
| // Do not allow extended CONNECT request if the backend doesn't support | |
| // it. | |
| session->set_allow_extended_connect( | |
| server_backend()->SupportsExtendedConnect()); | |
| } | |
| session->Initialize(); | |
| return session; | |
| } | |
| void SetSessionFactory(QuicTestServer::SessionFactory* factory) { | |
| QuicWriterMutexLock lock(&factory_lock_); | |
| QUICHE_DCHECK(session_factory_ == nullptr); | |
| QUICHE_DCHECK(stream_factory_ == nullptr); | |
| QUICHE_DCHECK(crypto_stream_factory_ == nullptr); | |
| session_factory_ = factory; | |
| } | |
| void SetStreamFactory(QuicTestServer::StreamFactory* factory) { | |
| QuicWriterMutexLock lock(&factory_lock_); | |
| QUICHE_DCHECK(session_factory_ == nullptr); | |
| QUICHE_DCHECK(stream_factory_ == nullptr); | |
| stream_factory_ = factory; | |
| } | |
| void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) { | |
| QuicWriterMutexLock lock(&factory_lock_); | |
| QUICHE_DCHECK(session_factory_ == nullptr); | |
| QUICHE_DCHECK(crypto_stream_factory_ == nullptr); | |
| crypto_stream_factory_ = factory; | |
| } | |
| private: | |
| QuicMutex factory_lock_; | |
| QuicTestServer::SessionFactory* session_factory_; // Not owned. | |
| QuicTestServer::StreamFactory* stream_factory_; // Not owned. | |
| QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned. | |
| }; | |
| QuicTestServer::QuicTestServer( | |
| std::unique_ptr<ProofSource> proof_source, | |
| QuicSimpleServerBackend* quic_simple_server_backend) | |
| : QuicServer(std::move(proof_source), quic_simple_server_backend) {} | |
| QuicTestServer::QuicTestServer( | |
| std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, | |
| const ParsedQuicVersionVector& supported_versions, | |
| QuicSimpleServerBackend* quic_simple_server_backend) | |
| : QuicTestServer(std::move(proof_source), config, supported_versions, | |
| quic_simple_server_backend, | |
| kQuicDefaultConnectionIdLength) {} | |
| QuicTestServer::QuicTestServer( | |
| std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, | |
| const ParsedQuicVersionVector& supported_versions, | |
| QuicSimpleServerBackend* quic_simple_server_backend, | |
| uint8_t expected_server_connection_id_length) | |
| : QuicServer(std::move(proof_source), config, | |
| QuicCryptoServerConfig::ConfigOptions(), supported_versions, | |
| quic_simple_server_backend, | |
| expected_server_connection_id_length) {} | |
| QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { | |
| return new QuicTestDispatcher( | |
| &config(), &crypto_config(), version_manager(), | |
| std::make_unique<QuicDefaultConnectionHelper>(), | |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper>( | |
| new QuicSimpleCryptoServerStreamHelper()), | |
| event_loop()->CreateAlarmFactory(), server_backend(), | |
| expected_server_connection_id_length(), connection_id_generator()); | |
| } | |
| void QuicTestServer::SetSessionFactory(SessionFactory* factory) { | |
| QUICHE_DCHECK(dispatcher()); | |
| static_cast<QuicTestDispatcher*>(dispatcher())->SetSessionFactory(factory); | |
| } | |
| void QuicTestServer::SetSpdyStreamFactory(StreamFactory* factory) { | |
| static_cast<QuicTestDispatcher*>(dispatcher())->SetStreamFactory(factory); | |
| } | |
| void QuicTestServer::SetCryptoStreamFactory(CryptoStreamFactory* factory) { | |
| static_cast<QuicTestDispatcher*>(dispatcher()) | |
| ->SetCryptoStreamFactory(factory); | |
| } | |
| void QuicTestServer::SetEventLoopFactory(QuicEventLoopFactory* factory) { | |
| event_loop_factory_ = factory; | |
| } | |
| std::unique_ptr<QuicEventLoop> QuicTestServer::CreateEventLoop() { | |
| QuicEventLoopFactory* factory = event_loop_factory_; | |
| if (factory == nullptr) { | |
| factory = GetDefaultEventLoop(); | |
| } | |
| return factory->Create(QuicDefaultClock::Get()); | |
| } | |
| /////////////////////////// TEST SESSIONS /////////////////////////////// | |
| ImmediateGoAwaySession::ImmediateGoAwaySession( | |
| const QuicConfig& config, QuicConnection* connection, | |
| QuicSession::Visitor* visitor, QuicCryptoServerStreamBase::Helper* helper, | |
| const QuicCryptoServerConfig* crypto_config, | |
| QuicCompressedCertsCache* compressed_certs_cache, | |
| QuicSimpleServerBackend* quic_simple_server_backend) | |
| : QuicSimpleServerSession( | |
| config, CurrentSupportedVersions(), connection, visitor, helper, | |
| crypto_config, compressed_certs_cache, quic_simple_server_backend) {} | |
| void ImmediateGoAwaySession::OnStreamFrame(const QuicStreamFrame& frame) { | |
| if (VersionUsesHttp3(transport_version())) { | |
| SendHttp3GoAway(QUIC_PEER_GOING_AWAY, ""); | |
| } else { | |
| SendGoAway(QUIC_PEER_GOING_AWAY, ""); | |
| } | |
| QuicSimpleServerSession::OnStreamFrame(frame); | |
| } | |
| void ImmediateGoAwaySession::OnCryptoFrame(const QuicCryptoFrame& frame) { | |
| // In IETF QUIC, GOAWAY lives up in HTTP/3 layer. It's sent in a QUIC stream | |
| // and requires encryption. Thus the sending is done in | |
| // OnNewEncryptionKeyAvailable(). | |
| if (!VersionUsesHttp3(transport_version())) { | |
| SendGoAway(QUIC_PEER_GOING_AWAY, ""); | |
| } | |
| QuicSimpleServerSession::OnCryptoFrame(frame); | |
| } | |
| void ImmediateGoAwaySession::OnNewEncryptionKeyAvailable( | |
| EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) { | |
| QuicSimpleServerSession::OnNewEncryptionKeyAvailable(level, | |
| std::move(encrypter)); | |
| if (VersionUsesHttp3(transport_version())) { | |
| if (IsEncryptionEstablished() && !goaway_sent()) { | |
| SendHttp3GoAway(QUIC_PEER_GOING_AWAY, ""); | |
| } | |
| } | |
| } | |
| } // namespace test | |
| } // namespace quic |