| // 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 "quic/test_tools/quic_test_server.h" |
| |
| #include <utility> |
| |
| #include "absl/memory/memory.h" |
| #include "absl/strings/string_view.h" |
| #include "quic/core/quic_epoll_alarm_factory.h" |
| #include "quic/core/quic_epoll_connection_helper.h" |
| #include "quic/tools/quic_simple_crypto_server_stream_helper.h" |
| #include "quic/tools/quic_simple_dispatcher.h" |
| #include "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) |
| : 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), |
| 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}); |
| |
| 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<QuicEpollConnectionHelper>(epoll_server(), |
| QuicAllocator::BUFFER_POOL), |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper>( |
| new QuicSimpleCryptoServerStreamHelper()), |
| std::make_unique<QuicEpollAlarmFactory>(epoll_server()), server_backend(), |
| expected_server_connection_id_length()); |
| } |
| |
| 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); |
| } |
| |
| /////////////////////////// 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 |