@fails-components/webtransport 0.3.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/lib/client.js +81 -40
  2. package/lib/dom.ts +7 -5
  3. package/lib/http2/browser/browser.js +168 -0
  4. package/lib/http2/browser/browserparser.js +248 -0
  5. package/lib/http2/flowcontroller.js +371 -0
  6. package/lib/http2/node/capsuleparser.js +291 -0
  7. package/lib/http2/node/client.js +239 -0
  8. package/lib/http2/node/index.js +2 -0
  9. package/lib/http2/node/server.js +499 -0
  10. package/lib/http2/node/websocketparser.js +829 -0
  11. package/lib/http2/parserbase.js +139 -0
  12. package/lib/http2/parserbasehttp2.js +128 -0
  13. package/lib/http2/session.js +225 -0
  14. package/lib/http2/stream.js +354 -0
  15. package/lib/http2/websocketcommon.js +1 -0
  16. package/lib/{index.js → index.browser.js} +6 -10
  17. package/lib/index.node.js +27 -0
  18. package/lib/server.js +252 -69
  19. package/lib/session.js +31 -68
  20. package/lib/stream.js +103 -179
  21. package/lib/types.ts +174 -87
  22. package/lib/utils.js +2 -1
  23. package/lib/webstreams.browser.js +6 -0
  24. package/lib/webstreams.js +7 -0
  25. package/lib/webtransport.browser.js +284 -0
  26. package/lib/webtransport.node.js +137 -0
  27. package/lib/{webtransport.js → webtransportbase.js} +47 -41
  28. package/old_test/test.js +31 -29
  29. package/old_test/testsuite.js +1 -1
  30. package/package.json +18 -17
  31. package/readme.md +94 -30
  32. package/test/bidirectional-streams.spec.js +51 -9
  33. package/test/datagrams.spec.js +8 -2
  34. package/test/fixtures/known-bytes.js +29 -0
  35. package/test/fixtures/read-stream.js +1 -1
  36. package/test/fixtures/reader-value.js +1 -1
  37. package/test/fixtures/server.js +24 -10
  38. package/test/fixtures/webtransport.browser.js +20 -2
  39. package/test/fixtures/webtransport.js +1 -1
  40. package/test/index.js +33 -6
  41. package/test/pw-no-https-errors.json +5 -0
  42. package/test/session.spec.js +71 -52
  43. package/test/unidirectional-streams.spec.js +20 -4
  44. package/CMakeLists.txt +0 -991
  45. package/LICENSE.chromium +0 -27
  46. package/LICENSE.envoy +0 -207
  47. package/build.js +0 -313
  48. package/dist/lib/client.d.ts +0 -78
  49. package/dist/lib/client.d.ts.map +0 -1
  50. package/dist/lib/dom.d.ts +0 -87
  51. package/dist/lib/dom.d.ts.map +0 -1
  52. package/dist/lib/error.d.ts +0 -8
  53. package/dist/lib/error.d.ts.map +0 -1
  54. package/dist/lib/event-loop.d.ts +0 -33
  55. package/dist/lib/event-loop.d.ts.map +0 -1
  56. package/dist/lib/index.d.ts +0 -79
  57. package/dist/lib/index.d.ts.map +0 -1
  58. package/dist/lib/native.d.ts +0 -2
  59. package/dist/lib/native.d.ts.map +0 -1
  60. package/dist/lib/server.d.ts +0 -92
  61. package/dist/lib/server.d.ts.map +0 -1
  62. package/dist/lib/session.d.ts +0 -298
  63. package/dist/lib/session.d.ts.map +0 -1
  64. package/dist/lib/stream.d.ts +0 -135
  65. package/dist/lib/stream.d.ts.map +0 -1
  66. package/dist/lib/transport.d.ts +0 -34
  67. package/dist/lib/transport.d.ts.map +0 -1
  68. package/dist/lib/types.d.ts +0 -212
  69. package/dist/lib/types.d.ts.map +0 -1
  70. package/dist/lib/utils.d.ts +0 -11
  71. package/dist/lib/utils.d.ts.map +0 -1
  72. package/dist/lib/webtransport.d.ts +0 -47
  73. package/dist/lib/webtransport.d.ts.map +0 -1
  74. package/dist/test/bidirectional-streams.spec.d.ts +0 -5
  75. package/dist/test/bidirectional-streams.spec.d.ts.map +0 -1
  76. package/dist/test/datagrams.spec.d.ts +0 -5
  77. package/dist/test/datagrams.spec.d.ts.map +0 -1
  78. package/dist/test/event-loop.node.d.ts +0 -2
  79. package/dist/test/event-loop.node.d.ts.map +0 -1
  80. package/dist/test/fixtures/certificate.d.ts +0 -21
  81. package/dist/test/fixtures/certificate.d.ts.map +0 -1
  82. package/dist/test/fixtures/chai.d.ts +0 -2
  83. package/dist/test/fixtures/chai.d.ts.map +0 -1
  84. package/dist/test/fixtures/known-bytes.d.ts +0 -6
  85. package/dist/test/fixtures/known-bytes.d.ts.map +0 -1
  86. package/dist/test/fixtures/p-timeout.d.ts +0 -8
  87. package/dist/test/fixtures/p-timeout.d.ts.map +0 -1
  88. package/dist/test/fixtures/read-cert-hash.d.ts +0 -6
  89. package/dist/test/fixtures/read-cert-hash.d.ts.map +0 -1
  90. package/dist/test/fixtures/read-stream.d.ts +0 -19
  91. package/dist/test/fixtures/read-stream.d.ts.map +0 -1
  92. package/dist/test/fixtures/reader-value.d.ts +0 -22
  93. package/dist/test/fixtures/reader-value.d.ts.map +0 -1
  94. package/dist/test/fixtures/server.d.ts +0 -5
  95. package/dist/test/fixtures/server.d.ts.map +0 -1
  96. package/dist/test/fixtures/webtransport.browser.d.ts +0 -3
  97. package/dist/test/fixtures/webtransport.browser.d.ts.map +0 -1
  98. package/dist/test/fixtures/webtransport.d.ts +0 -3
  99. package/dist/test/fixtures/webtransport.d.ts.map +0 -1
  100. package/dist/test/fixtures/write-stream.d.ts +0 -10
  101. package/dist/test/fixtures/write-stream.d.ts.map +0 -1
  102. package/dist/test/index.d.ts +0 -2
  103. package/dist/test/index.d.ts.map +0 -1
  104. package/dist/test/session.spec.d.ts +0 -5
  105. package/dist/test/session.spec.d.ts.map +0 -1
  106. package/dist/test/unidirectional-streams.spec.d.ts +0 -2
  107. package/dist/test/unidirectional-streams.spec.d.ts.map +0 -1
  108. package/failslogolicensereadme.txt +0 -4
  109. package/lib/event-loop.js +0 -88
  110. package/lib/native.js +0 -28
  111. package/lib/transport.js +0 -82
  112. package/platform/icufix/fakedata.cpp +0 -8
  113. package/platform/quiche/quic/core/io/socket_win.inc +0 -3
  114. package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +0 -7
  115. package/platform/quiche_platform_impl/quiche_client_stats_impl.h +0 -7
  116. package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +0 -7
  117. package/platform/quiche_platform_impl/quiche_containers_impl.h +0 -7
  118. package/platform/quiche_platform_impl/quiche_event_loop_impl.h +0 -7
  119. package/platform/quiche_platform_impl/quiche_export_impl.h +0 -6
  120. package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +0 -11
  121. package/platform/quiche_platform_impl/quiche_flags_impl.h +0 -8
  122. package/platform/quiche_platform_impl/quiche_iovec_impl.h +0 -10
  123. package/platform/quiche_platform_impl/quiche_logging_impl.h +0 -21
  124. package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +0 -2
  125. package/platform/quiche_platform_impl/quiche_mutex_impl.h +0 -8
  126. package/platform/quiche_platform_impl/quiche_prefetch_impl.h +0 -11
  127. package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +0 -16
  128. package/platform/quiche_platform_impl/quiche_server_stats_impl.h +0 -7
  129. package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +0 -12
  130. package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +0 -8
  131. package/platform/quiche_platform_impl/quiche_testvalue_impl.h +0 -1
  132. package/platform/quiche_platform_impl/quiche_thread_local_impl.h +0 -6
  133. package/platform/quiche_platform_impl/quiche_time_utils_impl.h +0 -13
  134. package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +0 -39
  135. package/src/http3backendresponse.cc +0 -36
  136. package/src/http3backendresponse.h +0 -109
  137. package/src/http3client.cc +0 -1529
  138. package/src/http3client.h +0 -557
  139. package/src/http3clientsession.cc +0 -65
  140. package/src/http3clientsession.h +0 -60
  141. package/src/http3clientstream.cc +0 -52
  142. package/src/http3clientstream.h +0 -42
  143. package/src/http3dispatcher.cc +0 -62
  144. package/src/http3dispatcher.h +0 -57
  145. package/src/http3eventloop.cc +0 -1107
  146. package/src/http3eventloop.h +0 -316
  147. package/src/http3server.cc +0 -514
  148. package/src/http3server.h +0 -151
  149. package/src/http3serverbackend.cc +0 -105
  150. package/src/http3serverbackend.h +0 -98
  151. package/src/http3serversession.cc +0 -123
  152. package/src/http3serversession.h +0 -95
  153. package/src/http3serverstream.cc +0 -463
  154. package/src/http3serverstream.h +0 -114
  155. package/src/http3sessioncache.cc +0 -85
  156. package/src/http3sessioncache.h +0 -59
  157. package/src/http3wtsessionvisitor.cc +0 -46
  158. package/src/http3wtsessionvisitor.h +0 -397
  159. package/src/http3wtstreamvisitor.cc +0 -155
  160. package/src/http3wtstreamvisitor.h +0 -404
  161. package/test/event-loop.node.js +0 -24
  162. package/tsconfig.json +0 -39
@@ -1,1529 +0,0 @@
1
- // Copyright (c) 2022 Marten Richter or other contributers (see commit). 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
-
5
- // portions taken from libquiche or Chromium, original copyright, see LICENSE.chromium
6
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
7
- // Use of this source code is governed by a BSD-style license that can be
8
- // found in the LICENSE file.
9
-
10
- #include "src/http3client.h"
11
- #include "src/http3eventloop.h"
12
- #include "src/http3clientsession.h"
13
- #include "src/http3wtsessionvisitor.h"
14
- #include "src/http3sessioncache.h"
15
-
16
- #include <memory>
17
- #include <utility>
18
- #include <vector>
19
-
20
- #include "absl/strings/match.h"
21
- #include "absl/strings/string_view.h"
22
- #include "absl/cleanup/cleanup.h"
23
- #include "openssl/x509.h"
24
- #include "quiche/quic/core/crypto/proof_verifier.h"
25
- #include "quiche/quic/core/http/quic_spdy_client_stream.h"
26
- #include "quiche/quic/core/http/spdy_utils.h"
27
- #include "quiche/quic/core/http/web_transport_http3.h"
28
- #include "quiche/quic/core/web_transport_interface.h"
29
- #include "quiche/quic/core/quic_default_packet_writer.h"
30
- #include "quiche/quic/core/quic_default_connection_helper.h"
31
- #include "quiche/quic/core/quic_default_clock.h"
32
- #include "quiche/quic/core/quic_packet_writer_wrapper.h"
33
- #include "quiche/quic/core/quic_server_id.h"
34
- #include "quiche/quic/core/quic_utils.h"
35
- #include "quiche/quic/platform/api/quic_flags.h"
36
- #include "quiche/quic/platform/api/quic_logging.h"
37
- #include "quiche/quic/platform/api/quic_stack_trace.h"
38
- //#include "quiche/quic/test_tools/crypto_test_utils.h"
39
- #include "quiche/quic/core/quic_udp_socket.h"
40
- #include "quiche/quic/tools/quic_url.h"
41
- #include "quiche/common/quiche_text_utils.h"
42
-
43
- using spdy::Http2HeaderBlock;
44
-
45
- namespace quic
46
- {
47
-
48
- // taken from libquiche
49
- namespace
50
- {
51
-
52
- // For level-triggered I/O, we need to manually rearm the kSocketEventWritable
53
- // listener whenever the socket gets blocked.
54
- class LevelTriggeredPacketWriter : public QuicDefaultPacketWriter
55
- {
56
- public:
57
- explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop *event_loop)
58
- : QuicDefaultPacketWriter(fd), event_loop_(event_loop)
59
- {
60
- QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered());
61
- }
62
-
63
- WriteResult WritePacket(const char *buffer, size_t buf_len,
64
- const QuicIpAddress &self_address,
65
- const QuicSocketAddress &peer_address,
66
- PerPacketOptions *options,
67
- const quic::QuicPacketWriterParams& wparams) override
68
- {
69
- WriteResult result = QuicDefaultPacketWriter::WritePacket(
70
- buffer, buf_len, self_address, peer_address, options, wparams);
71
- if (IsWriteBlockedStatus(result.status))
72
- {
73
- bool success = event_loop_->RearmSocket(fd(), kSocketEventWritable);
74
- QUICHE_DCHECK(success);
75
- }
76
- return result;
77
- }
78
-
79
- private:
80
- QuicEventLoop *event_loop_;
81
- };
82
-
83
- } // namespace
84
-
85
- // taken from chromium to behave like the browser
86
- // A version of WebTransportFingerprintProofVerifier that enforces
87
- // Chromium-specific policies.
88
- class ChromiumWebTransportFingerprintProofVerifier
89
- : public quic::WebTransportFingerprintProofVerifier
90
- {
91
- public:
92
- using WebTransportFingerprintProofVerifier::
93
- WebTransportFingerprintProofVerifier;
94
-
95
- protected:
96
- bool IsKeyTypeAllowedByPolicy(
97
- const quic::CertificateView &certificate) override
98
- {
99
- if (certificate.public_key_type() == quic::PublicKeyType::kRsa)
100
- {
101
- return false;
102
- }
103
- return WebTransportFingerprintProofVerifier::IsKeyTypeAllowedByPolicy(
104
- certificate);
105
- }
106
- };
107
-
108
- QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
109
- QuicTransportVersion version, int n)
110
- {
111
- int num = n;
112
- if (!VersionUsesHttp3(version))
113
- {
114
- num++;
115
- }
116
- return QuicUtils::GetFirstBidirectionalStreamId(version,
117
- Perspective::IS_CLIENT) +
118
- QuicUtils::StreamIdDelta(version) * num;
119
- }
120
-
121
- Http3Client::Http3Client(Http3EventLoop *eventloop,
122
- QuicSocketAddress server_address, const std::string &server_hostname,
123
- int local_port,
124
- std::unique_ptr<ProofVerifier> proof_verifier,
125
- std::unique_ptr<SessionCache> session_cache,
126
- std::unique_ptr<QuicConnectionHelperInterface> helper)
127
- : server_id_(QuicServerId(server_hostname, server_address.port(), false)),
128
- initialized_(false),
129
- local_port_(local_port),
130
- store_response_(false),
131
- latest_response_code_(-1),
132
- overflow_supported_(false),
133
- packets_dropped_(0),
134
- packet_reader_(new QuicPacketReader()),
135
- crypto_config_(std::move(proof_verifier), std::move(session_cache)),
136
- helper_(std::move(helper)),
137
- eventloop_(eventloop),
138
- alarm_factory_(eventloop->getQuicEventLoop()->CreateAlarmFactory()),
139
- supported_versions_({ParsedQuicVersion::RFCv1()}),
140
- initial_max_packet_length_(0),
141
- num_sent_client_hellos_(0),
142
- js_(nullptr),
143
- connection_error_(QUIC_NO_ERROR),
144
- connected_or_attempting_connect_(false),
145
- server_connection_id_length_(kQuicDefaultConnectionIdLength),
146
- client_connection_id_length_(0),
147
- max_reads_per_loop_(std::numeric_limits<int>::max()),
148
- wait_for_encryption_(false),
149
- connection_in_progress_(false),
150
- num_attempts_connect_(0),
151
- webtransport_server_support_inform_(false),
152
- connection_debug_visitor_(nullptr),
153
- priority_(HttpStreamPriority())
154
- {
155
- set_server_address(server_address);
156
- Initialize();
157
- }
158
-
159
- Http3Client::~Http3Client()
160
- {
161
- // printf("client destruct %x\n", this);
162
- }
163
-
164
- bool Http3Client::closeClientInt()
165
- {
166
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
167
- {
168
- stream.second->set_visitor(nullptr);
169
- }
170
- if (connected())
171
- {
172
- session_->connection()->CloseConnection(
173
- QUIC_PEER_GOING_AWAY, "Client being torn down",
174
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
175
- }
176
- // We own the push promise index. We need to explicitly kill
177
- // the session before the push promise index goes out of scope.
178
- ResetSession();
179
-
180
- CleanUpAllUDPSockets();
181
-
182
- eventloop_->informUnref(this->getJS());
183
- return true;
184
- }
185
-
186
- void Http3Client::Initialize()
187
- {
188
- priority_ = QuicStreamPriority(HttpStreamPriority());
189
- connect_attempted_ = false;
190
- auto_reconnect_ = false;
191
- buffer_body_ = true;
192
- num_requests_ = 0;
193
- num_responses_ = 0;
194
- ClearPerConnectionState();
195
- // As chrome will generally do this, we want it to be the default when it's
196
- // not overridden.
197
- if (!config_.HasSetBytesForConnectionIdToSend())
198
- {
199
- config_.SetBytesForConnectionIdToSend(0);
200
- }
201
- }
202
-
203
- void Http3Client::SetUserAgentID(const std::string &user_agent_id)
204
- {
205
- crypto_config_.set_user_agent_id(user_agent_id);
206
- }
207
-
208
- void Http3Client::SendRequest(const std::string &uri)
209
- {
210
- spdy::Http2HeaderBlock headers;
211
- if (!PopulateHeaderBlockFromUrl(uri, &headers))
212
- {
213
- return;
214
- }
215
- SendMessageAsync(headers, "");
216
- }
217
-
218
- void Http3Client::SendRequestAndRstTogether(const std::string &uri)
219
- {
220
- spdy::Http2HeaderBlock headers;
221
- if (!PopulateHeaderBlockFromUrl(uri, &headers))
222
- {
223
- return;
224
- }
225
-
226
- QuicSpdyClientSession *session = session_.get();
227
- QuicConnection::ScopedPacketFlusher flusher(session->connection());
228
- SendMessageAsync(headers, "", /*fin=*/true);
229
-
230
- QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
231
- session->transport_version(), 0);
232
- session->ResetStream(stream_id, QUIC_STREAM_CANCELLED);
233
- }
234
-
235
- void Http3Client::GetOrCreateStreamAndSendRequest(
236
- const spdy::Http2HeaderBlock *headers, absl::string_view body, bool fin)
237
- {
238
- if (headers)
239
- {
240
- QuicClientPushPromiseIndex::TryHandle *handle;
241
- QuicAsyncStatus rv =
242
- push_promise_index_.Try(*headers, this, &handle);
243
- if (rv == QUIC_SUCCESS)
244
- return;
245
- if (rv == QUIC_PENDING)
246
- {
247
- // May need to retry request if asynchronous rendezvous fails.
248
- std::unique_ptr<spdy::Http2HeaderBlock> new_headers(
249
- new spdy::Http2HeaderBlock(headers->Clone()));
250
- push_promise_data_to_resend_ = std::make_unique<Http3ClientDataToResend>(
251
- std::move(new_headers), body, fin, this);
252
- return;
253
- }
254
- }
255
-
256
- std::shared_ptr<spdy::Http2HeaderBlock> spdy_headers;
257
- bool hasheaders = false;
258
- if (headers != nullptr)
259
- {
260
- spdy_headers = std::make_shared<spdy::Http2HeaderBlock>(headers->Clone());
261
- hasheaders = true;
262
- }
263
-
264
- // Maybe it's better just to overload this. it's just that we need
265
- // for the GetOrCreateStream function to call something else...which
266
- // is icky and complicated, but maybe not worse than this.
267
- RunOnStreamMaybeCreateStream(
268
- [spdy_headers, hasheaders, body, fin, this](QuicSpdyClientStream *stream)
269
- {
270
- if (stream == nullptr)
271
- {
272
- return;
273
- }
274
- // QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener);
275
-
276
- ssize_t ret = 0;
277
- if (hasheaders)
278
- {
279
- if ((*spdy_headers.get())[":authority"].as_string().empty())
280
- {
281
- (*spdy_headers.get())[":authority"] = server_id_.host();
282
- }
283
- ret = stream->SendRequest(std::move(*spdy_headers.get()), body, fin);
284
- ++num_requests_;
285
- }
286
- else
287
- {
288
- stream->WriteOrBufferBody(std::string(body), fin);
289
- ret = body.length();
290
- }
291
- });
292
- }
293
-
294
- void Http3Client::SendMessageAsync(const spdy::Http2HeaderBlock &headers,
295
- absl::string_view body)
296
- {
297
- return SendMessageAsync(headers, body, /*fin=*/true);
298
- }
299
-
300
- void Http3Client::SendMessageAsync(const spdy::Http2HeaderBlock &headers,
301
- absl::string_view body, bool fin)
302
- {
303
- // Always force creation of a stream for SendMessage.
304
- latest_created_stream_ = nullptr;
305
-
306
- GetOrCreateStreamAndSendRequest(&headers, body, fin);
307
- }
308
-
309
- bool Http3Client::response_complete() const { return response_complete_; }
310
-
311
- int64_t Http3Client::response_body_size() const
312
- {
313
- return response_body_size_;
314
- }
315
-
316
- bool Http3Client::buffer_body() const { return buffer_body_; }
317
-
318
- void Http3Client::set_buffer_body(bool buffer_body)
319
- {
320
- buffer_body_ = buffer_body;
321
- }
322
-
323
- const std::string &Http3Client::response_body() const { return response_; }
324
-
325
- void Http3Client::SendConnectivityProbing()
326
- {
327
- QuicConnection *connection = session_->connection();
328
- connection->SendConnectivityProbingPacket(connection->writer(),
329
- connection->peer_address());
330
- }
331
-
332
- void Http3Client::SetLatestCreatedStream(QuicSpdyClientStream *stream)
333
- {
334
- latest_created_stream_ = stream;
335
- if (latest_created_stream_ != nullptr)
336
- {
337
- open_streams_[stream->id()] = stream;
338
- stream->set_visitor(this);
339
- }
340
- }
341
-
342
- void Http3Client::CreateClientStream(std::function<void(QuicSpdyClientStream *)> finish)
343
- {
344
- if (!connected())
345
- {
346
- finish(nullptr);
347
- }
348
- finish_stream_open_.push(finish);
349
-
350
- checkSession(); // check if it is already available
351
- /*
352
- if (VersionHasIetfQuicFrames(session_->transport_version()))
353
- {
354
- // Process MAX_STREAMS from peer or wait for liveness testing succeeds.
355
- while (!session_->CanOpenNextOutgoingBidirectionalStream())
356
- {
357
- RunEventLoop();
358
- }
359
- }
360
- auto *stream = static_cast<QuicSpdyClientStream *>(
361
- session_->CreateOutgoingBidirectionalStream());
362
- if (stream)
363
- {
364
- stream->set_visitor(this);
365
- }
366
- return stream; */
367
- }
368
-
369
- void Http3Client::RunOnStreamMaybeCreateStream(std::function<void(QuicSpdyClientStream *)> finish)
370
- {
371
- if (!connect_attempted_ || auto_reconnect_)
372
- {
373
- if (!connected())
374
- {
375
- Connect();
376
- }
377
- if (!connected())
378
- {
379
- finish(nullptr);
380
- return;
381
- }
382
- }
383
- if (open_streams_.empty())
384
- {
385
- ClearPerConnectionState();
386
- }
387
- if (!latest_created_stream_)
388
- {
389
- CreateClientStream(
390
- [this, finish](QuicSpdyClientStream *stream)
391
- {
392
- SetLatestCreatedStream(stream);
393
- if (latest_created_stream_)
394
- {
395
- latest_created_stream_->SetPriority(priority_);
396
- }
397
- finish(latest_created_stream_);
398
- });
399
- }
400
- else
401
- {
402
- finish(latest_created_stream_);
403
- }
404
- }
405
-
406
- QuicErrorCode Http3Client::connection_error() const
407
- {
408
- // Return the high-level error if there was one. Otherwise, return the
409
- // connection error from the last session.
410
- if (connection_error_ != QUIC_NO_ERROR)
411
- {
412
- return connection_error_;
413
- }
414
- if (session_ == nullptr)
415
- {
416
- return QUIC_NO_ERROR;
417
- }
418
- return session_->error();
419
- }
420
-
421
- const QuicTagValueMap &Http3Client::GetServerConfig()
422
- {
423
- const QuicCryptoClientConfig::CachedState *state =
424
- crypto_config_.LookupOrCreate(server_id_);
425
- const CryptoHandshakeMessage *handshake_msg = state->GetServerConfig();
426
- return handshake_msg->tag_value_map();
427
- }
428
-
429
- bool Http3Client::connected() const
430
- {
431
- return session_.get() && session_->connection() &&
432
- session_->connection()->connected();
433
- }
434
-
435
- bool Http3Client::clientInitialize()
436
- {
437
- num_sent_client_hellos_ = 0;
438
- connection_error_ = QUIC_NO_ERROR;
439
- connected_or_attempting_connect_ = false;
440
-
441
- // If an initial flow control window has not explicitly been set, then use the
442
- // same values that Chrome uses.
443
- const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
444
- const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
445
- if (config_.GetInitialStreamFlowControlWindowToSend() ==
446
- kDefaultFlowControlSendWindow)
447
- {
448
- config_.SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
449
- }
450
- if (config_.GetInitialSessionFlowControlWindowToSend() ==
451
- kDefaultFlowControlSendWindow)
452
- {
453
- config_.SetInitialSessionFlowControlWindowToSend(
454
- kSessionMaxRecvWindowSize);
455
- }
456
-
457
- if (!CreateUDPSocketAndBind(server_address_,
458
- bind_to_address_, local_port_))
459
- {
460
- eventloop_->informAboutClientConnected(this, false);
461
- return false;
462
- }
463
-
464
- initialized_ = true;
465
- return true;
466
- }
467
-
468
- bool Http3Client::CreateUDPSocketAndBind(
469
- QuicSocketAddress server_address, QuicIpAddress bind_to_address,
470
- int bind_to_port)
471
- {
472
-
473
- QuicUdpSocketApi api;
474
- QuicUdpSocketFd fd = api.Create(server_address.host().AddressFamilyToInt(),
475
- /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
476
- /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
477
- if (fd == kQuicInvalidSocketFd)
478
- {
479
- return false;
480
- }
481
-
482
- overflow_supported_ = api.EnableDroppedPacketCount(fd);
483
- api.EnableReceiveTimestamp(fd);
484
-
485
- auto closer = absl::MakeCleanup([fd]
486
- { QuicUdpSocketApi api;api.Destroy(fd); });
487
-
488
- QuicSocketAddress client_address;
489
- if (bind_to_address.IsInitialized())
490
- {
491
- client_address = QuicSocketAddress(bind_to_address, local_port_);
492
- }
493
- else if (server_address.host().address_family() == IpAddressFamily::IP_V4)
494
- {
495
- client_address = QuicSocketAddress(QuicIpAddress::Any4(), bind_to_port);
496
- }
497
- else
498
- {
499
- client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port);
500
- }
501
-
502
- // Some platforms expect that the addrlen given to bind() exactly matches the
503
- // size of the associated protocol family's sockaddr struct.
504
- // TODO(b/179430548): Revert this when affected platforms are updated to
505
- // to support binding with an addrelen of sizeof(sockaddr_storage)
506
- socklen_t addrlen;
507
- switch (client_address.host().address_family())
508
- {
509
- case IpAddressFamily::IP_V4:
510
- addrlen = sizeof(sockaddr_in);
511
- break;
512
- case IpAddressFamily::IP_V6:
513
- addrlen = sizeof(sockaddr_in6);
514
- break;
515
- case IpAddressFamily::IP_UNSPEC:
516
- addrlen = 0;
517
- break;
518
- }
519
-
520
- if (!api.Bind(fd, client_address))
521
- {
522
- QUIC_LOG(ERROR) << "Bind failed"
523
- << " bind_to_address:" << bind_to_address
524
- << ", bind_to_port:" << bind_to_port
525
- << ", client_address:" << client_address;
526
- return false;
527
- }
528
-
529
- if (client_address.FromSocket(fd) != 0)
530
- {
531
- QUIC_LOG(ERROR) << "Unable to get self address. Error: "
532
- << strerror(errno);
533
- }
534
- const int kEpollFlags = kSocketEventReadable | kSocketEventWritable; // there is no analogue to EPOLLET in libuv hopefully not a problem
535
-
536
- if (eventloop_->getQuicEventLoop()->RegisterSocket(fd, kEpollFlags, this))
537
- {
538
- fd_address_map_[fd] = client_address;
539
- std::move(closer).Cancel();
540
- return true;
541
- }
542
- return false;
543
- }
544
-
545
- void Http3Client::CleanUpUDPSocket(int fd)
546
- {
547
- CleanUpUDPSocketImpl(fd);
548
- fd_address_map_.erase(fd);
549
- }
550
-
551
- void Http3Client::CleanUpAllUDPSockets()
552
- {
553
- for (std::pair<int, QuicSocketAddress> fd_address : fd_address_map_)
554
- {
555
- CleanUpUDPSocketImpl(fd_address.first);
556
- }
557
- fd_address_map_.clear();
558
- }
559
-
560
- void Http3Client::CleanUpUDPSocketImpl(QuicUdpSocketFd fd)
561
- {
562
- if (fd != kQuicInvalidSocketFd)
563
- {
564
- eventloop_->getQuicEventLoop()->UnregisterSocket(fd);
565
- QuicUdpSocketApi api;
566
- api.Destroy(fd);
567
- }
568
- }
569
-
570
- QuicSocketAddress Http3Client::GetLatestClientAddress() const
571
- {
572
- if (fd_address_map_.empty())
573
- {
574
- return QuicSocketAddress();
575
- }
576
-
577
- return fd_address_map_.back().second;
578
- }
579
-
580
- void Http3Client::Connect()
581
- {
582
- if (connected())
583
- {
584
- QUIC_BUG(quic_bug_10133_1) << "Cannot connect already-connected client";
585
- return;
586
- }
587
- if (!connect_attempted_)
588
- {
589
- clientInitialize();
590
- }
591
-
592
- // If we've been asked to override SNI, set it now
593
- if (override_sni_set_)
594
- {
595
- // This should only be set before the initial Connect()
596
- server_id_ = QuicServerId(override_sni_, address().port(), false);
597
- }
598
- connection_in_progress_ = true;
599
- wait_for_encryption_ = false;
600
- }
601
-
602
- bool Http3Client::handleConnecting()
603
- {
604
- bool recheck = false;
605
- if (connection_in_progress_)
606
- {
607
- if (!wait_for_encryption_)
608
- {
609
- if (!connected() && num_attempts_connect_ <= QuicCryptoClientStream::kMaxClientHellos)
610
- {
611
- StartConnect();
612
- wait_for_encryption_ = true;
613
- }
614
- else if (session_ == nullptr && num_attempts_connect_ > QuicCryptoClientStream::kMaxClientHellos)
615
- {
616
- connection_in_progress_ = false;
617
- connect_attempted_ = true;
618
- QUIC_BUG(quic_bug_10906_1) << "Missing session after Connect";
619
- eventloop_->informAboutClientConnected(this, false);
620
- }
621
- }
622
- if (wait_for_encryption_)
623
- {
624
- if (EncryptionBeingEstablished())
625
- return false;
626
- wait_for_encryption_ = false;
627
- ParsedQuicVersion version = UnsupportedQuicVersion();
628
- if (session_ != nullptr && !CanReconnectWithDifferentVersion(&version) && !session_->connection()->connected())
629
- {
630
- // We've successfully created a session but we're not connected, and we
631
- // cannot reconnect with a different version. Give up trying.
632
- connection_in_progress_ = false;
633
- connect_attempted_ = true;
634
- eventloop_->informAboutClientConnected(this, false);
635
- }
636
- else if (session_ != nullptr && session_->connection()->connected())
637
- {
638
- connect_attempted_ = true;
639
- connection_in_progress_ = false;
640
- eventloop_->informAboutClientConnected(this, true);
641
- webtransport_server_support_inform_ = true;
642
- recheck = true;
643
- }
644
- else
645
- {
646
- num_attempts_connect_++;
647
- recheck = true;
648
- }
649
- }
650
- }
651
- if (webtransport_server_support_inform_ && connected())
652
- {
653
- if (session_->SupportsWebTransport())
654
- {
655
- eventloop_->informClientWebtransportSupport(this);
656
- webtransport_server_support_inform_ = false;
657
- }
658
- else
659
- recheck = true;
660
- }
661
-
662
- if (checkSession())
663
- {
664
- recheck = true;
665
- }
666
-
667
- return recheck;
668
- }
669
-
670
- bool Http3Client::checkSession()
671
- {
672
- while (finish_stream_open_.size() > 0 && session_->CanOpenNextOutgoingBidirectionalStream())
673
- {
674
- auto *stream = static_cast<QuicSpdyClientStream *>(
675
- session_->CreateOutgoingBidirectionalStream());
676
- if (stream)
677
- {
678
- stream->set_visitor(this);
679
- }
680
- finish_stream_open_.front()(stream);
681
- if (stream != nullptr)
682
- {
683
- if (stream->web_transport() != nullptr)
684
- {
685
- WebTransportSessionId id = stream->id();
686
- WebTransportHttp3 *wtsession = session_->GetWebTransportSession(id);
687
- if (wtsession == nullptr)
688
- {
689
- eventloop_->informNewClientSession(this, nullptr);
690
- // may be throw error
691
- }
692
- else
693
- {
694
- // ok we have our session, do we wait for session ready, no set visitor immediatele
695
- Http3WTSession *wtsessionobj =
696
- new Http3WTSession();
697
- wtsessionobj->init(
698
- static_cast<WebTransportSession *>(wtsession),
699
- eventloop_);
700
- eventloop_->informNewClientSession(this, wtsessionobj);
701
- auto visitor = std::make_unique<Http3WTSession::Visitor>(wtsessionobj);
702
- wtsession->SetVisitor(std::move(visitor));
703
- }
704
- }
705
- }
706
- finish_stream_open_.pop();
707
- }
708
-
709
- return finish_stream_open_.size() > 0;
710
- }
711
-
712
- void Http3Client::openWTSessionInt(absl::string_view path)
713
- {
714
- spdy::Http2HeaderBlock headers;
715
- headers[":scheme"] = "https";
716
- headers[":authority"] = "localhost";
717
- headers[":path"] = path;
718
- headers[":method"] = "CONNECT";
719
- headers[":protocol"] = "webtransport";
720
-
721
- SendMessageAsync(headers, "", /*fin=*/false);
722
- }
723
-
724
- int Http3Client::GetLatestFD() const
725
- {
726
- if (fd_address_map_.empty())
727
- {
728
- return -1;
729
- }
730
-
731
- return fd_address_map_.back().first;
732
- }
733
-
734
- void Http3Client::StartConnect()
735
- {
736
- QUICHE_DCHECK(initialized_);
737
- QUICHE_DCHECK(!connected());
738
- QuicPacketWriter *writer;
739
- if (eventloop_->getQuicEventLoop()->SupportsEdgeTriggered())
740
- {
741
- writer = new QuicDefaultPacketWriter(GetLatestFD());
742
- }
743
- else
744
- {
745
- writer = new LevelTriggeredPacketWriter(GetLatestFD(), eventloop_->getQuicEventLoop());
746
- }
747
- ParsedQuicVersion mutual_version = UnsupportedQuicVersion();
748
- const bool can_reconnect_with_different_version =
749
- CanReconnectWithDifferentVersion(&mutual_version);
750
- if (connected_or_attempting_connect_)
751
- {
752
- // Clear queued up data if client can not try to connect with a different
753
- // version.
754
- if (!can_reconnect_with_different_version)
755
- {
756
- ClearDataToResend();
757
- }
758
- // Before we destroy the last session and create a new one, gather its stats
759
- // and update the stats for the overall connection.
760
- // no stats for me!
761
- // UpdateStats();
762
- }
763
- QuicConnectionId newconnid = QuicUtils::CreateRandomConnectionId(server_connection_id_length_);
764
-
765
- const quic::ParsedQuicVersionVector client_supported_versions =
766
- can_reconnect_with_different_version
767
- ? ParsedQuicVersionVector{mutual_version}
768
- : supported_versions_;
769
-
770
- session_ = std::make_unique<Http3ClientSession>(
771
- config_, client_supported_versions, new QuicConnection(newconnid, QuicSocketAddress(), server_address_, helper_.get(), alarm_factory_.get(), writer,
772
- /* owns_writer= */ false, Perspective::IS_CLIENT, client_supported_versions, connection_id_generator_),
773
- server_id_, &crypto_config_,
774
- &push_promise_index_, false /*drop_response_body_*/, true /* enable_web_transport */);
775
-
776
- if (can_reconnect_with_different_version)
777
- {
778
- session_->set_client_original_supported_versions(supported_versions_);
779
- }
780
- if (connection_debug_visitor_ != nullptr)
781
- {
782
- session_->connection()->set_debug_visitor(connection_debug_visitor_);
783
- }
784
- session_->connection()->set_client_connection_id(
785
- QuicUtils::CreateRandomConnectionId(client_connection_id_length_));
786
- if (initial_max_packet_length_ != 0)
787
- {
788
- session_->connection()->SetMaxPacketLength(initial_max_packet_length_);
789
- }
790
- // Reset |writer()| after |session()| so that the old writer outlives the old
791
- // session.
792
- if (writer_.get() != writer)
793
- {
794
- writer_.reset(writer);
795
- }
796
- // set_writer(writer);
797
- InitializeSession();
798
- if (can_reconnect_with_different_version)
799
- {
800
- // This is a reconnect using server supported |mutual_version|.
801
- session_->connection()->SetVersionNegotiated();
802
- }
803
- connected_or_attempting_connect_ = true;
804
- }
805
-
806
- void Http3Client::InitializeSession()
807
- {
808
- if (max_inbound_header_list_size_ > 0)
809
- {
810
- session_->set_max_inbound_header_list_size(
811
- max_inbound_header_list_size_);
812
- }
813
- session_->Initialize();
814
- session_->CryptoConnect();
815
- }
816
-
817
- void Http3Client::ResetConnection()
818
- {
819
- Disconnect();
820
- Connect();
821
- }
822
-
823
- void Http3Client::Disconnect()
824
- {
825
- ClearPerConnectionState();
826
- if (initialized_)
827
- {
828
- QUICHE_DCHECK(initialized_);
829
-
830
- initialized_ = false;
831
- if (connected())
832
- {
833
- session_->connection()->CloseConnection(
834
- QUIC_PEER_GOING_AWAY, "Client disconnecting",
835
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
836
- }
837
-
838
- ClearDataToResend();
839
-
840
- CleanUpAllUDPSockets();
841
- }
842
- connect_attempted_ = false;
843
- }
844
-
845
- bool Http3Client::CanReconnectWithDifferentVersion(
846
- ParsedQuicVersion *version) const
847
- {
848
- if (session_ == nullptr || session_->connection() == nullptr ||
849
- session_->error() != QUIC_INVALID_VERSION)
850
- {
851
- return false;
852
- }
853
-
854
- const auto &server_supported_versions =
855
- session_->connection()->server_supported_versions();
856
- if (server_supported_versions.empty())
857
- {
858
- return false;
859
- }
860
-
861
- for (const auto &client_version : supported_versions_)
862
- {
863
- if (std::find(server_supported_versions.begin(),
864
- server_supported_versions.end(),
865
- client_version) != server_supported_versions.end())
866
- {
867
- *version = client_version;
868
- return true;
869
- }
870
- }
871
- return false;
872
- }
873
-
874
- bool Http3Client::EncryptionBeingEstablished()
875
- {
876
- return !session_->IsEncryptionEstablished() &&
877
- session_->connection()->connected();
878
- }
879
-
880
- bool Http3Client::HasActiveRequests()
881
- {
882
- return session_->HasActiveRequestStreams();
883
- }
884
-
885
- QuicSocketAddress Http3Client::local_address() const
886
- {
887
- return GetLatestClientAddress();
888
- }
889
-
890
- void Http3Client::ClearPerRequestState()
891
- {
892
- stream_error_ = QUIC_STREAM_NO_ERROR;
893
- response_ = "";
894
- response_complete_ = false;
895
- response_headers_complete_ = false;
896
- response_headers_.clear();
897
- response_trailers_.clear();
898
- bytes_read_ = 0;
899
- bytes_written_ = 0;
900
- response_body_size_ = 0;
901
- }
902
-
903
- void Http3Client::ClearDataToResend()
904
- {
905
- data_to_resend_on_connect_.clear();
906
- }
907
-
908
- bool Http3Client::HaveActiveStream()
909
- {
910
- return push_promise_data_to_resend_.get() || !open_streams_.empty();
911
- }
912
-
913
- void Http3Client::OnSocketEvent(QuicEventLoop *event_loop, QuicUdpSocketFd fd,
914
- QuicSocketEventMask events)
915
- {
916
- if (events & kSocketEventReadable)
917
- {
918
- QUIC_DVLOG(1) << "Read packets on kSocketEventReadable";
919
- int times_to_read = max_reads_per_loop_;
920
- bool more_to_read = true;
921
- QuicPacketCount packets_dropped = 0;
922
- while (connected() && more_to_read && times_to_read > 0)
923
- {
924
- more_to_read = packet_reader_->ReadAndDispatchPackets(
925
- fd, GetLatestClientAddress().port(), *helper_->GetClock(),
926
- this, overflow_supported_ ? &packets_dropped : nullptr);
927
- --times_to_read;
928
- }
929
- if (packets_dropped_ < packets_dropped)
930
- {
931
- QUIC_LOG(ERROR)
932
- << packets_dropped - packets_dropped_
933
- << " more packets are dropped in the socket receive buffer.";
934
- packets_dropped_ = packets_dropped;
935
- }
936
- if (connected() && more_to_read)
937
- {
938
- // Register EPOLLIN event to consume buffered CHLO(s).
939
- bool success =
940
- event_loop->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
941
- QUICHE_DCHECK(success);
942
- } else if (!event_loop->SupportsEdgeTriggered())
943
- {
944
- bool success = event_loop->RearmSocket(fd, kSocketEventReadable);
945
- QUICHE_DCHECK(success);
946
- }
947
- }
948
- if (connected() && (events & kSocketEventWritable))
949
- {
950
- writer_->SetWritable();
951
- session_->connection()->OnCanWrite();
952
- }
953
-
954
- if (handleConnecting())
955
- {
956
- bool success =
957
- event_loop->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
958
- QUICHE_DCHECK(success);
959
- }
960
- }
961
-
962
- void Http3Client::ProcessPacket(
963
- const QuicSocketAddress &self_address,
964
- const QuicSocketAddress &peer_address, const QuicReceivedPacket &packet)
965
- {
966
- session_->ProcessUdpPacket(self_address, peer_address, packet);
967
- }
968
-
969
- bool Http3Client::response_headers_complete() const
970
- {
971
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
972
- {
973
- if (stream.second->headers_decompressed())
974
- {
975
- return true;
976
- }
977
- }
978
- return response_headers_complete_;
979
- }
980
-
981
- const spdy::Http2HeaderBlock *Http3Client::response_headers() const
982
- {
983
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
984
- {
985
- if (stream.second->headers_decompressed())
986
- {
987
- response_headers_ = stream.second->response_headers().Clone();
988
- break;
989
- }
990
- }
991
- return &response_headers_;
992
- }
993
-
994
- const spdy::Http2HeaderBlock &Http3Client::response_trailers() const
995
- {
996
- return response_trailers_;
997
- }
998
-
999
- int64_t Http3Client::response_size() const { return bytes_read(); }
1000
-
1001
- size_t Http3Client::bytes_read() const
1002
- {
1003
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
1004
- {
1005
- size_t bytes_read = stream.second->total_body_bytes_read() +
1006
- stream.second->header_bytes_read();
1007
- if (bytes_read > 0)
1008
- {
1009
- return bytes_read;
1010
- }
1011
- }
1012
- return bytes_read_;
1013
- }
1014
-
1015
- size_t Http3Client::bytes_written() const
1016
- {
1017
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
1018
- {
1019
- size_t bytes_written = stream.second->stream_bytes_written() +
1020
- stream.second->header_bytes_written();
1021
- if (bytes_written > 0)
1022
- {
1023
- return bytes_written;
1024
- }
1025
- }
1026
- return bytes_written_;
1027
- }
1028
-
1029
- void Http3Client::OnCompleteResponse(
1030
- QuicStreamId id, const spdy::Http2HeaderBlock &response_headers,
1031
- const absl::string_view &response_body)
1032
- {
1033
- // implement
1034
- }
1035
-
1036
- void Http3Client::OnClose(QuicSpdyStream *stream)
1037
- {
1038
- if (stream == nullptr)
1039
- {
1040
- return;
1041
- }
1042
- // Always close the stream, regardless of whether it was the last stream
1043
- // written.
1044
- QUICHE_DCHECK(stream != nullptr);
1045
- QuicSpdyClientStream *client_stream =
1046
- static_cast<QuicSpdyClientStream *>(stream);
1047
-
1048
- const Http2HeaderBlock &response_headers = client_stream->response_headers();
1049
-
1050
- OnCompleteResponse(stream->id(), response_headers, client_stream->data());
1051
-
1052
- // Store response headers and body.
1053
- if (store_response_)
1054
- {
1055
- auto status = response_headers.find(":status");
1056
- if (status == response_headers.end())
1057
- {
1058
- QUIC_LOG(ERROR) << "Missing :status response header";
1059
- }
1060
- else if (!absl::SimpleAtoi(status->second, &latest_response_code_))
1061
- {
1062
- QUIC_LOG(ERROR) << "Invalid :status response header: " << status->second;
1063
- }
1064
- latest_response_headers_ = response_headers.DebugString();
1065
- for (const Http2HeaderBlock &headers :
1066
- client_stream->preliminary_headers())
1067
- {
1068
- absl::StrAppend(&preliminary_response_headers_, headers.DebugString());
1069
- }
1070
- latest_response_header_block_ = response_headers.Clone();
1071
- latest_response_body_ = client_stream->data();
1072
- latest_response_trailers_ =
1073
- client_stream->received_trailers().DebugString();
1074
- }
1075
- ++num_responses_;
1076
- if (open_streams_.find(stream->id()) == open_streams_.end())
1077
- {
1078
- return;
1079
- }
1080
- if (latest_created_stream_ == stream)
1081
- {
1082
- latest_created_stream_ = nullptr;
1083
- }
1084
-
1085
- QuicStreamId id = client_stream->id();
1086
- closed_stream_states_.insert(std::make_pair(
1087
- id,
1088
- PerStreamState(
1089
- // Set response_complete to true iff stream is closed while connected.
1090
- client_stream->stream_error(), connected(),
1091
- client_stream->headers_decompressed(),
1092
- client_stream->response_headers(),
1093
- (buffer_body() ? client_stream->data() : ""),
1094
- client_stream->received_trailers(),
1095
- // Use NumBytesConsumed to avoid counting retransmitted stream frames.
1096
- client_stream->total_body_bytes_read() +
1097
- client_stream->header_bytes_read(),
1098
- client_stream->stream_bytes_written() +
1099
- client_stream->header_bytes_written(),
1100
- client_stream->data().size())));
1101
- open_streams_.erase(id);
1102
- }
1103
-
1104
- bool Http3Client::CheckVary(
1105
- const spdy::Http2HeaderBlock & /*client_request*/,
1106
- const spdy::Http2HeaderBlock & /*promise_request*/,
1107
- const spdy::Http2HeaderBlock & /*promise_response*/)
1108
- {
1109
- return true;
1110
- }
1111
-
1112
- void Http3Client::OnRendezvousResult(QuicSpdyStream *stream)
1113
- {
1114
- std::unique_ptr<Http3ClientDataToResend> data_to_resend =
1115
- std::move(push_promise_data_to_resend_);
1116
- SetLatestCreatedStream(static_cast<QuicSpdyClientStream *>(stream));
1117
- if (stream)
1118
- {
1119
- stream->OnBodyAvailable();
1120
- }
1121
- else if (data_to_resend)
1122
- {
1123
- data_to_resend->Resend();
1124
- }
1125
- }
1126
-
1127
- bool Http3Client::MigrateSocket(const QuicIpAddress &new_host)
1128
- {
1129
- return MigrateSocketWithSpecifiedPort(new_host, local_port_);
1130
- }
1131
-
1132
- bool Http3Client::MigrateSocketWithSpecifiedPort(
1133
- const QuicIpAddress &new_host, int port)
1134
- {
1135
- local_port_ = port;
1136
- if (!connected())
1137
- {
1138
- QUICHE_DVLOG(1)
1139
- << "MigrateSocketWithSpecifiedPort failed as connection has closed";
1140
- return false;
1141
- }
1142
-
1143
- CleanUpAllUDPSockets();
1144
- std::unique_ptr<QuicPacketWriter> writer =
1145
- CreateWriterForNewNetwork(new_host, port);
1146
- if (writer == nullptr)
1147
- {
1148
- QUICHE_DVLOG(1)
1149
- << "MigrateSocketWithSpecifiedPort failed from writer creation";
1150
- return false;
1151
- }
1152
- if (!session_->MigratePath(GetLatestClientAddress(),
1153
- session_->connection()->peer_address(),
1154
- writer.get(), false))
1155
- {
1156
- QUICHE_DVLOG(1)
1157
- << "MigrateSocketWithSpecifiedPort failed from session()->MigratePath";
1158
- return false;
1159
- }
1160
- writer_ = std::move(writer);
1161
- // set_writer(writer.release());
1162
- return true;
1163
- }
1164
-
1165
- std::unique_ptr<QuicPacketWriter> Http3Client::CreateWriterForNewNetwork(
1166
- const QuicIpAddress &new_host, int port)
1167
- {
1168
- set_bind_to_address(new_host);
1169
- local_port_ = port;
1170
- if (!CreateUDPSocketAndBind(server_address_,
1171
- bind_to_address_, port))
1172
- {
1173
- return nullptr;
1174
- }
1175
-
1176
- QuicPacketWriter *writer = new QuicDefaultPacketWriter(GetLatestFD());
1177
- QUIC_LOG_IF(WARNING, writer == writer_.get())
1178
- << "The new writer is wrapped in the same wrapper as the old one, thus "
1179
- "appearing to have the same address as the old one.";
1180
- return std::unique_ptr<QuicPacketWriter>(writer);
1181
- }
1182
-
1183
- QuicIpAddress Http3Client::bind_to_address() const
1184
- {
1185
- return bind_to_address_;
1186
- }
1187
-
1188
- void Http3Client::set_bind_to_address(QuicIpAddress address)
1189
- {
1190
- bind_to_address_ = address;
1191
- }
1192
-
1193
- const QuicSocketAddress &Http3Client::address() const
1194
- {
1195
- return server_address_;
1196
- }
1197
-
1198
- Http3Client::Http3ClientDataToResend::Http3ClientDataToResend(
1199
- std::unique_ptr<spdy::Http2HeaderBlock> headers, absl::string_view body,
1200
- bool fin, Http3Client *client)
1201
- : headers_(std::move(headers)), body_(body), fin_(fin),
1202
- client_(client) {}
1203
-
1204
- Http3Client::Http3ClientDataToResend::~Http3ClientDataToResend() = default;
1205
-
1206
- void Http3Client::Http3ClientDataToResend::Resend()
1207
- {
1208
- client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_);
1209
- headers_.reset();
1210
- }
1211
-
1212
- Http3Client::PerStreamState::PerStreamState(const PerStreamState &other)
1213
- : stream_error(other.stream_error),
1214
- response_complete(other.response_complete),
1215
- response_headers_complete(other.response_headers_complete),
1216
- response_headers(other.response_headers.Clone()),
1217
- response(other.response),
1218
- response_trailers(other.response_trailers.Clone()),
1219
- bytes_read(other.bytes_read),
1220
- bytes_written(other.bytes_written),
1221
- response_body_size(other.response_body_size) {}
1222
-
1223
- Http3Client::PerStreamState::PerStreamState(
1224
- QuicRstStreamErrorCode stream_error, bool response_complete,
1225
- bool response_headers_complete,
1226
- const spdy::Http2HeaderBlock &response_headers,
1227
- const absl::string_view response, const spdy::Http2HeaderBlock &response_trailers,
1228
- uint64_t bytes_read, uint64_t bytes_written, int64_t response_body_size)
1229
- : stream_error(stream_error),
1230
- response_complete(response_complete),
1231
- response_headers_complete(response_headers_complete),
1232
- response_headers(response_headers.Clone()),
1233
- response(response),
1234
- response_trailers(response_trailers.Clone()),
1235
- bytes_read(bytes_read),
1236
- bytes_written(bytes_written),
1237
- response_body_size(response_body_size) {}
1238
-
1239
- Http3Client::PerStreamState::~PerStreamState() = default;
1240
-
1241
- bool Http3Client::PopulateHeaderBlockFromUrl(
1242
- const std::string &uri, spdy::Http2HeaderBlock *headers)
1243
- {
1244
- std::string url;
1245
- if (absl::StartsWith(uri, "https://") || absl::StartsWith(uri, "http://"))
1246
- {
1247
- url = uri;
1248
- }
1249
- else if (uri[0] == '/')
1250
- {
1251
- url = "https://" + server_id_.host() + uri;
1252
- }
1253
- else
1254
- {
1255
- url = "https://" + uri;
1256
- }
1257
- return SpdyUtils::PopulateHeaderBlockFromUrl(url, headers);
1258
- }
1259
-
1260
- /*
1261
- void Http3Client::ReadNextResponse()
1262
- {
1263
- if (closed_stream_states_.empty())
1264
- {
1265
- return;
1266
- }
1267
-
1268
- PerStreamState state(closed_stream_states_.front().second);
1269
-
1270
- stream_error_ = state.stream_error;
1271
- response_ = state.response;
1272
- response_complete_ = state.response_complete;
1273
- response_headers_complete_ = state.response_headers_complete;
1274
- response_headers_ = state.response_headers.Clone();
1275
- response_trailers_ = state.response_trailers.Clone();
1276
- bytes_read_ = state.bytes_read;
1277
- bytes_written_ = state.bytes_written;
1278
- response_body_size_ = state.response_body_size;
1279
-
1280
- closed_stream_states_.pop_front();
1281
- }
1282
- */
1283
-
1284
- void Http3Client::ClearPerConnectionState()
1285
- {
1286
- ClearPerRequestState();
1287
- open_streams_.clear();
1288
- closed_stream_states_.clear();
1289
- latest_created_stream_ = nullptr;
1290
- }
1291
-
1292
- Http3ClientJS::Http3ClientJS(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Http3ClientJS>(info)
1293
- {
1294
-
1295
- std::string port = "443";
1296
- bool allowPooling = false;
1297
- std::vector<WebTransportHash> serverCertificateHashes;
1298
- std::string privkey;
1299
- std::string hostname = "localhost";
1300
- int local_port = 0;
1301
- bool forceipv6 = false;
1302
- auto env = info.Env();
1303
- if (!info[0].IsUndefined())
1304
- {
1305
- Napi::Object lobj = info[0].ToObject();
1306
- if (!lobj.IsEmpty())
1307
- {
1308
-
1309
- if (lobj.Has("allowPooling") && !(lobj).Get("allowPooling").IsEmpty())
1310
- {
1311
- Napi::Value poolValue = (lobj).Get("allowPooling");
1312
- allowPooling = poolValue.As<Napi::Boolean>().Value();
1313
- }
1314
-
1315
- if (lobj.Has("forceIpv6") && !(lobj).Get("forceIpv6").IsEmpty())
1316
- {
1317
- Napi::Value ipv6Value = (lobj).Get("forceIpv6");
1318
- forceipv6 = ipv6Value.As<Napi::Boolean>().Value();
1319
- }
1320
-
1321
- if (lobj.Has("port") && !(lobj).Get("port").IsEmpty())
1322
- {
1323
- Napi::Value portValue = (lobj).Get("port");
1324
- port = portValue.ToString().Utf8Value();
1325
- }
1326
- else
1327
- {
1328
- Napi::Error::New(env, "no port specified").ThrowAsJavaScriptException();
1329
- return;
1330
- }
1331
-
1332
- if (lobj.Has("host") && !(lobj).Get("host").IsEmpty())
1333
- {
1334
- Napi::Value hostnameValue = (lobj).Get("host");
1335
- hostname = hostnameValue.ToString().Utf8Value();
1336
- }
1337
- else
1338
- {
1339
- Napi::Error::New(env, "no hostname specified").ThrowAsJavaScriptException();
1340
- return;
1341
- }
1342
-
1343
- if (lobj.Has("serverCertificateHashes") && !(lobj).Get("serverCertificateHashes").IsEmpty())
1344
- {
1345
- Napi::Value hashValue = (lobj).Get("serverCertificateHashes");
1346
- if (hashValue.IsArray())
1347
- {
1348
- Napi::Array hashArray = hashValue.As<Napi::Array>();
1349
- int length = hashArray.Length();
1350
-
1351
- for (unsigned int i = 0; i < length; i++)
1352
- {
1353
- WebTransportHash curhash;
1354
- Napi::Value hash = hashArray.Get(i);
1355
- Napi::Object hashobj = hash.ToObject();
1356
- if (hashobj.Has("value") && !(hashobj).Get("value").IsEmpty())
1357
- {
1358
- Napi::Object bufferlocal = (hashobj).Get("value").ToObject();
1359
- char *buffer = bufferlocal.As<Napi::Buffer<char>>().Data();
1360
- size_t len = bufferlocal.As<Napi::Buffer<char>>().Length();
1361
- curhash.value = std::string(buffer, len);
1362
- }
1363
- else
1364
- {
1365
- Napi::Error::New(env, "serverCertificateHashes wrong format").ThrowAsJavaScriptException();
1366
- return;
1367
- }
1368
- if (hashobj.Has("algorithm") && !(hashobj).Get("algorithm").IsEmpty())
1369
- {
1370
- Napi::Value algorithmValue = (hashobj).Get("algorithm");
1371
- curhash.algorithm = algorithmValue.ToString().Utf8Value();
1372
- }
1373
- else
1374
- {
1375
- Napi::Error::New(env, "serverCertificateHashes wrong format").ThrowAsJavaScriptException();
1376
- return;
1377
- }
1378
- if (curhash.algorithm.compare(WebTransportHash::kSha256) != 0)
1379
- {
1380
- Napi::Error::New(env, "serverCertificateHashes unknown algorithm").ThrowAsJavaScriptException();
1381
- return;
1382
- }
1383
- serverCertificateHashes.push_back(curhash);
1384
- }
1385
- }
1386
- else
1387
- {
1388
- Napi::Error::New(env, "serverCertificateHashes is not an array").ThrowAsJavaScriptException();
1389
- return;
1390
- }
1391
- }
1392
-
1393
- if (lobj.Has("localPort") && !(lobj).Get("localPort").IsEmpty())
1394
- {
1395
- Napi::Value localPortValue = (lobj).Get("localPort");
1396
- if (localPortValue.IsNumber())
1397
- local_port = localPortValue.As<Napi::Number>().Int32Value();
1398
- else
1399
- {
1400
- Napi::Error::New(env, "localPort is not a number").ThrowAsJavaScriptException();
1401
- return;
1402
- }
1403
- }
1404
- }
1405
- }
1406
-
1407
- // Callback *callback, int port, std::unique_ptr<ProofSource> proof_source, const char *secret
1408
-
1409
- Http3EventLoop *eventloop = nullptr;
1410
- if (!info[1].IsUndefined())
1411
- {
1412
- Napi::Object lobj = info[1].ToObject();
1413
- eventloop = dynamic_cast<Http3EventLoop *>(Napi::ObjectWrap<Http3EventLoop>::Unwrap(lobj));
1414
- }
1415
- else
1416
- {
1417
- Napi::Error::New(env, "No eventloop arguments passed to Http3Client").ThrowAsJavaScriptException();
1418
- return;
1419
- }
1420
-
1421
- std::unique_ptr<QuicConnectionHelperInterface> helper =
1422
- std::make_unique<QuicDefaultConnectionHelper>();
1423
-
1424
- std::unique_ptr<ChromiumWebTransportFingerprintProofVerifier> verifier;
1425
-
1426
- if (serverCertificateHashes.size() > 0)
1427
- {
1428
- verifier = std::make_unique<ChromiumWebTransportFingerprintProofVerifier>(helper->GetClock(), 14);
1429
-
1430
- for (auto cur = serverCertificateHashes.begin();
1431
- cur != serverCertificateHashes.end(); cur++)
1432
- {
1433
- if (!verifier->AddFingerprint(*cur))
1434
- {
1435
- Napi::Error::New(env, "serverCertificateHashes is not valid fingerprint").ThrowAsJavaScriptException();
1436
- return;
1437
- }
1438
- }
1439
- }
1440
- else
1441
- {
1442
- Napi::Error::New(env, "No supported verification method included").ThrowAsJavaScriptException();
1443
- return;
1444
- }
1445
-
1446
- std::unique_ptr<Http3SessionCache> cache;
1447
-
1448
- /* Http3Client(Http3EventLoop *eventloop, QuicSocketAddress server_address,
1449
- const std::string &server_hostname,
1450
- std::unique_ptr<ProofVerifier> proof_verifier,
1451
- std::unique_ptr<SessionCache> session_cache);*/
1452
-
1453
- QuicSocketAddress address;
1454
-
1455
- addrinfo hint;
1456
- memset(&hint, 0, sizeof(hint));
1457
- hint.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
1458
- if (forceipv6)
1459
- hint.ai_family = AF_INET6;
1460
- hint.ai_protocol = IPPROTO_UDP;
1461
-
1462
- addrinfo *info_list = nullptr;
1463
- int result = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &info_list);
1464
- if (result != 0)
1465
- {
1466
- QUIC_LOG(ERROR) << "Failed to look up " << hostname << ": "
1467
- << gai_strerror(result);
1468
- info_list = nullptr;
1469
- Napi::Error::New(env, "URL host lookup failed").ThrowAsJavaScriptException();
1470
- return;
1471
- }
1472
-
1473
- QUICHE_CHECK(info_list != nullptr);
1474
- address = QuicSocketAddress(info_list->ai_addr, info_list->ai_addrlen);
1475
- freeaddrinfo(info_list);
1476
-
1477
- client_ = std::make_unique<Http3Client>(eventloop, address, hostname, local_port,
1478
- std::move(verifier), std::move(cache), std::move(helper));
1479
- client_->SetUserAgentID("fails-components/webtransport");
1480
-
1481
- client_->setJS(this);
1482
-
1483
- Ref(); // do not garbage collect
1484
-
1485
- std::function<void()> task = [this]()
1486
- {
1487
- client_->Connect();
1488
- };
1489
- client_->eventloop_->Schedule(task);
1490
- return;
1491
- }
1492
-
1493
- void Http3ClientJS::openWTSession(const Napi::CallbackInfo &info)
1494
- {
1495
- Http3Client *obj = getObj();
1496
- // got the object we can now start the server
1497
-
1498
- if (!info[0].IsUndefined())
1499
- {
1500
- std::string lpath(info[0].ToString().Utf8Value());
1501
- std::function<void()> task = [obj, lpath]()
1502
- {
1503
- obj->openWTSessionInt(lpath);
1504
- };
1505
- obj->eventloop_->Schedule(task);
1506
- }
1507
- else
1508
- {
1509
- Napi::Error::New(info.Env(), "openWTSession without path").ThrowAsJavaScriptException();
1510
- return;
1511
- }
1512
- }
1513
-
1514
- void Http3ClientJS::closeClient(const Napi::CallbackInfo &info)
1515
- {
1516
- Http3Client *obj = getObj();
1517
- // got the object we can now start the server
1518
- std::function<void()> task = [obj]()
1519
- {
1520
- if (!obj->closeClientInt())
1521
- {
1522
- printf("closeClientInt failed for Http3Client");
1523
- return;
1524
- }
1525
- };
1526
- obj->eventloop_->Schedule(task);
1527
- }
1528
-
1529
- } // namespace quic