| // 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 <memory> | 
 | #include <utility> | 
 |  | 
 | #include "absl/memory/memory.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "absl/synchronization/mutex.h" | 
 | #include "quiche/quic/core/connection_id_generator.h" | 
 | #include "quiche/quic/core/io/quic_default_event_loop.h" | 
 | #include "quiche/quic/core/quic_default_connection_helper.h" | 
 | #include "quiche/quic/core/quic_types.h" | 
 | #include "quiche/quic/core/quic_versions.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*/, | 
 |       ConnectionIdGeneratorInterface& connection_id_generator) override { | 
 |     absl::ReaderMutexLock 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(), alpn); | 
 |     } | 
 |     if (VersionUsesHttp3(version.transport_version)) { | 
 |       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) { | 
 |     absl::WriterMutexLock 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) { | 
 |     absl::WriterMutexLock lock(&factory_lock_); | 
 |     QUICHE_DCHECK(session_factory_ == nullptr); | 
 |     QUICHE_DCHECK(stream_factory_ == nullptr); | 
 |     stream_factory_ = factory; | 
 |   } | 
 |  | 
 |   void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) { | 
 |     absl::WriterMutexLock lock(&factory_lock_); | 
 |     QUICHE_DCHECK(session_factory_ == nullptr); | 
 |     QUICHE_DCHECK(crypto_stream_factory_ == nullptr); | 
 |     crypto_stream_factory_ = factory; | 
 |   } | 
 |  | 
 |  private: | 
 |   absl::Mutex 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 |