@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.
- package/lib/client.js +81 -40
- package/lib/dom.ts +7 -5
- package/lib/http2/browser/browser.js +168 -0
- package/lib/http2/browser/browserparser.js +248 -0
- package/lib/http2/flowcontroller.js +371 -0
- package/lib/http2/node/capsuleparser.js +291 -0
- package/lib/http2/node/client.js +239 -0
- package/lib/http2/node/index.js +2 -0
- package/lib/http2/node/server.js +499 -0
- package/lib/http2/node/websocketparser.js +829 -0
- package/lib/http2/parserbase.js +139 -0
- package/lib/http2/parserbasehttp2.js +128 -0
- package/lib/http2/session.js +225 -0
- package/lib/http2/stream.js +354 -0
- package/lib/http2/websocketcommon.js +1 -0
- package/lib/{index.js → index.browser.js} +6 -10
- package/lib/index.node.js +27 -0
- package/lib/server.js +252 -69
- package/lib/session.js +31 -68
- package/lib/stream.js +103 -179
- package/lib/types.ts +174 -87
- package/lib/utils.js +2 -1
- package/lib/webstreams.browser.js +6 -0
- package/lib/webstreams.js +7 -0
- package/lib/webtransport.browser.js +284 -0
- package/lib/webtransport.node.js +137 -0
- package/lib/{webtransport.js → webtransportbase.js} +47 -41
- package/old_test/test.js +31 -29
- package/old_test/testsuite.js +1 -1
- package/package.json +18 -17
- package/readme.md +94 -30
- package/test/bidirectional-streams.spec.js +51 -9
- package/test/datagrams.spec.js +8 -2
- package/test/fixtures/known-bytes.js +29 -0
- package/test/fixtures/read-stream.js +1 -1
- package/test/fixtures/reader-value.js +1 -1
- package/test/fixtures/server.js +24 -10
- package/test/fixtures/webtransport.browser.js +20 -2
- package/test/fixtures/webtransport.js +1 -1
- package/test/index.js +33 -6
- package/test/pw-no-https-errors.json +5 -0
- package/test/session.spec.js +71 -52
- package/test/unidirectional-streams.spec.js +20 -4
- package/CMakeLists.txt +0 -991
- package/LICENSE.chromium +0 -27
- package/LICENSE.envoy +0 -207
- package/build.js +0 -313
- package/dist/lib/client.d.ts +0 -78
- package/dist/lib/client.d.ts.map +0 -1
- package/dist/lib/dom.d.ts +0 -87
- package/dist/lib/dom.d.ts.map +0 -1
- package/dist/lib/error.d.ts +0 -8
- package/dist/lib/error.d.ts.map +0 -1
- package/dist/lib/event-loop.d.ts +0 -33
- package/dist/lib/event-loop.d.ts.map +0 -1
- package/dist/lib/index.d.ts +0 -79
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/native.d.ts +0 -2
- package/dist/lib/native.d.ts.map +0 -1
- package/dist/lib/server.d.ts +0 -92
- package/dist/lib/server.d.ts.map +0 -1
- package/dist/lib/session.d.ts +0 -298
- package/dist/lib/session.d.ts.map +0 -1
- package/dist/lib/stream.d.ts +0 -135
- package/dist/lib/stream.d.ts.map +0 -1
- package/dist/lib/transport.d.ts +0 -34
- package/dist/lib/transport.d.ts.map +0 -1
- package/dist/lib/types.d.ts +0 -212
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/utils.d.ts +0 -11
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/webtransport.d.ts +0 -47
- package/dist/lib/webtransport.d.ts.map +0 -1
- package/dist/test/bidirectional-streams.spec.d.ts +0 -5
- package/dist/test/bidirectional-streams.spec.d.ts.map +0 -1
- package/dist/test/datagrams.spec.d.ts +0 -5
- package/dist/test/datagrams.spec.d.ts.map +0 -1
- package/dist/test/event-loop.node.d.ts +0 -2
- package/dist/test/event-loop.node.d.ts.map +0 -1
- package/dist/test/fixtures/certificate.d.ts +0 -21
- package/dist/test/fixtures/certificate.d.ts.map +0 -1
- package/dist/test/fixtures/chai.d.ts +0 -2
- package/dist/test/fixtures/chai.d.ts.map +0 -1
- package/dist/test/fixtures/known-bytes.d.ts +0 -6
- package/dist/test/fixtures/known-bytes.d.ts.map +0 -1
- package/dist/test/fixtures/p-timeout.d.ts +0 -8
- package/dist/test/fixtures/p-timeout.d.ts.map +0 -1
- package/dist/test/fixtures/read-cert-hash.d.ts +0 -6
- package/dist/test/fixtures/read-cert-hash.d.ts.map +0 -1
- package/dist/test/fixtures/read-stream.d.ts +0 -19
- package/dist/test/fixtures/read-stream.d.ts.map +0 -1
- package/dist/test/fixtures/reader-value.d.ts +0 -22
- package/dist/test/fixtures/reader-value.d.ts.map +0 -1
- package/dist/test/fixtures/server.d.ts +0 -5
- package/dist/test/fixtures/server.d.ts.map +0 -1
- package/dist/test/fixtures/webtransport.browser.d.ts +0 -3
- package/dist/test/fixtures/webtransport.browser.d.ts.map +0 -1
- package/dist/test/fixtures/webtransport.d.ts +0 -3
- package/dist/test/fixtures/webtransport.d.ts.map +0 -1
- package/dist/test/fixtures/write-stream.d.ts +0 -10
- package/dist/test/fixtures/write-stream.d.ts.map +0 -1
- package/dist/test/index.d.ts +0 -2
- package/dist/test/index.d.ts.map +0 -1
- package/dist/test/session.spec.d.ts +0 -5
- package/dist/test/session.spec.d.ts.map +0 -1
- package/dist/test/unidirectional-streams.spec.d.ts +0 -2
- package/dist/test/unidirectional-streams.spec.d.ts.map +0 -1
- package/failslogolicensereadme.txt +0 -4
- package/lib/event-loop.js +0 -88
- package/lib/native.js +0 -28
- package/lib/transport.js +0 -82
- package/platform/icufix/fakedata.cpp +0 -8
- package/platform/quiche/quic/core/io/socket_win.inc +0 -3
- package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_client_stats_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_containers_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_event_loop_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_export_impl.h +0 -6
- package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +0 -11
- package/platform/quiche_platform_impl/quiche_flags_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_iovec_impl.h +0 -10
- package/platform/quiche_platform_impl/quiche_logging_impl.h +0 -21
- package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +0 -2
- package/platform/quiche_platform_impl/quiche_mutex_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_prefetch_impl.h +0 -11
- package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +0 -16
- package/platform/quiche_platform_impl/quiche_server_stats_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +0 -12
- package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_testvalue_impl.h +0 -1
- package/platform/quiche_platform_impl/quiche_thread_local_impl.h +0 -6
- package/platform/quiche_platform_impl/quiche_time_utils_impl.h +0 -13
- package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +0 -39
- package/src/http3backendresponse.cc +0 -36
- package/src/http3backendresponse.h +0 -109
- package/src/http3client.cc +0 -1529
- package/src/http3client.h +0 -557
- package/src/http3clientsession.cc +0 -65
- package/src/http3clientsession.h +0 -60
- package/src/http3clientstream.cc +0 -52
- package/src/http3clientstream.h +0 -42
- package/src/http3dispatcher.cc +0 -62
- package/src/http3dispatcher.h +0 -57
- package/src/http3eventloop.cc +0 -1107
- package/src/http3eventloop.h +0 -316
- package/src/http3server.cc +0 -514
- package/src/http3server.h +0 -151
- package/src/http3serverbackend.cc +0 -105
- package/src/http3serverbackend.h +0 -98
- package/src/http3serversession.cc +0 -123
- package/src/http3serversession.h +0 -95
- package/src/http3serverstream.cc +0 -463
- package/src/http3serverstream.h +0 -114
- package/src/http3sessioncache.cc +0 -85
- package/src/http3sessioncache.h +0 -59
- package/src/http3wtsessionvisitor.cc +0 -46
- package/src/http3wtsessionvisitor.h +0 -397
- package/src/http3wtstreamvisitor.cc +0 -155
- package/src/http3wtstreamvisitor.h +0 -404
- package/test/event-loop.node.js +0 -24
- package/tsconfig.json +0 -39
package/src/http3client.cc
DELETED
|
@@ -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
|