dedicated_web_transport_http3_client_test.cc 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/quic/dedicated_web_transport_http3_client.h"
  5. #include <memory>
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/strings/strcat.h"
  8. #include "base/threading/thread_task_runner_handle.h"
  9. #include "build/build_config.h"
  10. #include "net/base/schemeful_site.h"
  11. #include "net/cert/mock_cert_verifier.h"
  12. #include "net/dns/mock_host_resolver.h"
  13. #include "net/proxy_resolution/configured_proxy_resolution_service.h"
  14. #include "net/quic/crypto/proof_source_chromium.h"
  15. #include "net/test/test_data_directory.h"
  16. #include "net/test/test_with_task_environment.h"
  17. #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
  18. #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_backend.h"
  19. #include "net/tools/quic/quic_simple_server.h"
  20. #include "net/tools/quic/quic_simple_server_socket.h"
  21. #include "net/url_request/url_request_context.h"
  22. #include "net/url_request/url_request_context_builder.h"
  23. #include "testing/gmock/include/gmock/gmock.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. #include "url/gurl.h"
  26. #include "url/origin.h"
  27. namespace net::test {
  28. namespace {
  29. using ::quic::test::MemSliceFromString;
  30. using ::testing::_;
  31. using ::testing::DoAll;
  32. using ::testing::Optional;
  33. using ::testing::SaveArg;
  34. class MockVisitor : public WebTransportClientVisitor {
  35. public:
  36. MOCK_METHOD(void,
  37. OnConnected,
  38. (scoped_refptr<HttpResponseHeaders>),
  39. (override));
  40. MOCK_METHOD(void, OnConnectionFailed, (const WebTransportError&), (override));
  41. MOCK_METHOD(void,
  42. OnClosed,
  43. (const absl::optional<WebTransportCloseInfo>&),
  44. (override));
  45. MOCK_METHOD(void, OnError, (const WebTransportError&), (override));
  46. MOCK_METHOD0(OnIncomingBidirectionalStreamAvailable, void());
  47. MOCK_METHOD0(OnIncomingUnidirectionalStreamAvailable, void());
  48. MOCK_METHOD1(OnDatagramReceived, void(base::StringPiece));
  49. MOCK_METHOD0(OnCanCreateNewOutgoingBidirectionalStream, void());
  50. MOCK_METHOD0(OnCanCreateNewOutgoingUnidirectionalStream, void());
  51. MOCK_METHOD1(OnDatagramProcessed, void(absl::optional<quic::MessageStatus>));
  52. };
  53. // A clock that only mocks out WallNow(), but uses real Now() and
  54. // ApproximateNow(). Useful for certificate verification.
  55. class TestWallClock : public quic::QuicClock {
  56. public:
  57. quic::QuicTime Now() const override {
  58. return quic::QuicChromiumClock::GetInstance()->Now();
  59. }
  60. quic::QuicTime ApproximateNow() const override {
  61. return quic::QuicChromiumClock::GetInstance()->ApproximateNow();
  62. }
  63. quic::QuicWallTime WallNow() const override { return wall_now_; }
  64. void set_wall_now(quic::QuicWallTime now) { wall_now_ = now; }
  65. private:
  66. quic::QuicWallTime wall_now_ = quic::QuicWallTime::Zero();
  67. };
  68. class TestConnectionHelper : public quic::QuicConnectionHelperInterface {
  69. public:
  70. const quic::QuicClock* GetClock() const override { return &clock_; }
  71. quic::QuicRandom* GetRandomGenerator() override {
  72. return quic::QuicRandom::GetInstance();
  73. }
  74. quiche::QuicheBufferAllocator* GetStreamSendBufferAllocator() override {
  75. return &allocator_;
  76. }
  77. TestWallClock& clock() { return clock_; }
  78. private:
  79. TestWallClock clock_;
  80. quiche::SimpleBufferAllocator allocator_;
  81. };
  82. class DedicatedWebTransportHttp3Test : public TestWithTaskEnvironment {
  83. public:
  84. DedicatedWebTransportHttp3Test() {
  85. quic::QuicEnableVersion(quic::ParsedQuicVersion::RFCv1());
  86. origin_ = url::Origin::Create(GURL{"https://example.org"});
  87. isolation_key_ =
  88. NetworkIsolationKey(SchemefulSite(origin_), SchemefulSite(origin_));
  89. URLRequestContextBuilder builder;
  90. builder.set_proxy_resolution_service(
  91. ConfiguredProxyResolutionService::CreateDirect());
  92. auto cert_verifier = std::make_unique<MockCertVerifier>();
  93. cert_verifier->set_default_result(OK);
  94. builder.SetCertVerifier(std::move(cert_verifier));
  95. auto host_resolver = std::make_unique<MockHostResolver>();
  96. host_resolver->rules()->AddRule("test.example.com", "127.0.0.1");
  97. builder.set_host_resolver(std::move(host_resolver));
  98. auto helper = std::make_unique<TestConnectionHelper>();
  99. helper_ = helper.get();
  100. auto quic_context = std::make_unique<QuicContext>(std::move(helper));
  101. quic_context->params()->supported_versions.clear();
  102. // This is required to bypass the check that only allows known certificate
  103. // roots in QUIC.
  104. quic_context->params()->origins_to_force_quic_on.insert(
  105. HostPortPair("test.example.com", 0));
  106. builder.set_quic_context(std::move(quic_context));
  107. builder.set_net_log(NetLog::Get());
  108. context_ = builder.Build();
  109. // By default, quit on error instead of waiting for RunLoop() to time out.
  110. ON_CALL(visitor_, OnConnectionFailed(_))
  111. .WillByDefault([this](const WebTransportError& error) {
  112. LOG(ERROR) << "Connection failed: " << error;
  113. run_loop_->Quit();
  114. });
  115. ON_CALL(visitor_, OnError(_))
  116. .WillByDefault([this](const WebTransportError& error) {
  117. LOG(ERROR) << "Connection error: " << error;
  118. run_loop_->Quit();
  119. });
  120. }
  121. ~DedicatedWebTransportHttp3Test() override {
  122. if (server_ != nullptr) {
  123. server_->Shutdown();
  124. }
  125. }
  126. GURL GetURL(const std::string& suffix) {
  127. return GURL{base::StrCat(
  128. {"https://test.example.com:", base::NumberToString(port_), suffix})};
  129. }
  130. void StartServer(std::unique_ptr<quic::ProofSource> proof_source = nullptr) {
  131. if (proof_source == nullptr) {
  132. proof_source = quic::test::crypto_test_utils::ProofSourceForTesting();
  133. }
  134. backend_.set_enable_webtransport(true);
  135. server_ = std::make_unique<QuicSimpleServer>(
  136. std::move(proof_source), quic::QuicConfig(),
  137. quic::QuicCryptoServerConfig::ConfigOptions(),
  138. quic::AllSupportedVersions(), &backend_);
  139. ASSERT_TRUE(server_->CreateUDPSocketAndListen(
  140. quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), /*port=*/0)));
  141. port_ = server_->server_address().port();
  142. }
  143. void Run() {
  144. run_loop_ = std::make_unique<base::RunLoop>();
  145. run_loop_->Run();
  146. }
  147. auto StopRunning() {
  148. return [this]() { run_loop_->Quit(); };
  149. }
  150. protected:
  151. quic::test::QuicFlagSaver flags_; // Save/restore all QUIC flag values.
  152. std::unique_ptr<URLRequestContext> context_;
  153. std::unique_ptr<DedicatedWebTransportHttp3Client> client_;
  154. raw_ptr<TestConnectionHelper> helper_; // Owned by |context_|.
  155. ::testing::NiceMock<MockVisitor> visitor_;
  156. std::unique_ptr<QuicSimpleServer> server_;
  157. std::unique_ptr<base::RunLoop> run_loop_;
  158. quic::test::QuicTestBackend backend_;
  159. int port_ = 0;
  160. url::Origin origin_;
  161. NetworkIsolationKey isolation_key_;
  162. };
  163. TEST_F(DedicatedWebTransportHttp3Test, Connect) {
  164. StartServer();
  165. client_ = std::make_unique<DedicatedWebTransportHttp3Client>(
  166. GetURL("/echo"), origin_, &visitor_, isolation_key_, context_.get(),
  167. WebTransportParameters());
  168. EXPECT_CALL(visitor_, OnConnected(_)).WillOnce(StopRunning());
  169. client_->Connect();
  170. Run();
  171. ASSERT_TRUE(client_->session() != nullptr);
  172. client_->Close(absl::nullopt);
  173. EXPECT_CALL(visitor_, OnClosed(_)).WillOnce(StopRunning());
  174. Run();
  175. }
  176. // TODO(https://crbug.com/1288036): The test is flaky on Mac and iOS.
  177. #if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_MAC)
  178. #define MAYBE_CloseTimeout DISABLED_CloseTimeout
  179. #else
  180. #define MAYBE_CloseTimeout CloseTimeout
  181. #endif
  182. TEST_F(DedicatedWebTransportHttp3Test, MAYBE_CloseTimeout) {
  183. StartServer();
  184. client_ = std::make_unique<DedicatedWebTransportHttp3Client>(
  185. GetURL("/echo"), origin_, &visitor_, isolation_key_, context_.get(),
  186. WebTransportParameters());
  187. EXPECT_CALL(visitor_, OnConnected(_)).WillOnce(StopRunning());
  188. client_->Connect();
  189. Run();
  190. ASSERT_TRUE(client_->session() != nullptr);
  191. // Delete the server and put up a no-op socket in its place to simulate the
  192. // traffic being dropped. Note that this is normally not a supported way of
  193. // shutting down a QuicServer, and will generate a lot of errors in the logs.
  194. server_.reset();
  195. IPEndPoint bind_address(IPAddress::IPv6AllZeros(), port_);
  196. auto noop_socket =
  197. std::make_unique<UDPServerSocket>(/*net_log=*/nullptr, NetLogSource());
  198. noop_socket->AllowAddressReuse();
  199. ASSERT_GE(noop_socket->Listen(bind_address), 0);
  200. client_->Close(absl::nullopt);
  201. EXPECT_CALL(visitor_, OnError(_)).WillOnce(StopRunning());
  202. Run();
  203. }
  204. TEST_F(DedicatedWebTransportHttp3Test, CloseReason) {
  205. StartServer();
  206. client_ = std::make_unique<DedicatedWebTransportHttp3Client>(
  207. GetURL("/session-close"), origin_, &visitor_, isolation_key_,
  208. context_.get(), WebTransportParameters());
  209. EXPECT_CALL(visitor_, OnConnected(_)).WillOnce(StopRunning());
  210. client_->Connect();
  211. Run();
  212. ASSERT_TRUE(client_->session() != nullptr);
  213. quic::WebTransportStream* stream =
  214. client_->session()->OpenOutgoingUnidirectionalStream();
  215. ASSERT_TRUE(stream != nullptr);
  216. EXPECT_TRUE(stream->Write("42 test error"));
  217. EXPECT_TRUE(stream->SendFin());
  218. WebTransportCloseInfo close_info(42, "test error");
  219. absl::optional<WebTransportCloseInfo> received_close_info;
  220. EXPECT_CALL(visitor_, OnClosed(_))
  221. .WillOnce(DoAll(StopRunning(), SaveArg<0>(&received_close_info)));
  222. Run();
  223. EXPECT_THAT(received_close_info, Optional(close_info));
  224. }
  225. } // namespace
  226. } // namespace net::test