| // 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 |