web_transport_unittest.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. // Copyright 2019 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 "services/network/web_transport.h"
  5. #include <set>
  6. #include <vector>
  7. #include "base/containers/contains.h"
  8. #include "base/rand_util.h"
  9. #include "base/strings/strcat.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/test/bind.h"
  12. #include "base/test/task_environment.h"
  13. #include "net/cert/mock_cert_verifier.h"
  14. #include "net/cert/pem.h"
  15. #include "net/dns/mock_host_resolver.h"
  16. #include "net/log/test_net_log.h"
  17. #include "net/quic/crypto/proof_source_chromium.h"
  18. #include "net/quic/quic_context.h"
  19. #include "net/test/test_data_directory.h"
  20. #include "net/third_party/quiche/src/quiche/quic/core/crypto/proof_source_x509.h"
  21. #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
  22. #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_backend.h"
  23. #include "net/tools/quic/quic_simple_server.h"
  24. #include "net/url_request/url_request_context.h"
  25. #include "services/network/network_context.h"
  26. #include "services/network/network_service.h"
  27. #include "services/network/public/mojom/network_context.mojom.h"
  28. #include "services/network/test/fake_test_cert_verifier_params_factory.h"
  29. #include "services/network/url_request_context_builder_mojo.h"
  30. #include "testing/gtest/include/gtest/gtest.h"
  31. namespace network {
  32. namespace {
  33. class HostResolverFactory final : public net::HostResolver::Factory {
  34. public:
  35. explicit HostResolverFactory(std::unique_ptr<net::HostResolver> resolver)
  36. : resolver_(std::move(resolver)) {}
  37. std::unique_ptr<net::HostResolver> CreateResolver(
  38. net::HostResolverManager* manager,
  39. base::StringPiece host_mapping_rules,
  40. bool enable_caching) override {
  41. DCHECK(resolver_);
  42. return std::move(resolver_);
  43. }
  44. // See HostResolver::CreateStandaloneResolver.
  45. std::unique_ptr<net::HostResolver> CreateStandaloneResolver(
  46. net::NetLog* net_log,
  47. const net::HostResolver::ManagerOptions& options,
  48. base::StringPiece host_mapping_rules,
  49. bool enable_caching) override {
  50. NOTREACHED();
  51. return nullptr;
  52. }
  53. private:
  54. std::unique_ptr<net::HostResolver> resolver_;
  55. };
  56. // A clock that only mocks out WallNow(), but uses real Now() and
  57. // ApproximateNow(). Useful for certificate verification.
  58. class TestWallClock : public quic::QuicClock {
  59. public:
  60. quic::QuicTime Now() const override {
  61. return quic::QuicChromiumClock::GetInstance()->Now();
  62. }
  63. quic::QuicTime ApproximateNow() const override {
  64. return quic::QuicChromiumClock::GetInstance()->ApproximateNow();
  65. }
  66. quic::QuicWallTime WallNow() const override { return wall_now_; }
  67. void set_wall_now(quic::QuicWallTime now) { wall_now_ = now; }
  68. private:
  69. quic::QuicWallTime wall_now_ = quic::QuicWallTime::Zero();
  70. };
  71. class TestConnectionHelper : public quic::QuicConnectionHelperInterface {
  72. public:
  73. const quic::QuicClock* GetClock() const override { return &clock_; }
  74. quic::QuicRandom* GetRandomGenerator() override {
  75. return quic::QuicRandom::GetInstance();
  76. }
  77. quiche::QuicheBufferAllocator* GetStreamSendBufferAllocator() override {
  78. return &allocator_;
  79. }
  80. TestWallClock& clock() { return clock_; }
  81. private:
  82. TestWallClock clock_;
  83. quiche::SimpleBufferAllocator allocator_;
  84. };
  85. mojom::NetworkContextParamsPtr CreateNetworkContextParams() {
  86. auto context_params = mojom::NetworkContextParams::New();
  87. // Use a dummy CertVerifier that always passes cert verification, since
  88. // these unittests don't need to test CertVerifier behavior.
  89. context_params->cert_verifier_params =
  90. FakeTestCertVerifierParamsFactory::GetCertVerifierParams();
  91. return context_params;
  92. }
  93. // We don't use mojo::BlockingCopyToString because it leads to deadlocks.
  94. std::string Read(mojo::ScopedDataPipeConsumerHandle readable) {
  95. std::string output;
  96. while (true) {
  97. char buffer[1024];
  98. uint32_t size = sizeof(buffer);
  99. MojoResult result =
  100. readable->ReadData(buffer, &size, MOJO_READ_DATA_FLAG_NONE);
  101. if (result == MOJO_RESULT_SHOULD_WAIT) {
  102. base::RunLoop run_loop;
  103. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  104. run_loop.QuitClosure());
  105. run_loop.Run();
  106. continue;
  107. }
  108. if (result == MOJO_RESULT_FAILED_PRECONDITION) {
  109. return output;
  110. }
  111. DCHECK_EQ(result, MOJO_RESULT_OK);
  112. output.append(buffer, size);
  113. }
  114. }
  115. class TestHandshakeClient final : public mojom::WebTransportHandshakeClient {
  116. public:
  117. TestHandshakeClient(mojo::PendingReceiver<mojom::WebTransportHandshakeClient>
  118. pending_receiver,
  119. base::OnceClosure callback)
  120. : receiver_(this, std::move(pending_receiver)),
  121. callback_(std::move(callback)) {
  122. receiver_.set_disconnect_handler(base::BindOnce(
  123. &TestHandshakeClient::OnMojoConnectionError, base::Unretained(this)));
  124. }
  125. ~TestHandshakeClient() override = default;
  126. void OnConnectionEstablished(
  127. mojo::PendingRemote<mojom::WebTransport> transport,
  128. mojo::PendingReceiver<mojom::WebTransportClient> client_receiver,
  129. const scoped_refptr<net::HttpResponseHeaders>& response_headers)
  130. override {
  131. transport_ = std::move(transport);
  132. client_receiver_ = std::move(client_receiver);
  133. has_seen_connection_establishment_ = true;
  134. receiver_.reset();
  135. std::move(callback_).Run();
  136. }
  137. void OnHandshakeFailed(
  138. const absl::optional<net::WebTransportError>& error) override {
  139. has_seen_handshake_failure_ = true;
  140. handshake_error_ = error;
  141. receiver_.reset();
  142. std::move(callback_).Run();
  143. }
  144. void OnMojoConnectionError() {
  145. has_seen_handshake_failure_ = true;
  146. std::move(callback_).Run();
  147. }
  148. mojo::PendingRemote<mojom::WebTransport> PassTransport() {
  149. return std::move(transport_);
  150. }
  151. mojo::PendingReceiver<mojom::WebTransportClient> PassClientReceiver() {
  152. return std::move(client_receiver_);
  153. }
  154. bool has_seen_connection_establishment() const {
  155. return has_seen_connection_establishment_;
  156. }
  157. bool has_seen_handshake_failure() const {
  158. return has_seen_handshake_failure_;
  159. }
  160. bool has_seen_mojo_connection_error() const {
  161. return has_seen_mojo_connection_error_;
  162. }
  163. absl::optional<net::WebTransportError> handshake_error() const {
  164. return handshake_error_;
  165. }
  166. private:
  167. mojo::Receiver<mojom::WebTransportHandshakeClient> receiver_;
  168. mojo::PendingRemote<mojom::WebTransport> transport_;
  169. mojo::PendingReceiver<mojom::WebTransportClient> client_receiver_;
  170. base::OnceClosure callback_;
  171. bool has_seen_connection_establishment_ = false;
  172. bool has_seen_handshake_failure_ = false;
  173. bool has_seen_mojo_connection_error_ = false;
  174. absl::optional<net::WebTransportError> handshake_error_;
  175. };
  176. class TestClient final : public mojom::WebTransportClient {
  177. public:
  178. explicit TestClient(
  179. mojo::PendingReceiver<mojom::WebTransportClient> pending_receiver)
  180. : receiver_(this, std::move(pending_receiver)) {
  181. receiver_.set_disconnect_handler(base::BindOnce(
  182. &TestClient::OnMojoConnectionError, base::Unretained(this)));
  183. }
  184. // mojom::WebTransportClient implementation.
  185. void OnDatagramReceived(base::span<const uint8_t> data) override {
  186. received_datagrams_.push_back(
  187. std::vector<uint8_t>(data.begin(), data.end()));
  188. }
  189. void OnIncomingStreamClosed(uint32_t stream_id, bool fin_received) override {
  190. closed_incoming_streams_.insert(std::make_pair(stream_id, fin_received));
  191. if (quit_closure_for_incoming_stream_closure_) {
  192. std::move(quit_closure_for_incoming_stream_closure_).Run();
  193. }
  194. }
  195. void OnOutgoingStreamClosed(uint32_t stream_id) override {
  196. closed_outgoing_streams_.insert(stream_id);
  197. if (quit_closure_for_outgoing_stream_closure_) {
  198. std::move(quit_closure_for_outgoing_stream_closure_).Run();
  199. }
  200. }
  201. void OnReceivedResetStream(uint32_t stream_id, uint8_t) override {}
  202. void OnReceivedStopSending(uint32_t stream_id, uint8_t) override {}
  203. void OnClosed(mojom::WebTransportCloseInfoPtr close_info) override {}
  204. void WaitUntilMojoConnectionError() {
  205. base::RunLoop run_loop;
  206. quit_closure_for_mojo_connection_error_ = run_loop.QuitClosure();
  207. run_loop.Run();
  208. }
  209. void WaitUntilIncomingStreamIsClosed(uint32_t stream_id) {
  210. while (!stream_is_closed_as_incoming_stream(stream_id)) {
  211. base::RunLoop run_loop;
  212. quit_closure_for_incoming_stream_closure_ = run_loop.QuitClosure();
  213. run_loop.Run();
  214. }
  215. }
  216. void WaitUntilOutgoingStreamIsClosed(uint32_t stream_id) {
  217. while (!stream_is_closed_as_outgoing_stream(stream_id)) {
  218. base::RunLoop run_loop;
  219. quit_closure_for_outgoing_stream_closure_ = run_loop.QuitClosure();
  220. run_loop.Run();
  221. }
  222. }
  223. const std::vector<std::vector<uint8_t>>& received_datagrams() const {
  224. return received_datagrams_;
  225. }
  226. bool has_received_fin_for(uint32_t stream_id) {
  227. auto it = closed_incoming_streams_.find(stream_id);
  228. return it != closed_incoming_streams_.end() && it->second;
  229. }
  230. bool stream_is_closed_as_incoming_stream(uint32_t stream_id) {
  231. return closed_incoming_streams_.find(stream_id) !=
  232. closed_incoming_streams_.end();
  233. }
  234. bool stream_is_closed_as_outgoing_stream(uint32_t stream_id) {
  235. return closed_outgoing_streams_.find(stream_id) !=
  236. closed_outgoing_streams_.end();
  237. }
  238. bool has_seen_mojo_connection_error() const {
  239. return has_seen_mojo_connection_error_;
  240. }
  241. private:
  242. void OnMojoConnectionError() {
  243. has_seen_mojo_connection_error_ = true;
  244. if (quit_closure_for_mojo_connection_error_) {
  245. std::move(quit_closure_for_mojo_connection_error_).Run();
  246. }
  247. }
  248. mojo::Receiver<mojom::WebTransportClient> receiver_;
  249. base::OnceClosure quit_closure_for_mojo_connection_error_;
  250. base::OnceClosure quit_closure_for_incoming_stream_closure_;
  251. base::OnceClosure quit_closure_for_outgoing_stream_closure_;
  252. std::vector<std::vector<uint8_t>> received_datagrams_;
  253. std::map<uint32_t, bool> closed_incoming_streams_;
  254. std::set<uint32_t> closed_outgoing_streams_;
  255. bool has_seen_mojo_connection_error_ = false;
  256. };
  257. quic::ParsedQuicVersion GetTestVersion() {
  258. quic::ParsedQuicVersion version = quic::ParsedQuicVersion::RFCv1();
  259. quic::QuicEnableVersion(version);
  260. return version;
  261. }
  262. class WebTransportTest : public testing::TestWithParam<base::StringPiece> {
  263. public:
  264. WebTransportTest()
  265. : WebTransportTest(
  266. quic::test::crypto_test_utils::ProofSourceForTesting()) {}
  267. explicit WebTransportTest(std::unique_ptr<quic::ProofSource> proof_source)
  268. : version_(GetTestVersion()),
  269. origin_(url::Origin::Create(GURL("https://example.org/"))),
  270. task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
  271. network_service_(NetworkService::CreateForTesting()),
  272. network_context_remote_(mojo::NullRemote()) {
  273. auto host_resolver = std::make_unique<net::MockHostResolver>();
  274. host_resolver->rules()->AddRule("test.example.com", "127.0.0.1");
  275. network_service_->set_host_resolver_factory_for_testing(
  276. std::make_unique<HostResolverFactory>(std::move(host_resolver)));
  277. network_context_ = NetworkContext::CreateForTesting(
  278. network_service_.get(),
  279. network_context_remote_.BindNewPipeAndPassReceiver(),
  280. CreateNetworkContextParams(),
  281. base::BindOnce([](net::URLRequestContextBuilder* builder) {
  282. auto cert_verifier = std::make_unique<net::MockCertVerifier>();
  283. cert_verifier->set_default_result(net::OK);
  284. builder->SetCertVerifier(std::move(cert_verifier));
  285. }));
  286. backend_.set_enable_webtransport(true);
  287. http_server_ = std::make_unique<net::QuicSimpleServer>(
  288. std::move(proof_source), quic::QuicConfig(),
  289. quic::QuicCryptoServerConfig::ConfigOptions(),
  290. quic::AllSupportedVersions(), &backend_);
  291. EXPECT_TRUE(http_server_->CreateUDPSocketAndListen(quic::QuicSocketAddress(
  292. quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), /*port=*/0))));
  293. auto* quic_context =
  294. network_context_->url_request_context()->quic_context();
  295. quic_context->params()->supported_versions.push_back(version_);
  296. quic_context->params()->origins_to_force_quic_on.insert(
  297. net::HostPortPair("test.example.com", 0));
  298. }
  299. ~WebTransportTest() override = default;
  300. void CreateWebTransport(
  301. const GURL& url,
  302. const url::Origin& origin,
  303. const net::NetworkIsolationKey& key,
  304. std::vector<mojom::WebTransportCertificateFingerprintPtr> fingerprints,
  305. mojo::PendingRemote<mojom::WebTransportHandshakeClient>
  306. handshake_client) {
  307. network_context_->CreateWebTransport(
  308. url, origin, key, std::move(fingerprints), std::move(handshake_client));
  309. }
  310. void CreateWebTransport(
  311. const GURL& url,
  312. const url::Origin& origin,
  313. mojo::PendingRemote<mojom::WebTransportHandshakeClient>
  314. handshake_client) {
  315. CreateWebTransport(url, origin, net::NetworkIsolationKey(), {},
  316. std::move(handshake_client));
  317. }
  318. void CreateWebTransport(
  319. const GURL& url,
  320. const url::Origin& origin,
  321. std::vector<mojom::WebTransportCertificateFingerprintPtr> fingerprints,
  322. mojo::PendingRemote<mojom::WebTransportHandshakeClient>
  323. handshake_client) {
  324. CreateWebTransport(url, origin, net::NetworkIsolationKey(),
  325. std::move(fingerprints), std::move(handshake_client));
  326. }
  327. GURL GetURL(base::StringPiece suffix) {
  328. int port = http_server_->server_address().port();
  329. return GURL(base::StrCat(
  330. {"https://test.example.com:", base::NumberToString(port), suffix}));
  331. }
  332. const url::Origin& origin() const { return origin_; }
  333. const NetworkContext& network_context() const { return *network_context_; }
  334. NetworkContext& mutable_network_context() { return *network_context_; }
  335. net::RecordingNetLogObserver& net_log_observer() { return net_log_observer_; }
  336. void RunPendingTasks() {
  337. base::RunLoop run_loop;
  338. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  339. run_loop.QuitClosure());
  340. run_loop.Run();
  341. }
  342. private:
  343. quic::test::QuicFlagSaver flags_; // Save/restore all QUIC flag values.
  344. quic::ParsedQuicVersion version_;
  345. const url::Origin origin_;
  346. base::test::TaskEnvironment task_environment_;
  347. std::unique_ptr<NetworkService> network_service_;
  348. mojo::Remote<mojom::NetworkContext> network_context_remote_;
  349. net::RecordingNetLogObserver net_log_observer_;
  350. std::unique_ptr<NetworkContext> network_context_;
  351. std::unique_ptr<net::QuicSimpleServer> http_server_;
  352. quic::test::QuicTestBackend backend_;
  353. };
  354. TEST_F(WebTransportTest, ConnectSuccessfully) {
  355. base::RunLoop run_loop_for_handshake;
  356. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  357. TestHandshakeClient test_handshake_client(
  358. handshake_client.InitWithNewPipeAndPassReceiver(),
  359. run_loop_for_handshake.QuitClosure());
  360. CreateWebTransport(GetURL("/echo"), origin(), std::move(handshake_client));
  361. run_loop_for_handshake.Run();
  362. EXPECT_TRUE(test_handshake_client.has_seen_connection_establishment());
  363. EXPECT_FALSE(test_handshake_client.has_seen_handshake_failure());
  364. EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
  365. EXPECT_EQ(1u, network_context().NumOpenWebTransports());
  366. }
  367. TEST_F(WebTransportTest, ConnectHandles404) {
  368. base::RunLoop run_loop_for_handshake;
  369. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  370. TestHandshakeClient test_handshake_client(
  371. handshake_client.InitWithNewPipeAndPassReceiver(),
  372. run_loop_for_handshake.QuitClosure());
  373. CreateWebTransport(GetURL("/does_not_exist"), origin(),
  374. std::move(handshake_client));
  375. run_loop_for_handshake.Run();
  376. EXPECT_FALSE(test_handshake_client.has_seen_connection_establishment());
  377. EXPECT_TRUE(test_handshake_client.has_seen_handshake_failure());
  378. EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
  379. EXPECT_EQ(0u, network_context().NumOpenWebTransports());
  380. }
  381. TEST_F(WebTransportTest, ConnectToBannedPort) {
  382. base::RunLoop run_loop_for_handshake;
  383. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  384. TestHandshakeClient test_handshake_client(
  385. handshake_client.InitWithNewPipeAndPassReceiver(),
  386. run_loop_for_handshake.QuitClosure());
  387. CreateWebTransport(GURL("https://test.example.com:5060/echo"), origin(),
  388. std::move(handshake_client));
  389. run_loop_for_handshake.Run();
  390. EXPECT_FALSE(test_handshake_client.has_seen_connection_establishment());
  391. EXPECT_TRUE(test_handshake_client.has_seen_handshake_failure());
  392. EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
  393. EXPECT_EQ(0u, network_context().NumOpenWebTransports());
  394. ASSERT_TRUE(test_handshake_client.handshake_error().has_value());
  395. EXPECT_EQ(test_handshake_client.handshake_error()->net_error,
  396. net::ERR_UNSAFE_PORT);
  397. }
  398. TEST_F(WebTransportTest, SendDatagram) {
  399. base::RunLoop run_loop_for_handshake;
  400. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  401. TestHandshakeClient test_handshake_client(
  402. handshake_client.InitWithNewPipeAndPassReceiver(),
  403. run_loop_for_handshake.QuitClosure());
  404. CreateWebTransport(GetURL("/echo"),
  405. url::Origin::Create(GURL("https://example.org/")),
  406. std::move(handshake_client));
  407. run_loop_for_handshake.Run();
  408. mojo::Remote<mojom::WebTransport> transport_remote(
  409. test_handshake_client.PassTransport());
  410. TestClient client(test_handshake_client.PassClientReceiver());
  411. std::set<std::vector<uint8_t>> sent_data;
  412. // Both sending and receiving datagrams are flaky due to lack of
  413. // retransmission, and we cannot expect a specific message to be echoed back.
  414. // Instead, we expect one of sent messages to be echoed back.
  415. while (client.received_datagrams().empty()) {
  416. base::RunLoop run_loop_for_datagram;
  417. bool result;
  418. std::vector<uint8_t> data = {
  419. static_cast<uint8_t>(base::RandInt(0, 255)),
  420. static_cast<uint8_t>(base::RandInt(0, 255)),
  421. static_cast<uint8_t>(base::RandInt(0, 255)),
  422. static_cast<uint8_t>(base::RandInt(0, 255)),
  423. };
  424. transport_remote->SendDatagram(base::make_span(data),
  425. base::BindLambdaForTesting([&](bool r) {
  426. result = r;
  427. run_loop_for_datagram.Quit();
  428. }));
  429. run_loop_for_datagram.Run();
  430. if (sent_data.empty()) {
  431. // We expect that the first data went to the network successfully.
  432. ASSERT_TRUE(result);
  433. }
  434. sent_data.insert(std::move(data));
  435. }
  436. EXPECT_TRUE(base::Contains(sent_data, client.received_datagrams()[0]));
  437. }
  438. TEST_F(WebTransportTest, SendToolargeDatagram) {
  439. base::RunLoop run_loop_for_handshake;
  440. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  441. TestHandshakeClient test_handshake_client(
  442. handshake_client.InitWithNewPipeAndPassReceiver(),
  443. run_loop_for_handshake.QuitClosure());
  444. CreateWebTransport(GetURL("/echo"),
  445. url::Origin::Create(GURL("https://example.org/")),
  446. std::move(handshake_client));
  447. run_loop_for_handshake.Run();
  448. base::RunLoop run_loop_for_datagram;
  449. bool result;
  450. // The actual upper limit for one datagram is platform specific, but
  451. // 786kb should be large enough for any platform.
  452. std::vector<uint8_t> data(786 * 1024, 99);
  453. mojo::Remote<mojom::WebTransport> transport_remote(
  454. test_handshake_client.PassTransport());
  455. transport_remote->SendDatagram(base::make_span(data),
  456. base::BindLambdaForTesting([&](bool r) {
  457. result = r;
  458. run_loop_for_datagram.Quit();
  459. }));
  460. run_loop_for_datagram.Run();
  461. EXPECT_FALSE(result);
  462. }
  463. TEST_F(WebTransportTest, EchoOnUnidirectionalStreams) {
  464. base::RunLoop run_loop_for_handshake;
  465. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  466. TestHandshakeClient test_handshake_client(
  467. handshake_client.InitWithNewPipeAndPassReceiver(),
  468. run_loop_for_handshake.QuitClosure());
  469. CreateWebTransport(GetURL("/echo"),
  470. url::Origin::Create(GURL("https://example.org/")),
  471. std::move(handshake_client));
  472. run_loop_for_handshake.Run();
  473. ASSERT_TRUE(test_handshake_client.has_seen_connection_establishment());
  474. TestClient client(test_handshake_client.PassClientReceiver());
  475. mojo::Remote<mojom::WebTransport> transport_remote(
  476. test_handshake_client.PassTransport());
  477. mojo::ScopedDataPipeConsumerHandle readable_for_outgoing;
  478. mojo::ScopedDataPipeProducerHandle writable_for_outgoing;
  479. const MojoCreateDataPipeOptions options = {
  480. sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 4 * 1024};
  481. ASSERT_EQ(MOJO_RESULT_OK,
  482. mojo::CreateDataPipe(&options, writable_for_outgoing,
  483. readable_for_outgoing));
  484. uint32_t size = 5;
  485. ASSERT_EQ(MOJO_RESULT_OK, writable_for_outgoing->WriteData(
  486. "hello", &size, MOJO_WRITE_DATA_FLAG_NONE));
  487. base::RunLoop run_loop_for_stream_creation;
  488. uint32_t stream_id;
  489. bool stream_created;
  490. transport_remote->CreateStream(
  491. std::move(readable_for_outgoing),
  492. /*writable=*/{}, base::BindLambdaForTesting([&](bool b, uint32_t id) {
  493. stream_created = b;
  494. stream_id = id;
  495. run_loop_for_stream_creation.Quit();
  496. }));
  497. run_loop_for_stream_creation.Run();
  498. ASSERT_TRUE(stream_created);
  499. transport_remote->SendFin(stream_id);
  500. writable_for_outgoing.reset();
  501. client.WaitUntilOutgoingStreamIsClosed(stream_id);
  502. mojo::ScopedDataPipeConsumerHandle readable_for_incoming;
  503. uint32_t incoming_stream_id = stream_id;
  504. base::RunLoop run_loop_for_incoming_stream;
  505. transport_remote->AcceptUnidirectionalStream(base::BindLambdaForTesting(
  506. [&](uint32_t id, mojo::ScopedDataPipeConsumerHandle readable) {
  507. incoming_stream_id = id;
  508. readable_for_incoming = std::move(readable);
  509. run_loop_for_incoming_stream.Quit();
  510. }));
  511. run_loop_for_incoming_stream.Run();
  512. ASSERT_TRUE(readable_for_incoming);
  513. EXPECT_NE(stream_id, incoming_stream_id);
  514. std::string echo_back = Read(std::move(readable_for_incoming));
  515. EXPECT_EQ("hello", echo_back);
  516. client.WaitUntilIncomingStreamIsClosed(incoming_stream_id);
  517. EXPECT_FALSE(client.has_received_fin_for(stream_id));
  518. EXPECT_TRUE(client.has_received_fin_for(incoming_stream_id));
  519. EXPECT_FALSE(client.has_seen_mojo_connection_error());
  520. std::vector<net::NetLogEntry> resets_sent =
  521. net_log_observer().GetEntriesWithType(
  522. net::NetLogEventType::QUIC_SESSION_RST_STREAM_FRAME_SENT);
  523. EXPECT_EQ(0u, resets_sent.size());
  524. }
  525. // crbug.com/1129847: disabled because it is flaky.
  526. TEST_F(WebTransportTest, DISABLED_EchoOnBidirectionalStream) {
  527. base::RunLoop run_loop_for_handshake;
  528. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  529. TestHandshakeClient test_handshake_client(
  530. handshake_client.InitWithNewPipeAndPassReceiver(),
  531. run_loop_for_handshake.QuitClosure());
  532. CreateWebTransport(GetURL("/echo"),
  533. url::Origin::Create(GURL("https://example.org/")),
  534. std::move(handshake_client));
  535. run_loop_for_handshake.Run();
  536. ASSERT_TRUE(test_handshake_client.has_seen_connection_establishment());
  537. TestClient client(test_handshake_client.PassClientReceiver());
  538. mojo::Remote<mojom::WebTransport> transport_remote(
  539. test_handshake_client.PassTransport());
  540. mojo::ScopedDataPipeConsumerHandle readable_for_outgoing;
  541. mojo::ScopedDataPipeProducerHandle writable_for_outgoing;
  542. mojo::ScopedDataPipeConsumerHandle readable_for_incoming;
  543. mojo::ScopedDataPipeProducerHandle writable_for_incoming;
  544. const MojoCreateDataPipeOptions options = {
  545. sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 4 * 1024};
  546. ASSERT_EQ(MOJO_RESULT_OK,
  547. mojo::CreateDataPipe(&options, writable_for_outgoing,
  548. readable_for_outgoing));
  549. ASSERT_EQ(MOJO_RESULT_OK,
  550. mojo::CreateDataPipe(&options, writable_for_incoming,
  551. readable_for_incoming));
  552. uint32_t size = 5;
  553. ASSERT_EQ(MOJO_RESULT_OK, writable_for_outgoing->WriteData(
  554. "hello", &size, MOJO_WRITE_DATA_FLAG_NONE));
  555. base::RunLoop run_loop_for_stream_creation;
  556. uint32_t stream_id;
  557. bool stream_created;
  558. transport_remote->CreateStream(
  559. std::move(readable_for_outgoing), std::move(writable_for_incoming),
  560. base::BindLambdaForTesting([&](bool b, uint32_t id) {
  561. stream_created = b;
  562. stream_id = id;
  563. run_loop_for_stream_creation.Quit();
  564. }));
  565. run_loop_for_stream_creation.Run();
  566. ASSERT_TRUE(stream_created);
  567. // Signal the end-of-data.
  568. writable_for_outgoing.reset();
  569. transport_remote->SendFin(stream_id);
  570. std::string echo_back = Read(std::move(readable_for_incoming));
  571. EXPECT_EQ("hello", echo_back);
  572. client.WaitUntilIncomingStreamIsClosed(stream_id);
  573. EXPECT_FALSE(client.has_seen_mojo_connection_error());
  574. EXPECT_TRUE(client.has_received_fin_for(stream_id));
  575. EXPECT_TRUE(client.stream_is_closed_as_incoming_stream(stream_id));
  576. }
  577. class WebTransportWithCustomCertificateTest : public WebTransportTest {
  578. public:
  579. WebTransportWithCustomCertificateTest()
  580. : WebTransportTest(CreateProofSource()) {
  581. auto helper = std::make_unique<TestConnectionHelper>();
  582. // Set clock to a time in which quic-short-lived.pem is valid
  583. // (2020-06-05T20:35:00.000Z).
  584. helper->clock().set_wall_now(
  585. quic::QuicWallTime::FromUNIXSeconds(1591389300));
  586. mutable_network_context()
  587. .url_request_context()
  588. ->quic_context()
  589. ->SetHelperForTesting(std::move(helper));
  590. }
  591. ~WebTransportWithCustomCertificateTest() override = default;
  592. static std::unique_ptr<quic::ProofSource> CreateProofSource() {
  593. auto proof_source = std::make_unique<net::ProofSourceChromium>();
  594. base::FilePath certs_dir = net::GetTestCertsDirectory();
  595. base::FilePath cert_path = certs_dir.AppendASCII("quic-short-lived.pem");
  596. base::FilePath key_path = certs_dir.AppendASCII("quic-ecdsa-leaf.key");
  597. std::string cert_pem, key_raw;
  598. if (!base::ReadFileToString(cert_path, &cert_pem)) {
  599. ADD_FAILURE() << "Failed to load the certificate from " << cert_path;
  600. return nullptr;
  601. }
  602. if (!base::ReadFileToString(key_path, &key_raw)) {
  603. ADD_FAILURE() << "Failed to load the private key from " << key_path;
  604. return nullptr;
  605. }
  606. net::PEMTokenizer pem_tokenizer(cert_pem, {"CERTIFICATE"});
  607. if (!pem_tokenizer.GetNext()) {
  608. ADD_FAILURE() << "No certificates found in " << cert_path;
  609. return nullptr;
  610. }
  611. auto chain =
  612. quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>(
  613. new quic::ProofSource::Chain(
  614. std::vector<std::string>{pem_tokenizer.data()}));
  615. std::unique_ptr<quic::CertificatePrivateKey> key =
  616. quic::CertificatePrivateKey::LoadFromDer(key_raw);
  617. if (!key) {
  618. ADD_FAILURE() << "Failed to parse the key file " << key_path;
  619. return nullptr;
  620. }
  621. return quic::ProofSourceX509::Create(std::move(chain), std::move(*key));
  622. }
  623. };
  624. TEST_F(WebTransportWithCustomCertificateTest, WithValidFingerprint) {
  625. base::RunLoop run_loop_for_handshake;
  626. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  627. TestHandshakeClient test_handshake_client(
  628. handshake_client.InitWithNewPipeAndPassReceiver(),
  629. run_loop_for_handshake.QuitClosure());
  630. auto fingerprint = mojom::WebTransportCertificateFingerprint::New(
  631. "sha-256",
  632. "6E:8E:7B:43:2A:30:B2:A8:5F:59:56:85:64:C2:48:E9:35:"
  633. "CB:63:B0:7A:E9:F5:CA:3C:35:6F:CB:CC:E8:8D:1B");
  634. std::vector<mojom::WebTransportCertificateFingerprintPtr> fingerprints;
  635. fingerprints.push_back(std::move(fingerprint));
  636. CreateWebTransport(GetURL("/echo"), origin(), std::move(fingerprints),
  637. std::move(handshake_client));
  638. run_loop_for_handshake.Run();
  639. EXPECT_TRUE(test_handshake_client.has_seen_connection_establishment());
  640. EXPECT_FALSE(test_handshake_client.has_seen_handshake_failure());
  641. EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
  642. EXPECT_EQ(1u, network_context().NumOpenWebTransports());
  643. }
  644. TEST_F(WebTransportWithCustomCertificateTest, WithInvalidFingerprint) {
  645. base::RunLoop run_loop_for_handshake;
  646. mojo::PendingRemote<mojom::WebTransportHandshakeClient> handshake_client;
  647. TestHandshakeClient test_handshake_client(
  648. handshake_client.InitWithNewPipeAndPassReceiver(),
  649. run_loop_for_handshake.QuitClosure());
  650. auto fingerprint = network::mojom::WebTransportCertificateFingerprint::New(
  651. "sha-256",
  652. "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:"
  653. "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00");
  654. std::vector<mojom::WebTransportCertificateFingerprintPtr> fingerprints;
  655. fingerprints.push_back(std::move(fingerprint));
  656. CreateWebTransport(GetURL("/echo"), origin(), std::move(fingerprints),
  657. std::move(handshake_client));
  658. run_loop_for_handshake.Run();
  659. EXPECT_FALSE(test_handshake_client.has_seen_connection_establishment());
  660. EXPECT_TRUE(test_handshake_client.has_seen_handshake_failure());
  661. EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
  662. EXPECT_EQ(0u, network_context().NumOpenWebTransports());
  663. }
  664. } // namespace
  665. } // namespace network