|  | // 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 "net/third_party/quiche/src/quic/test_tools/quic_test_server.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" | 
|  | #include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h" | 
|  | #include "net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h" | 
|  | #include "net/third_party/quiche/src/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, | 
|  | QuicCryptoServerStream::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(QuicWrapUnique(stream)); | 
|  | return stream; | 
|  | } | 
|  | return QuicSimpleServerSession::CreateIncomingStream(id); | 
|  | } | 
|  |  | 
|  | 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<QuicCryptoServerStream::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) {} | 
|  |  | 
|  | QuicServerSessionBase* CreateQuicSession( | 
|  | QuicConnectionId id, | 
|  | const QuicSocketAddress& client, | 
|  | QuicStringPiece alpn, | 
|  | const ParsedQuicVersion& version) override { | 
|  | QuicReaderMutexLock lock(&factory_lock_); | 
|  | if (session_factory_ == nullptr && stream_factory_ == nullptr && | 
|  | crypto_stream_factory_ == nullptr) { | 
|  | return QuicSimpleDispatcher::CreateQuicSession(id, client, alpn, version); | 
|  | } | 
|  | QuicConnection* connection = | 
|  | new QuicConnection(id, client, helper(), alarm_factory(), writer(), | 
|  | /* owns_writer= */ false, Perspective::IS_SERVER, | 
|  | ParsedQuicVersionVector{version}); | 
|  |  | 
|  | QuicServerSessionBase* session = nullptr; | 
|  | if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) { | 
|  | session = new 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()); | 
|  | } | 
|  | // TODO(b/142715651): Figure out how to use QPACK in tests. | 
|  | // Do not use the QPACK dynamic table in tests to avoid flakiness due to the | 
|  | // uncertain order of receiving the SETTINGS frame and sending headers. | 
|  | session->set_qpack_maximum_dynamic_table_capacity(0); | 
|  | session->set_qpack_maximum_blocked_streams(0); | 
|  | session->Initialize(); | 
|  | return session; | 
|  | } | 
|  |  | 
|  | void SetSessionFactory(QuicTestServer::SessionFactory* factory) { | 
|  | QuicWriterMutexLock lock(&factory_lock_); | 
|  | DCHECK(session_factory_ == nullptr); | 
|  | DCHECK(stream_factory_ == nullptr); | 
|  | DCHECK(crypto_stream_factory_ == nullptr); | 
|  | session_factory_ = factory; | 
|  | } | 
|  |  | 
|  | void SetStreamFactory(QuicTestServer::StreamFactory* factory) { | 
|  | QuicWriterMutexLock lock(&factory_lock_); | 
|  | DCHECK(session_factory_ == nullptr); | 
|  | DCHECK(stream_factory_ == nullptr); | 
|  | stream_factory_ = factory; | 
|  | } | 
|  |  | 
|  | void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) { | 
|  | QuicWriterMutexLock lock(&factory_lock_); | 
|  | DCHECK(session_factory_ == nullptr); | 
|  | 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<QuicCryptoServerStream::Helper>( | 
|  | new QuicSimpleCryptoServerStreamHelper()), | 
|  | std::make_unique<QuicEpollAlarmFactory>(epoll_server()), server_backend(), | 
|  | expected_server_connection_id_length()); | 
|  | } | 
|  |  | 
|  | void QuicTestServer::SetSessionFactory(SessionFactory* factory) { | 
|  | 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, | 
|  | QuicCryptoServerStream::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(); | 
|  | } 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. Even if it's a immediate | 
|  | // goaway session, goaway shouldn't be sent when crypto frame is received. | 
|  | if (!VersionUsesHttp3(transport_version())) { | 
|  | SendGoAway(QUIC_PEER_GOING_AWAY, ""); | 
|  | } | 
|  | QuicSimpleServerSession::OnCryptoFrame(frame); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  |  | 
|  | }  // namespace quic |