@fails-components/webtransport 0.0.6 → 0.0.8
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/CMakeLists.txt +11 -6
- package/package.json +1 -1
- package/platform/quiche_platform_impl/quic_udp_socket_winsock.cc +605 -523
- package/src/http3client.cc +86 -72
- package/src/http3client.h +6 -0
- package/src/http3dispatcher.cc +5 -3
- package/src/http3dispatcher.h +2 -1
- package/src/http3eventloop.cc +53 -37
- package/src/http3eventloop.h +18 -1
- package/src/http3server.cc +47 -10
- package/src/http3server.h +2 -1
- package/src/http3wtstreamvisitor.cc +8 -11
- package/src/webtransport.js +11 -3
- package/test/testsuite.js +8 -8
package/src/http3client.cc
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
#include "absl/strings/match.h"
|
|
21
21
|
#include "absl/strings/string_view.h"
|
|
22
|
+
#include "absl/cleanup/cleanup.h"
|
|
22
23
|
#include "openssl/x509.h"
|
|
23
24
|
#include "quiche/quic/core/crypto/proof_verifier.h"
|
|
24
25
|
#include "quiche/quic/core/http/quic_spdy_client_stream.h"
|
|
@@ -44,41 +45,41 @@ using spdy::Http2HeaderBlock;
|
|
|
44
45
|
namespace quic
|
|
45
46
|
{
|
|
46
47
|
|
|
47
|
-
// taken from libquiche
|
|
48
|
-
namespace
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
// For level-triggered I/O, we need to manually rearm the kSocketEventWritable
|
|
52
|
-
// listener whenever the socket gets blocked.
|
|
53
|
-
class LevelTriggeredPacketWriter : public QuicDefaultPacketWriter
|
|
48
|
+
// taken from libquiche
|
|
49
|
+
namespace
|
|
54
50
|
{
|
|
55
|
-
public:
|
|
56
|
-
explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop *event_loop)
|
|
57
|
-
: QuicDefaultPacketWriter(fd), event_loop_(event_loop)
|
|
58
|
-
{
|
|
59
|
-
QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered());
|
|
60
|
-
}
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
PerPacketOptions *options) override
|
|
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
|
|
66
55
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
public:
|
|
57
|
+
explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop *event_loop)
|
|
58
|
+
: QuicDefaultPacketWriter(fd), event_loop_(event_loop)
|
|
70
59
|
{
|
|
71
|
-
|
|
72
|
-
QUICHE_DCHECK(success);
|
|
60
|
+
QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered());
|
|
73
61
|
}
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
63
|
+
WriteResult WritePacket(const char *buffer, size_t buf_len,
|
|
64
|
+
const QuicIpAddress &self_address,
|
|
65
|
+
const QuicSocketAddress &peer_address,
|
|
66
|
+
PerPacketOptions *options) override
|
|
67
|
+
{
|
|
68
|
+
WriteResult result = QuicDefaultPacketWriter::WritePacket(
|
|
69
|
+
buffer, buf_len, self_address, peer_address, options);
|
|
70
|
+
if (IsWriteBlockedStatus(result.status))
|
|
71
|
+
{
|
|
72
|
+
bool success = event_loop_->RearmSocket(fd(), kSocketEventWritable);
|
|
73
|
+
QUICHE_DCHECK(success);
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private:
|
|
79
|
+
QuicEventLoop *event_loop_;
|
|
80
|
+
};
|
|
80
81
|
|
|
81
|
-
} // namespace
|
|
82
|
+
} // namespace
|
|
82
83
|
|
|
83
84
|
// taken from chromium to behave like the browser
|
|
84
85
|
// A version of WebTransportFingerprintProofVerifier that enforces
|
|
@@ -480,6 +481,9 @@ namespace
|
|
|
480
481
|
overflow_supported_ = api.EnableDroppedPacketCount(fd);
|
|
481
482
|
api.EnableReceiveTimestamp(fd);
|
|
482
483
|
|
|
484
|
+
auto closer = absl::MakeCleanup([fd]
|
|
485
|
+
{ QuicUdpSocketApi api;api.Destroy(fd); });
|
|
486
|
+
|
|
483
487
|
QuicSocketAddress client_address;
|
|
484
488
|
if (bind_to_address.IsInitialized())
|
|
485
489
|
{
|
|
@@ -528,10 +532,13 @@ namespace
|
|
|
528
532
|
}
|
|
529
533
|
const int kEpollFlags = kSocketEventReadable | kSocketEventWritable; // there is no analogue to EPOLLET in libuv hopefully not a problem
|
|
530
534
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
+
if (eventloop_->getQuicEventLoop()->RegisterSocket(fd, kEpollFlags, this))
|
|
536
|
+
{
|
|
537
|
+
fd_address_map_[fd] = client_address;
|
|
538
|
+
std::move(closer).Cancel();
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
535
542
|
}
|
|
536
543
|
|
|
537
544
|
void Http3Client::CleanUpUDPSocket(int fd)
|
|
@@ -687,8 +694,8 @@ namespace
|
|
|
687
694
|
Http3WTSession *wtsessionobj =
|
|
688
695
|
new Http3WTSession();
|
|
689
696
|
wtsessionobj->init(
|
|
690
|
-
|
|
691
|
-
|
|
697
|
+
static_cast<WebTransportSession *>(wtsession),
|
|
698
|
+
eventloop_);
|
|
692
699
|
eventloop_->informNewClientSession(this, wtsessionobj);
|
|
693
700
|
auto visitor = std::make_unique<Http3WTSession::Visitor>(wtsessionobj);
|
|
694
701
|
wtsession->SetVisitor(std::move(visitor));
|
|
@@ -753,7 +760,7 @@ namespace
|
|
|
753
760
|
|
|
754
761
|
session_ = std::make_unique<Http3ClientSession>(
|
|
755
762
|
config_, client_supported_versions, new QuicConnection(newconnid, QuicSocketAddress(), server_address_, helper_.get(), alarm_factory_.get(), writer,
|
|
756
|
-
/* owns_writer= */ false, Perspective::IS_CLIENT, client_supported_versions),
|
|
763
|
+
/* owns_writer= */ false, Perspective::IS_CLIENT, client_supported_versions, connection_id_generator_),
|
|
757
764
|
server_id_, &crypto_config_,
|
|
758
765
|
&push_promise_index_, false /*drop_response_body_*/, true /* enable_web_transport */);
|
|
759
766
|
|
|
@@ -924,7 +931,7 @@ namespace
|
|
|
924
931
|
bool success =
|
|
925
932
|
event_loop->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
|
|
926
933
|
QUICHE_DCHECK(success);
|
|
927
|
-
}
|
|
934
|
+
}
|
|
928
935
|
if (!event_loop->SupportsEdgeTriggered())
|
|
929
936
|
{
|
|
930
937
|
bool success = event_loop->RearmSocket(fd, kSocketEventReadable);
|
|
@@ -1292,8 +1299,7 @@ namespace
|
|
|
1292
1299
|
latest_created_stream_ = nullptr;
|
|
1293
1300
|
}
|
|
1294
1301
|
|
|
1295
|
-
Http3ClientJS::Http3ClientJS(const Napi::CallbackInfo &info) :
|
|
1296
|
-
Napi::ObjectWrap<Http3ClientJS>(info)
|
|
1302
|
+
Http3ClientJS::Http3ClientJS(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Http3ClientJS>(info)
|
|
1297
1303
|
{
|
|
1298
1304
|
|
|
1299
1305
|
std::string port = "443";
|
|
@@ -1310,39 +1316,41 @@ namespace
|
|
|
1310
1316
|
if (!lobj.IsEmpty())
|
|
1311
1317
|
{
|
|
1312
1318
|
|
|
1313
|
-
if (lobj.Has(
|
|
1319
|
+
if (lobj.Has("allowPooling") && !(lobj).Get("allowPooling").IsEmpty())
|
|
1314
1320
|
{
|
|
1315
1321
|
Napi::Value poolValue = (lobj).Get("allowPooling");
|
|
1316
1322
|
allowPooling = poolValue.As<Napi::Boolean>().Value();
|
|
1317
1323
|
}
|
|
1318
1324
|
|
|
1319
|
-
if (lobj.Has(
|
|
1325
|
+
if (lobj.Has("forceIpv6") && !(lobj).Get("forceIpv6").IsEmpty())
|
|
1320
1326
|
{
|
|
1321
1327
|
Napi::Value ipv6Value = (lobj).Get("forceIpv6");
|
|
1322
1328
|
forceipv6 = ipv6Value.As<Napi::Boolean>().Value();
|
|
1323
1329
|
}
|
|
1324
1330
|
|
|
1325
|
-
if (lobj.Has(
|
|
1331
|
+
if (lobj.Has("port") && !(lobj).Get("port").IsEmpty())
|
|
1326
1332
|
{
|
|
1327
1333
|
Napi::Value portValue = (lobj).Get("port");
|
|
1328
1334
|
port = portValue.ToString().Utf8Value();
|
|
1329
1335
|
}
|
|
1330
|
-
else
|
|
1336
|
+
else
|
|
1337
|
+
{
|
|
1331
1338
|
Napi::Error::New(env, "no port specified").ThrowAsJavaScriptException();
|
|
1332
|
-
return
|
|
1339
|
+
return;
|
|
1333
1340
|
}
|
|
1334
1341
|
|
|
1335
|
-
if (lobj.Has(
|
|
1342
|
+
if (lobj.Has("hostname") && !(lobj).Get("hostname").IsEmpty())
|
|
1336
1343
|
{
|
|
1337
1344
|
Napi::Value hostnameValue = (lobj).Get("hostname");
|
|
1338
1345
|
hostname = hostnameValue.ToString().Utf8Value();
|
|
1339
1346
|
}
|
|
1340
|
-
else
|
|
1347
|
+
else
|
|
1348
|
+
{
|
|
1341
1349
|
Napi::Error::New(env, "no hostname specified").ThrowAsJavaScriptException();
|
|
1342
|
-
return
|
|
1350
|
+
return;
|
|
1343
1351
|
}
|
|
1344
1352
|
|
|
1345
|
-
if (lobj.Has(
|
|
1353
|
+
if (lobj.Has("serverCertificateHashes") && !(lobj).Get("serverCertificateHashes").IsEmpty())
|
|
1346
1354
|
{
|
|
1347
1355
|
Napi::Value hashValue = (lobj).Get("serverCertificateHashes");
|
|
1348
1356
|
if (hashValue.IsArray())
|
|
@@ -1362,40 +1370,45 @@ namespace
|
|
|
1362
1370
|
size_t len = bufferlocal.As<Napi::Buffer<char>>().Length();
|
|
1363
1371
|
curhash.value = std::string(buffer, len);
|
|
1364
1372
|
}
|
|
1365
|
-
else
|
|
1373
|
+
else
|
|
1374
|
+
{
|
|
1366
1375
|
Napi::Error::New(env, "serverCertificateHashes wrong format").ThrowAsJavaScriptException();
|
|
1367
|
-
return
|
|
1376
|
+
return;
|
|
1368
1377
|
}
|
|
1369
1378
|
if (hashobj.Has("algorithm") && !(hashobj).Get("algorithm").IsEmpty())
|
|
1370
1379
|
{
|
|
1371
1380
|
Napi::Value algorithmValue = (hashobj).Get("algorithm");
|
|
1372
1381
|
curhash.algorithm = algorithmValue.ToString().Utf8Value();
|
|
1373
1382
|
}
|
|
1374
|
-
else
|
|
1383
|
+
else
|
|
1384
|
+
{
|
|
1375
1385
|
Napi::Error::New(env, "serverCertificateHashes wrong format").ThrowAsJavaScriptException();
|
|
1376
|
-
return
|
|
1386
|
+
return;
|
|
1377
1387
|
}
|
|
1378
|
-
if (curhash.algorithm.compare(WebTransportHash::kSha256) != 0)
|
|
1388
|
+
if (curhash.algorithm.compare(WebTransportHash::kSha256) != 0)
|
|
1389
|
+
{
|
|
1379
1390
|
Napi::Error::New(env, "serverCertificateHashes unknown algorithm").ThrowAsJavaScriptException();
|
|
1380
|
-
return
|
|
1391
|
+
return;
|
|
1381
1392
|
}
|
|
1382
1393
|
serverCertificateHashes.push_back(curhash);
|
|
1383
1394
|
}
|
|
1384
1395
|
}
|
|
1385
|
-
else
|
|
1396
|
+
else
|
|
1397
|
+
{
|
|
1386
1398
|
Napi::Error::New(env, "serverCertificateHashes is not an array").ThrowAsJavaScriptException();
|
|
1387
|
-
return
|
|
1399
|
+
return;
|
|
1388
1400
|
}
|
|
1389
1401
|
}
|
|
1390
1402
|
|
|
1391
|
-
if (lobj.Has(
|
|
1403
|
+
if (lobj.Has("localPort") && !(lobj).Get("localPort").IsEmpty())
|
|
1392
1404
|
{
|
|
1393
1405
|
Napi::Value localPortValue = (lobj).Get("localPort");
|
|
1394
1406
|
if (localPortValue.IsNumber())
|
|
1395
1407
|
local_port = localPortValue.As<Napi::Number>().Int32Value();
|
|
1396
|
-
else
|
|
1408
|
+
else
|
|
1409
|
+
{
|
|
1397
1410
|
Napi::Error::New(env, "localPort is not a number").ThrowAsJavaScriptException();
|
|
1398
|
-
return
|
|
1411
|
+
return;
|
|
1399
1412
|
}
|
|
1400
1413
|
}
|
|
1401
1414
|
}
|
|
@@ -1412,7 +1425,7 @@ namespace
|
|
|
1412
1425
|
else
|
|
1413
1426
|
{
|
|
1414
1427
|
Napi::Error::New(env, "No eventloop arguments passed to Http3Client").ThrowAsJavaScriptException();
|
|
1415
|
-
return
|
|
1428
|
+
return;
|
|
1416
1429
|
}
|
|
1417
1430
|
|
|
1418
1431
|
std::unique_ptr<QuicConnectionHelperInterface> helper =
|
|
@@ -1430,13 +1443,14 @@ namespace
|
|
|
1430
1443
|
if (!verifier->AddFingerprint(*cur))
|
|
1431
1444
|
{
|
|
1432
1445
|
Napi::Error::New(env, "serverCertificateHashes is not valid fingerprint").ThrowAsJavaScriptException();
|
|
1433
|
-
return
|
|
1446
|
+
return;
|
|
1434
1447
|
}
|
|
1435
1448
|
}
|
|
1436
1449
|
}
|
|
1437
|
-
else
|
|
1450
|
+
else
|
|
1451
|
+
{
|
|
1438
1452
|
Napi::Error::New(env, "No supported verification method included").ThrowAsJavaScriptException();
|
|
1439
|
-
return
|
|
1453
|
+
return;
|
|
1440
1454
|
}
|
|
1441
1455
|
|
|
1442
1456
|
std::unique_ptr<Http3SessionCache> cache;
|
|
@@ -1463,7 +1477,7 @@ namespace
|
|
|
1463
1477
|
<< gai_strerror(result);
|
|
1464
1478
|
info_list = nullptr;
|
|
1465
1479
|
Napi::Error::New(env, "URL host lookup failed").ThrowAsJavaScriptException();
|
|
1466
|
-
return
|
|
1480
|
+
return;
|
|
1467
1481
|
}
|
|
1468
1482
|
|
|
1469
1483
|
QUICHE_CHECK(info_list != nullptr);
|
|
@@ -1471,7 +1485,7 @@ namespace
|
|
|
1471
1485
|
freeaddrinfo(info_list);
|
|
1472
1486
|
|
|
1473
1487
|
client_ = std::make_unique<Http3Client>(eventloop, address, hostname, local_port,
|
|
1474
|
-
|
|
1488
|
+
std::move(verifier), std::move(cache), std::move(helper));
|
|
1475
1489
|
client_->SetUserAgentID("fails-components/webtransport");
|
|
1476
1490
|
|
|
1477
1491
|
client_->setJS(this);
|
|
@@ -1483,11 +1497,10 @@ namespace
|
|
|
1483
1497
|
client_->Connect();
|
|
1484
1498
|
};
|
|
1485
1499
|
client_->eventloop_->Schedule(task);
|
|
1486
|
-
return
|
|
1500
|
+
return;
|
|
1487
1501
|
}
|
|
1488
1502
|
|
|
1489
|
-
|
|
1490
|
-
void Http3ClientJS::openWTSession(const Napi::CallbackInfo& info)
|
|
1503
|
+
void Http3ClientJS::openWTSession(const Napi::CallbackInfo &info)
|
|
1491
1504
|
{
|
|
1492
1505
|
Http3Client *obj = getObj();
|
|
1493
1506
|
// got the object we can now start the server
|
|
@@ -1501,13 +1514,14 @@ namespace
|
|
|
1501
1514
|
};
|
|
1502
1515
|
obj->eventloop_->Schedule(task);
|
|
1503
1516
|
}
|
|
1504
|
-
else
|
|
1517
|
+
else
|
|
1518
|
+
{
|
|
1505
1519
|
Napi::Error::New(info.Env(), "openWTSession without path").ThrowAsJavaScriptException();
|
|
1506
|
-
return
|
|
1520
|
+
return;
|
|
1507
1521
|
}
|
|
1508
1522
|
}
|
|
1509
1523
|
|
|
1510
|
-
void Http3ClientJS::closeClient(const Napi::CallbackInfo&
|
|
1524
|
+
void Http3ClientJS::closeClient(const Napi::CallbackInfo &info)
|
|
1511
1525
|
{
|
|
1512
1526
|
Http3Client *obj = getObj();
|
|
1513
1527
|
// got the object we can now start the server
|
|
@@ -1515,8 +1529,8 @@ namespace
|
|
|
1515
1529
|
{
|
|
1516
1530
|
if (!obj->closeClientInt())
|
|
1517
1531
|
{
|
|
1518
|
-
printf(
|
|
1519
|
-
return
|
|
1532
|
+
printf("closeClientInt failed for Http3Client");
|
|
1533
|
+
return;
|
|
1520
1534
|
}
|
|
1521
1535
|
};
|
|
1522
1536
|
obj->eventloop_->Schedule(task);
|
package/src/http3client.h
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
#include "quiche/quic/core/quic_packet_reader.h"
|
|
30
30
|
#include "quiche/quic/platform/api/quic_socket_address.h"
|
|
31
31
|
#include "quiche/quic/core/proto/cached_network_parameters_proto.h"
|
|
32
|
+
#include "quiche/quic/core/deterministic_connection_id_generator.h"
|
|
32
33
|
#include "quiche/quic/core/quic_framer.h"
|
|
33
34
|
#include "quiche/quic/core/quic_packet_creator.h"
|
|
34
35
|
#include "quiche/quic/core/quic_packets.h"
|
|
@@ -353,6 +354,8 @@ namespace quic
|
|
|
353
354
|
// Returns true if the corresponding of this client has active requests.
|
|
354
355
|
bool HasActiveRequests();
|
|
355
356
|
|
|
357
|
+
ConnectionIdGeneratorInterface &connection_id_generator();
|
|
358
|
+
|
|
356
359
|
// Actually clean up |fd|.
|
|
357
360
|
void CleanUpUDPSocketImpl(QuicUdpSocketFd fd);
|
|
358
361
|
|
|
@@ -541,6 +544,9 @@ namespace quic
|
|
|
541
544
|
// space than allowed on the stack.
|
|
542
545
|
std::unique_ptr<QuicPacketReader> packet_reader_;
|
|
543
546
|
|
|
547
|
+
DeterministicConnectionIdGenerator connection_id_generator_{
|
|
548
|
+
kQuicDefaultConnectionIdLength};
|
|
549
|
+
|
|
544
550
|
Http3EventLoop *eventloop_;
|
|
545
551
|
// connection workflow
|
|
546
552
|
bool wait_for_encryption_;
|
package/src/http3dispatcher.cc
CHANGED
|
@@ -23,14 +23,16 @@ Http3Dispatcher::Http3Dispatcher(
|
|
|
23
23
|
std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
|
|
24
24
|
std::unique_ptr<QuicAlarmFactory> alarm_factory,
|
|
25
25
|
Http3ServerBackend* http3_server_backend,
|
|
26
|
-
uint8_t expected_server_connection_id_length
|
|
26
|
+
uint8_t expected_server_connection_id_length,
|
|
27
|
+
ConnectionIdGeneratorInterface& generator)
|
|
27
28
|
: QuicDispatcher(config,
|
|
28
29
|
crypto_config,
|
|
29
30
|
version_manager,
|
|
30
31
|
std::move(helper),
|
|
31
32
|
std::move(session_helper),
|
|
32
33
|
std::move(alarm_factory),
|
|
33
|
-
expected_server_connection_id_length
|
|
34
|
+
expected_server_connection_id_length,
|
|
35
|
+
generator),
|
|
34
36
|
http3_server_backend_(http3_server_backend) {}
|
|
35
37
|
|
|
36
38
|
Http3Dispatcher::~Http3Dispatcher() = default;
|
|
@@ -47,7 +49,7 @@ std::unique_ptr<QuicSession> Http3Dispatcher::CreateQuicSession(
|
|
|
47
49
|
new QuicConnection(connection_id, self_address, peer_address, helper(),
|
|
48
50
|
alarm_factory(), writer(),
|
|
49
51
|
/* owns_writer= */ false, Perspective::IS_SERVER,
|
|
50
|
-
ParsedQuicVersionVector{version});
|
|
52
|
+
ParsedQuicVersionVector{version}, connection_id_generator());
|
|
51
53
|
|
|
52
54
|
auto session = std::make_unique<Http3ServerSession>(
|
|
53
55
|
config(), GetSupportedVersions(), connection, this, session_helper(),
|
package/src/http3dispatcher.h
CHANGED
|
@@ -30,7 +30,8 @@ namespace quic
|
|
|
30
30
|
std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
|
|
31
31
|
std::unique_ptr<QuicAlarmFactory> alarm_factory,
|
|
32
32
|
Http3ServerBackend *http3_server_backend,
|
|
33
|
-
uint8_t expected_server_connection_id_length
|
|
33
|
+
uint8_t expected_server_connection_id_length,
|
|
34
|
+
ConnectionIdGeneratorInterface& generator);
|
|
34
35
|
|
|
35
36
|
~Http3Dispatcher() override;
|
|
36
37
|
|