// Copyright 2013 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 #include #include #include #include "base/compiler_specific.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "net/base/completion_once_callback.h" #include "net/base/elements_upload_data_stream.h" #include "net/base/ip_address.h" #include "net/base/test_completion_callback.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_data_stream.h" #include "net/cert/ct_policy_enforcer.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/multi_log_ct_verifier.h" #include "net/dns/mapped_host_resolver.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_handler_factory.h" #include "net/http/http_network_session.h" #include "net/http/http_network_transaction.h" #include "net/http/http_server_properties.h" #include "net/http/http_transaction_test_util.h" #include "net/http/transport_security_state.h" #include "net/log/net_log_with_source.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h" #include "net/quic/crypto_test_utils_chromium.h" #include "net/quic/quic_context.h" #include "net/socket/client_socket_factory.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_task_environment.h" #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quiche/quic/tools/quic_memory_cache_backend.h" #include "net/tools/quic/quic_simple_server.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" namespace net { using test::IsOk; namespace test { namespace { const char kResponseBody[] = "some arbitrary response body"; // Factory for creating HttpTransactions, used by TestTransactionConsumer. class TestTransactionFactory : public HttpTransactionFactory { public: explicit TestTransactionFactory( const HttpNetworkSessionParams& session_params, const HttpNetworkSessionContext& session_context) : session_(std::make_unique(session_params, session_context)) {} ~TestTransactionFactory() override = default; // HttpTransactionFactory methods int CreateTransaction(RequestPriority priority, std::unique_ptr* trans) override { *trans = std::make_unique(priority, session_.get()); return OK; } HttpCache* GetCache() override { return nullptr; } HttpNetworkSession* GetSession() override { return session_.get(); } private: std::unique_ptr session_; }; } // namespace class QuicEndToEndTest : public ::testing::Test, public WithTaskEnvironment { protected: QuicEndToEndTest() : host_resolver_(CreateResolverImpl()), ssl_config_service_(std::make_unique()), proxy_resolution_service_( ConfiguredProxyResolutionService::CreateDirect()), auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault()) { request_.method = "GET"; request_.url = GURL("https://test.example.com/"); request_.load_flags = 0; request_.traffic_annotation = net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); session_params_.enable_quic = true; session_context_.client_socket_factory = ClientSocketFactory::GetDefaultFactory(); session_context_.quic_context = &quic_context_; session_context_.host_resolver = &host_resolver_; session_context_.cert_verifier = &cert_verifier_; session_context_.transport_security_state = &transport_security_state_; session_context_.ct_policy_enforcer = &ct_policy_enforcer_; session_context_.proxy_resolution_service = proxy_resolution_service_.get(); session_context_.ssl_config_service = ssl_config_service_.get(); session_context_.http_auth_handler_factory = auth_handler_factory_.get(); session_context_.http_server_properties = &http_server_properties_; CertVerifyResult verify_result; verify_result.verified_cert = ImportCertFromFile(GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), "test.example.com", verify_result, OK); } // Creates a mock host resolver in which test.example.com // resolves to localhost. static std::unique_ptr CreateResolverImpl() { auto resolver = std::make_unique(); resolver->rules()->AddRule("test.example.com", "127.0.0.1"); return resolver; } void SetUp() override { StartServer(); // Use a mapped host resolver so that request for test.example.com (port 80) // reach the server running on localhost. std::string map_rule = "MAP test.example.com test.example.com:" + base::NumberToString(server_->server_address().port()); EXPECT_TRUE(host_resolver_.AddRuleFromString(map_rule)); // To simplify the test, and avoid the race with the HTTP request, we force // QUIC for these requests. quic_context_.params()->origins_to_force_quic_on.insert( HostPortPair::FromString("test.example.com:443")); transaction_factory_ = std::make_unique( session_params_, session_context_); } void TearDown() override {} // Starts the QUIC server listening on a random port. void StartServer() { server_address_ = IPEndPoint(IPAddress(127, 0, 0, 1), 0); server_config_.SetInitialStreamFlowControlWindowToSend( quic::test::kInitialStreamFlowControlWindowForTest); server_config_.SetInitialSessionFlowControlWindowToSend( quic::test::kInitialSessionFlowControlWindowForTest); server_ = std::make_unique( net::test::ProofSourceForTestingChromium(), server_config_, server_config_options_, quic::AllSupportedVersions(), &memory_cache_backend_); server_->Listen(server_address_); server_address_ = server_->server_address(); server_->StartReading(); server_started_ = true; } // Adds an entry to the cache used by the QUIC server to serve // responses. void AddToCache(absl::string_view path, int response_code, absl::string_view response_detail, absl::string_view body) { memory_cache_backend_.AddSimpleResponse("test.example.com", path, response_code, body); } // Populates |request_body_| with |length_| ASCII bytes. void GenerateBody(size_t length) { request_body_.clear(); request_body_.reserve(length); for (size_t i = 0; i < length; ++i) { request_body_.append(1, static_cast(32 + i % (126 - 32))); } } // Initializes |request_| for a post of |length| bytes. void InitializePostRequest(size_t length) { GenerateBody(length); std::vector> element_readers; element_readers.push_back(std::make_unique( request_body_.data(), request_body_.length())); upload_data_stream_ = std::make_unique( std::move(element_readers), 0); request_.method = "POST"; request_.url = GURL("https://test.example.com/"); request_.upload_data_stream = upload_data_stream_.get(); ASSERT_THAT(request_.upload_data_stream->Init(CompletionOnceCallback(), NetLogWithSource()), IsOk()); } // Checks that |consumer| completed and received |status_line| and |body|. void CheckResponse(const TestTransactionConsumer& consumer, const std::string& status_line, const std::string& body) { ASSERT_TRUE(consumer.is_done()); ASSERT_THAT(consumer.error(), IsOk()); EXPECT_EQ(status_line, consumer.response_info()->headers->GetStatusLine()); EXPECT_EQ(body, consumer.content()); } QuicContext quic_context_; MappedHostResolver host_resolver_; MockCertVerifier cert_verifier_; TransportSecurityState transport_security_state_; DefaultCTPolicyEnforcer ct_policy_enforcer_; std::unique_ptr ssl_config_service_; std::unique_ptr proxy_resolution_service_; std::unique_ptr auth_handler_factory_; HttpServerProperties http_server_properties_; HttpNetworkSessionParams session_params_; HttpNetworkSessionContext session_context_; std::unique_ptr transaction_factory_; HttpRequestInfo request_; std::string request_body_; std::unique_ptr upload_data_stream_; std::unique_ptr server_; quic::QuicMemoryCacheBackend memory_cache_backend_; IPEndPoint server_address_; std::string server_hostname_; quic::QuicConfig server_config_; quic::QuicCryptoServerConfig::ConfigOptions server_config_options_; bool server_started_; bool strike_register_no_startup_period_ = false; }; TEST_F(QuicEndToEndTest, LargeGetWithNoPacketLoss) { std::string response(10 * 1024, 'x'); AddToCache(request_.url.PathForRequest(), 200, "OK", response); TestTransactionConsumer consumer(DEFAULT_PRIORITY, transaction_factory_.get()); consumer.Start(&request_, NetLogWithSource()); // Will terminate when the last consumer completes. base::RunLoop().Run(); CheckResponse(consumer, "HTTP/1.1 200", response); } // crbug.com/559173 #if defined(THREAD_SANITIZER) TEST_F(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) { #else TEST_F(QuicEndToEndTest, LargePostWithNoPacketLoss) { #endif InitializePostRequest(1024 * 1024); AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody); TestTransactionConsumer consumer(DEFAULT_PRIORITY, transaction_factory_.get()); consumer.Start(&request_, NetLogWithSource()); // Will terminate when the last consumer completes. base::RunLoop().Run(); CheckResponse(consumer, "HTTP/1.1 200", kResponseBody); } // crbug.com/559173 #if defined(THREAD_SANITIZER) TEST_F(QuicEndToEndTest, DISABLED_LargePostWithPacketLoss) { #else TEST_F(QuicEndToEndTest, LargePostWithPacketLoss) { #endif // FLAGS_fake_packet_loss_percentage = 30; InitializePostRequest(1024 * 1024); AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody); TestTransactionConsumer consumer(DEFAULT_PRIORITY, transaction_factory_.get()); consumer.Start(&request_, NetLogWithSource()); // Will terminate when the last consumer completes. base::RunLoop().Run(); CheckResponse(consumer, "HTTP/1.1 200", kResponseBody); } // crbug.com/536845 #if defined(THREAD_SANITIZER) TEST_F(QuicEndToEndTest, DISABLED_UberTest) { #else TEST_F(QuicEndToEndTest, UberTest) { #endif // FLAGS_fake_packet_loss_percentage = 30; AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody); std::vector> consumers; for (size_t i = 0; i < 100; ++i) { TestTransactionConsumer* consumer = new TestTransactionConsumer( DEFAULT_PRIORITY, transaction_factory_.get()); consumers.push_back(base::WrapUnique(consumer)); consumer->Start(&request_, NetLogWithSource()); } // Will terminate when the last consumer completes. base::RunLoop().Run(); for (const auto& consumer : consumers) CheckResponse(*consumer.get(), "HTTP/1.1 200", kResponseBody); } } // namespace test } // namespace net