@fails-components/webtransport-transport-http3-quiche 1.0.0-rc.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 (67) hide show
  1. package/CMakeLists.txt +978 -0
  2. package/LICENSE +39 -0
  3. package/LICENSE.chromium +27 -0
  4. package/LICENSE.envoy +207 -0
  5. package/build.js +315 -0
  6. package/lib/clientsocket.js +80 -0
  7. package/lib/index.js +47 -0
  8. package/lib/serversocket.js +80 -0
  9. package/lib/socket.js +118 -0
  10. package/lib/types.ts +15 -0
  11. package/lib/utils.js +12 -0
  12. package/package.json +68 -0
  13. package/platform/icufix/fakedata.cpp +8 -0
  14. package/platform/quiche/quic/core/io/socket_win.inc +3 -0
  15. package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +7 -0
  16. package/platform/quiche_platform_impl/quiche_client_stats_impl.h +7 -0
  17. package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +7 -0
  18. package/platform/quiche_platform_impl/quiche_containers_impl.h +7 -0
  19. package/platform/quiche_platform_impl/quiche_event_loop_impl.h +7 -0
  20. package/platform/quiche_platform_impl/quiche_export_impl.h +6 -0
  21. package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +11 -0
  22. package/platform/quiche_platform_impl/quiche_flags_impl.h +8 -0
  23. package/platform/quiche_platform_impl/quiche_googleurl_impl.h +8 -0
  24. package/platform/quiche_platform_impl/quiche_iovec_impl.h +10 -0
  25. package/platform/quiche_platform_impl/quiche_logging_impl.h +21 -0
  26. package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +2 -0
  27. package/platform/quiche_platform_impl/quiche_mutex_impl.h +8 -0
  28. package/platform/quiche_platform_impl/quiche_prefetch_impl.h +11 -0
  29. package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +16 -0
  30. package/platform/quiche_platform_impl/quiche_server_stats_impl.h +7 -0
  31. package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +12 -0
  32. package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +8 -0
  33. package/platform/quiche_platform_impl/quiche_testvalue_impl.h +1 -0
  34. package/platform/quiche_platform_impl/quiche_thread_local_impl.h +6 -0
  35. package/platform/quiche_platform_impl/quiche_time_utils_impl.h +13 -0
  36. package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +39 -0
  37. package/readme.md +20 -0
  38. package/src/http3backendresponse.cc +36 -0
  39. package/src/http3backendresponse.h +109 -0
  40. package/src/http3client.cc +1402 -0
  41. package/src/http3client.h +531 -0
  42. package/src/http3clientsession.cc +65 -0
  43. package/src/http3clientsession.h +58 -0
  44. package/src/http3clientstream.cc +52 -0
  45. package/src/http3clientstream.h +42 -0
  46. package/src/http3dispatcher.cc +62 -0
  47. package/src/http3dispatcher.h +57 -0
  48. package/src/http3server.cc +529 -0
  49. package/src/http3server.h +149 -0
  50. package/src/http3serverbackend.cc +104 -0
  51. package/src/http3serverbackend.h +96 -0
  52. package/src/http3serversession.cc +123 -0
  53. package/src/http3serversession.h +95 -0
  54. package/src/http3serverstream.cc +463 -0
  55. package/src/http3serverstream.h +114 -0
  56. package/src/http3sessioncache.cc +85 -0
  57. package/src/http3sessioncache.h +59 -0
  58. package/src/http3wtsessionvisitor.cc +312 -0
  59. package/src/http3wtsessionvisitor.h +257 -0
  60. package/src/http3wtstreamvisitor.cc +286 -0
  61. package/src/http3wtstreamvisitor.h +323 -0
  62. package/src/librarymain.cc +86 -0
  63. package/src/librarymain.h +42 -0
  64. package/src/napialarmfactory.cc +51 -0
  65. package/src/napialarmfactory.h +165 -0
  66. package/src/socketjswriter.cc +46 -0
  67. package/src/socketjswriter.h +100 -0
@@ -0,0 +1,529 @@
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, original copyright, see LICENSE.chromium
6
+ // Copyright (c) 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 "absl/cleanup/cleanup.h"
11
+ #include "src/http3server.h"
12
+ #include "src/http3dispatcher.h"
13
+ #include "src/http3wtsessionvisitor.h"
14
+ #include "quiche/quic/core/quic_default_packet_writer.h"
15
+ #include "quiche/quic/core/quic_default_connection_helper.h"
16
+ #include "quiche/quic/core/quic_default_clock.h"
17
+ #include "quiche/quic/tools/quic_simple_crypto_server_stream_helper.h"
18
+ #include "quiche/quic/core/crypto/proof_source_x509.h"
19
+ #include "quiche/common/platform/api/quiche_reference_counted.h"
20
+
21
+ using namespace Napi;
22
+
23
+ namespace quic
24
+ {
25
+
26
+ const size_t kNumSessionsToCreatePerSocketEvent = 16;
27
+
28
+ Http3Server::Http3Server(Http3ServerJS *js, std::unique_ptr<ProofSource> proof_source,
29
+ const char *secret, QuicConfig config)
30
+ : config_(config),
31
+ http3_server_backend_(),
32
+ packet_reader_(new QuicPacketReader()),
33
+ packets_dropped_(0),
34
+ version_manager_({ParsedQuicVersion::RFCv1()}),
35
+ crypto_config_(secret,
36
+ QuicRandom::GetInstance(),
37
+ std::move(proof_source),
38
+ KeyExchangeSource::Default()),
39
+ expected_server_connection_id_length_(kQuicDefaultConnectionIdLength),
40
+ js_(js),
41
+ connection_id_generator_(expected_server_connection_id_length_)
42
+ {
43
+ // may be put somewhereelse
44
+ dispatcher_.reset(CreateQuicDispatcher());
45
+ dispatcher_->InitializeWithWriter(new SocketJSWriter(getJS()));
46
+ // may be put somewhereelse
47
+ const uint32_t kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB
48
+ const uint32_t kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB
49
+ if (config_.GetInitialStreamFlowControlWindowToSend() ==
50
+ kDefaultFlowControlSendWindow)
51
+ {
52
+ config_.SetInitialStreamFlowControlWindowToSend(
53
+ kInitialStreamFlowControlWindow);
54
+ }
55
+ if (config_.GetInitialSessionFlowControlWindowToSend() ==
56
+ kDefaultFlowControlSendWindow)
57
+ {
58
+ config_.SetInitialSessionFlowControlWindowToSend(
59
+ kInitialSessionFlowControlWindow);
60
+ }
61
+ }
62
+
63
+ Http3Server::~Http3Server()
64
+ {
65
+ // printf("server destruct %x\n", this);
66
+ }
67
+
68
+ // TODO make call from JS
69
+ void Http3Server::Destroy()
70
+ {
71
+
72
+ // if (!silent_close_) {
73
+ // Before we shut down the epoll server, give all active sessions a chance
74
+ // to notify clients that they're closing.
75
+ dispatcher_->Shutdown();
76
+ //}
77
+ }
78
+
79
+ QuicDispatcher *Http3Server::CreateQuicDispatcher()
80
+ {
81
+ http3_server_backend_.setServer(this);
82
+ return new Http3Dispatcher(
83
+ &config_, &crypto_config_, &version_manager_,
84
+ std::unique_ptr<QuicDefaultConnectionHelper>(new QuicDefaultConnectionHelper()),
85
+ std::unique_ptr<QuicCryptoServerStreamBase::Helper>(
86
+ new QuicSimpleCryptoServerStreamHelper()),
87
+ std::unique_ptr<QuicAlarmFactory>(new NapiAlarmFactory(QuicDefaultClock::Get(), getJS())),
88
+ &http3_server_backend_, expected_server_connection_id_length_, connection_id_generator_);
89
+ }
90
+
91
+ Http3ServerJS::Http3ServerJS(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Http3ServerJS>(info)
92
+ {
93
+ std::string secret;
94
+ std::string cert;
95
+ std::string privkey;
96
+
97
+ QuicConfig sconfig;
98
+ if (!info[0].IsUndefined())
99
+ {
100
+ Napi::Object lobj = info[0].ToObject();
101
+ if (!lobj.IsEmpty())
102
+ {
103
+ if (lobj.Has("secret") && !(lobj).Get("secret").IsEmpty())
104
+ {
105
+ Napi::Value secretValue = (lobj).Get("secret");
106
+ secret = secretValue.ToString().Utf8Value();
107
+ }
108
+ else
109
+ {
110
+ Napi::Error::New(Env(), "No secret set for Http3Server").ThrowAsJavaScriptException();
111
+ return;
112
+ }
113
+ if (lobj.Has("cert") && !(lobj).Get("cert").IsEmpty())
114
+ {
115
+ Napi::Value certValue = (lobj).Get("cert");
116
+ cert = certValue.ToString().Utf8Value();
117
+ }
118
+ else
119
+ {
120
+ Napi::Error::New(Env(), "No cert set for Http3Server").ThrowAsJavaScriptException();
121
+ return;
122
+ }
123
+ if (lobj.Has("privKey") && !(lobj).Get("privKey").IsEmpty())
124
+ {
125
+ Napi::Value keyValue = (lobj).Get("privKey");
126
+ privkey = keyValue.ToString().Utf8Value();
127
+ }
128
+ else
129
+ {
130
+ Napi::Error::New(Env(), "No privKey set for Http3Server").ThrowAsJavaScriptException();
131
+ return;
132
+ }
133
+ if (lobj.Has("maxConnections") && !(lobj).Get("maxConnections").IsEmpty())
134
+ {
135
+ Napi::Value maxconnValue = (lobj).Get("maxConnections");
136
+ int maxconn = maxconnValue.As<Napi::Number>().Int32Value();
137
+ sconfig.SetMaxBidirectionalStreamsToSend(maxconn);
138
+ sconfig.SetMaxUnidirectionalStreamsToSend(maxconn);
139
+ }
140
+
141
+ if (lobj.Has("initialStreamFlowControlWindow") && !(lobj).Get("initialStreamFlowControlWindow").IsEmpty())
142
+ {
143
+ Napi::Value initialStreamFlowControlWindowValue = (lobj).Get("initialStreamFlowControlWindow");
144
+ int initialStreamFlowControlWindow = initialStreamFlowControlWindowValue.As<Napi::Number>().Int32Value();
145
+ sconfig.SetInitialStreamFlowControlWindowToSend(initialStreamFlowControlWindow);
146
+ }
147
+
148
+ if (lobj.Has("initialSessionFlowControlWindow") && !(lobj).Get("initialSessionFlowControlWindow").IsEmpty())
149
+ {
150
+ Napi::Value initialSessionFlowControlWindowValue = (lobj).Get("initialSessionFlowControlWindow");
151
+ int initialSessionFlowControlWindow = initialSessionFlowControlWindowValue.As<Napi::Number>().Int32Value();
152
+ sconfig.SetInitialSessionFlowControlWindowToSend(initialSessionFlowControlWindow);
153
+ }
154
+
155
+ if (lobj.Has("streamFlowControlWindowSizeLimit") && !(lobj).Get("streamFlowControlWindowSizeLimit").IsEmpty())
156
+ {
157
+ Napi::Value streamFlowControlWindowSizeLimitValue = (lobj).Get("streamFlowControlWindowSizeLimit");
158
+ int streamFlowControlWindowSizeLimitWindow = streamFlowControlWindowSizeLimitValue.As<Napi::Number>().Int32Value();
159
+ sconfig.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(streamFlowControlWindowSizeLimitWindow);
160
+ sconfig.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(streamFlowControlWindowSizeLimitWindow);
161
+ sconfig.SetInitialMaxStreamDataBytesUnidirectionalToSend(streamFlowControlWindowSizeLimitWindow);
162
+ }
163
+ }
164
+ // Callback *callback, int port, std::unique_ptr<ProofSource> proof_source, const char *secret
165
+
166
+ std::stringstream certstream(cert, std::ios_base::in);
167
+ quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain(new ProofSource::Chain(CertificateView::LoadPemFromStream(&certstream)));
168
+
169
+ std::stringstream privkeystream(privkey, std::ios_base::in);
170
+
171
+ auto certprivkey = CertificatePrivateKey::LoadPemFromStream(&privkeystream);
172
+ if (certprivkey == nullptr)
173
+ {
174
+ Napi::Error::New(Env(), "LoadPemFromStream privKey failed for Http3Server").ThrowAsJavaScriptException();
175
+ return;
176
+ }
177
+
178
+ std::unique_ptr<ProofSourceX509> proofsource = ProofSourceX509::Create(chain, std::move(*certprivkey));
179
+ if (proofsource == nullptr)
180
+ {
181
+ Napi::Error::New(Env(), "LoadPemFromStream cert failed for Http3Server").ThrowAsJavaScriptException();
182
+ return;
183
+ }
184
+
185
+ server_ = std::make_unique<Http3Server>(this, std::move(proofsource), secret.c_str(), sconfig);
186
+
187
+ return;
188
+ }
189
+ else
190
+ {
191
+ Napi::Error::New(Env(), "No arguments passed to Http3Server").ThrowAsJavaScriptException();
192
+ return;
193
+ }
194
+ }
195
+
196
+ Http3ServerJS::~Http3ServerJS()
197
+ {
198
+ }
199
+
200
+ void Http3ServerJS::destroy(const Napi::CallbackInfo &info)
201
+ {
202
+ server_->Destroy();
203
+ server_.reset();
204
+ }
205
+
206
+ Napi::Value Http3ServerJS::recvPaket(const Napi::CallbackInfo &info)
207
+ {
208
+ QuicTime now = QuicDefaultClock::Get()->Now();
209
+ // Got a packet replace OnSocketEvent for readable
210
+ if (info[0].IsUndefined())
211
+ {
212
+ Napi::Error::New(Env(), "No obj passed to recvPaket").ThrowAsJavaScriptException();
213
+ return Env().Undefined();
214
+ }
215
+ Napi::Object lobj = info[0].ToObject();
216
+ if (lobj.IsEmpty())
217
+ {
218
+ Napi::Error::New(Env(), "Obj for recvPaket is empty").ThrowAsJavaScriptException();
219
+ return Env().Undefined();
220
+ }
221
+
222
+ if (!lobj.Has("selfaddress"))
223
+ {
224
+ Napi::Error::New(Env(), "No Selfaddress for recvPaket").ThrowAsJavaScriptException();
225
+ return Env().Undefined();
226
+ }
227
+
228
+ Napi::Object selfaddress = (lobj).Get("selfaddress").As<Napi::Object>();
229
+ if (selfaddress.IsEmpty())
230
+ {
231
+ Napi::Error::New(Env(), "Selfaddress for recvPaket empty").ThrowAsJavaScriptException();
232
+ return Env().Undefined();
233
+ }
234
+ int port = selfaddress.Get("port").As<Napi::Number>().Int32Value();
235
+ std::string selfipaddress = selfaddress.Get("address").As<Napi::String>();
236
+
237
+ QuicIpAddress self_ip;
238
+ self_ip.FromString(selfipaddress);
239
+ QuicSocketAddress self_address(self_ip, port);
240
+
241
+ if (!lobj.Has("rinfo"))
242
+ {
243
+ Napi::Error::New(Env(), "No rinfo for recvPaket").ThrowAsJavaScriptException();
244
+ return Env().Undefined();
245
+ }
246
+
247
+ Napi::Object rinfo = (lobj).Get("rinfo").As<Napi::Object>();
248
+ if (rinfo.IsEmpty())
249
+ {
250
+ Napi::Error::New(Env(), "Rinfo for recvPaket empty").ThrowAsJavaScriptException();
251
+ return Env().Undefined();
252
+ }
253
+ int peerport = rinfo.Get("port").As<Napi::Number>().Int32Value();
254
+ std::string peeripaddress = rinfo.Get("address").As<Napi::String>();
255
+
256
+ QuicIpAddress peer_ip;
257
+ peer_ip.FromString(peeripaddress);
258
+ QuicSocketAddress peer_address(peer_ip, peerport);
259
+
260
+ Napi::Object bufferlocal = lobj.Get("msg").As<Napi::Object>();
261
+
262
+ QuicReceivedPacket packet(
263
+ bufferlocal.As<Napi::Buffer<char>>().Data(), rinfo.Get("size").As<Napi::Number>().Uint32Value(), now,
264
+ /*owns_buffer=*/false, 0 /*ttl*/, false /*has_ttl*/, nullptr /*headers*/, 0 /*headers_length*/,
265
+ /*owns_header_buffer=*/false, ECN_NOT_ECT);
266
+
267
+ Http3Server *obj = getObj();
268
+ bool hasbufferedchlos = obj->ProcessPacket(self_address, peer_address, packet);
269
+ return Napi::Boolean::New(Env(), hasbufferedchlos);
270
+ }
271
+
272
+ bool Http3Server::ProcessPacket(const QuicSocketAddress &self_address,
273
+ const QuicSocketAddress &peer_address,
274
+ const QuicReceivedPacket &packet)
275
+ {
276
+ dispatcher_.get()->ProcessPacket(self_address, peer_address, packet);
277
+ return dispatcher_->HasChlosBuffered();
278
+ }
279
+
280
+ void Http3ServerJS::processBufferedChlos(const Napi::CallbackInfo &info)
281
+ {
282
+ Http3Server *obj = getObj();
283
+ obj->ProcessBufferedChlos();
284
+ }
285
+
286
+ void Http3Server::ProcessBufferedChlos()
287
+ {
288
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
289
+ }
290
+
291
+
292
+
293
+ void Http3ServerJS::onCanWrite(const Napi::CallbackInfo &info)
294
+ {
295
+ server_->OnCanWrite();
296
+ }
297
+
298
+ void Http3Server::OnCanWrite()
299
+ {
300
+ dispatcher_->OnCanWrite();
301
+ }
302
+
303
+ /*void Http3Server::OnSocketEvent(QuicEventLoop *event_loop, QuicUdpSocketFd fd,
304
+ QuicSocketEventMask events)
305
+ {
306
+ // QUICHE_DCHECK_EQ(fd, fd_);
307
+
308
+ /* if (events & kSocketEventReadable)
309
+ {
310
+ QUIC_DVLOG(1) << "kSocketEventReadable";
311
+
312
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
313
+
314
+ bool more_to_read = true;
315
+ while (more_to_read)
316
+ {
317
+ more_to_read = packet_reader_->ReadAndDispatchPackets(
318
+ fd_, port_, *QuicDefaultClock::Get(), dispatcher_.get(),
319
+ overflow_supported_ ? &packets_dropped_ : nullptr);
320
+ }
321
+
322
+ if (dispatcher_->HasChlosBuffered())
323
+ {
324
+ // Register EPOLLIN event to consume buffered CHLO(s).
325
+ bool success =
326
+ event_loop->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
327
+ QUICHE_DCHECK(success);
328
+ }
329
+ else if (!event_loop->SupportsEdgeTriggered())
330
+ {
331
+ bool success = event_loop->RearmSocket(fd, kSocketEventReadable);
332
+ QUICHE_DCHECK(success);
333
+ }
334
+ }
335
+ if (events & kSocketEventWritable)
336
+ {
337
+ dispatcher_->OnCanWrite();
338
+ if (!event_loop->SupportsEdgeTriggered() &&
339
+ dispatcher_->HasPendingWrites())
340
+ {
341
+ bool success = event_loop->RearmSocket(fd, kSocketEventWritable);
342
+ QUICHE_DCHECK(success);
343
+ }
344
+ }
345
+ }*/
346
+
347
+ void Http3ServerJS::processNewSession(Http3WTSession *session, const std::string &path, Napi::Reference<Napi::Value> *header)
348
+ {
349
+ Napi::HandleScope scope(Env());
350
+
351
+ Http3Constructors *constr = Env().GetInstanceData<Http3Constructors>();
352
+ Napi::Object sessionobj = constr->session.New({});
353
+ Http3WTSessionJS *sessionjs = Napi::ObjectWrap<Http3WTSessionJS>::Unwrap(sessionobj);
354
+ sessionjs->setObj(session);
355
+ sessionjs->Ref();
356
+ session->setJS(sessionjs);
357
+
358
+ Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
359
+
360
+ Napi::Object retObj = Napi::Object::New(Env());
361
+ retObj.Set("session", sessionobj);
362
+ retObj.Set("path", path);
363
+ if (header)
364
+ {
365
+ retObj.Set("header", header->Value());
366
+ header->Unref();
367
+ }
368
+ objVal.Get("onHttpWTSessionVisitor")
369
+ .As<Napi::Function>()
370
+ .Call(objVal, {retObj});
371
+ }
372
+
373
+ void Http3ServerJS::processNewSessionRequest(WebTransportSession *session, const spdy::Http2HeaderBlock &reqhead, WebTransportRespPromisePtr *promise)
374
+ {
375
+ Napi::HandleScope scope(Env());
376
+
377
+ Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
378
+
379
+ Napi::Object retObj = Napi::Object::New(Env());
380
+
381
+ // header
382
+
383
+ Napi::Object headObj = Napi::Object::New(Env());
384
+ for (auto pair : reqhead)
385
+ {
386
+ // we iterate over all header fields
387
+ headObj.Set(std::string(pair.first), std::string(pair.second));
388
+ }
389
+ retObj.Set("header", headObj);
390
+ // delete reqheadcopy; // we own it and must free it!
391
+
392
+ // promise
393
+ Napi::External<WebTransportRespPromisePtr> promObj =
394
+ Napi::External<WebTransportRespPromisePtr>::New(Env(), promise,
395
+ [](Napi::Env /*env*/, WebTransportRespPromisePtr *ref)
396
+ {
397
+ delete ref; // we own it and must delete it
398
+ });
399
+ retObj.Set("promise", promObj);
400
+
401
+ Napi::External<WebTransportSession> wtsObj =
402
+ Napi::External<WebTransportSession>::New(Env(), session,
403
+ [](Napi::Env /*env*/, WebTransportSession *ref)
404
+ {
405
+ // we do not own it! And do not delete it.
406
+ // does it outlife everything?
407
+ });
408
+ retObj.Set("session", wtsObj);
409
+
410
+ objVal.Get("onSessionRequest")
411
+ .As<Napi::Function>()
412
+ .Call(objVal, {retObj});
413
+ }
414
+
415
+ void Http3ServerJS::addPath(const Napi::CallbackInfo &info)
416
+ {
417
+ Http3Server *obj = getObj();
418
+
419
+ if (!info[0].IsUndefined())
420
+ {
421
+
422
+ std::string lpath(info[0].ToString().Utf8Value());
423
+ obj->http3_server_backend_.addPath(lpath);
424
+ }
425
+ else
426
+ return Napi::Error::New(Env(), "No path set for addPath").ThrowAsJavaScriptException();
427
+ }
428
+
429
+ void Http3ServerJS::finishSessionRequest(const Napi::CallbackInfo &info)
430
+ {
431
+ Http3Server *obj = getObj();
432
+
433
+ if (!info[0].IsUndefined())
434
+ {
435
+ // needs two properties
436
+ int status = -1;
437
+ std::string path = "";
438
+ Napi::Object lobj = info[0].ToObject();
439
+ if (!lobj.IsEmpty())
440
+ {
441
+ if (lobj.Has("status") && !(lobj).Get("status").IsEmpty())
442
+ {
443
+ Napi::Value statusValue = (lobj).Get("status");
444
+ status = statusValue.As<Napi::Number>().Int32Value();
445
+ }
446
+ else
447
+ return Napi::Error::New(Env(), "No status code passed for finishSessionRequest").ThrowAsJavaScriptException();
448
+
449
+ if (lobj.Has("path") && !(lobj).Get("path").IsEmpty())
450
+ {
451
+ Napi::Value pathValue = (lobj).Get("path");
452
+ path = pathValue.ToString().Utf8Value();
453
+ }
454
+ else
455
+ return Napi::Error::New(Env(), "No status code passed for finishSessionRequest").ThrowAsJavaScriptException();
456
+ WebTransportSession *session = nullptr;
457
+ if (lobj.Has("session") && !(lobj).Get("session").IsEmpty())
458
+ {
459
+ Napi::Value sessionVal = (lobj).Get("session");
460
+ if (!sessionVal.IsExternal())
461
+ return Napi::Error::New(Env(), "Session is not external for finishSessionRequest").ThrowAsJavaScriptException();
462
+ Napi::External<WebTransportSession> sessionExt = sessionVal.As<Napi::External<WebTransportSession>>();
463
+ session = sessionExt.Data();
464
+ }
465
+ else
466
+ return Napi::Error::New(Env(), "No session passed for finishSessionRequest").ThrowAsJavaScriptException();
467
+
468
+ if (lobj.Has("promise") && !(lobj).Get("promise").IsEmpty())
469
+ {
470
+ Napi::Value promiseVal = (lobj).Get("promise");
471
+ if (!promiseVal.IsExternal())
472
+ return Napi::Error::New(Env(), "Promise is not external for finishSessionRequest").ThrowAsJavaScriptException();
473
+ Napi::External<Http3ServerBackend::WebTransportRespPromisePtr> promise = promiseVal.As<Napi::External<Http3ServerBackend::WebTransportRespPromisePtr>>();
474
+
475
+ Http3ServerBackend::WebTransportRespPromisePtr *prom = promise.Data();
476
+ Napi::Reference<Napi::Value> *headerValue = nullptr;
477
+ if (status == 200)
478
+ {
479
+
480
+ if (lobj.Has("header") && !(lobj).Get("header").IsEmpty())
481
+ {
482
+ napi_ref ref;
483
+ napi_status status = napi_create_reference(Env(), lobj.Get("header"), 1, &ref);
484
+ NAPI_THROW_IF_FAILED(Env(), status, Reference<Napi::Value>());
485
+ headerValue = new Napi::Reference<Napi::Value>(Env(), ref);
486
+ }
487
+ else
488
+ return Napi::Error::New(Env(), "No status code passed for finishSessionRequest").ThrowAsJavaScriptException();
489
+ }
490
+ if (status != 200)
491
+ {
492
+ std::unique_ptr<Http3ServerBackend::WebTransportResponse> response = std::make_unique<Http3ServerBackend::WebTransportResponse>();
493
+ response->response_headers[":status"] = std::to_string(status);
494
+ (*prom)->resolve(std::move(response));
495
+ }
496
+ else
497
+ {
498
+ std::unique_ptr<Http3ServerBackend::WebTransportResponse> response = std::make_unique<Http3ServerBackend::WebTransportResponse>();
499
+ response->response_headers[":status"] = std::to_string(status);
500
+ Http3WTSession *wtsession = new Http3WTSession();
501
+ wtsession->init(session);
502
+ response->visitor =
503
+ std::make_unique<Http3WTSession::Visitor>(wtsession);
504
+ processNewSession(static_cast<Http3WTSession *>(wtsession), path, headerValue);
505
+ (*prom)->resolve(std::move(response));
506
+ }
507
+ }
508
+ else
509
+ return Napi::Error::New(Env(), "No promise passed for finishSessionRequest").ThrowAsJavaScriptException();
510
+ }
511
+ else
512
+ return Napi::Error::New(Env(), "No object passed for finishSessionRequest").ThrowAsJavaScriptException();
513
+ }
514
+ }
515
+
516
+ void Http3ServerJS::setJSRequestHandler(const Napi::CallbackInfo &info)
517
+ {
518
+ Http3Server *obj = getObj();
519
+
520
+ if (!info[0].IsUndefined())
521
+ {
522
+
523
+ bool hashandler = info[0].ToBoolean();
524
+ obj->http3_server_backend_.setJSHandler(hashandler);
525
+ }
526
+ else
527
+ return Napi::Error::New(Env(), "No bool set for setJSRequestHandler").ThrowAsJavaScriptException();
528
+ }
529
+ }
@@ -0,0 +1,149 @@
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, original copyright, see LICENSE.chromium
6
+ // Copyright (c) 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
+ #ifndef WT_HTTP3_SERVER_H
11
+ #define WT_HTTP3_SERVER_H
12
+
13
+ #include <memory>
14
+
15
+ #include <napi.h>
16
+
17
+ #include "src/librarymain.h"
18
+ #include "src/http3serverbackend.h"
19
+ #include "src/napialarmfactory.h"
20
+ #include "src/socketjswriter.h"
21
+ #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
22
+ #include "quiche/quic/core/deterministic_connection_id_generator.h"
23
+ #include "quiche/quic/core/quic_udp_socket.h"
24
+ #include "quiche/quic/core/quic_dispatcher.h"
25
+ #include "quiche/quic/core/quic_packet_reader.h"
26
+ #include "quiche/quic/platform/api/quic_socket_address.h"
27
+
28
+ using namespace Napi;
29
+
30
+ namespace quic
31
+ {
32
+
33
+ class Http3EventLoop;
34
+
35
+ class Http3Server;
36
+ class Http3ServerJS;
37
+ class Http3WTSession;
38
+
39
+
40
+
41
+ class Http3ServerJS : public Napi::ObjectWrap<Http3ServerJS>,
42
+ public EnvGetter
43
+ {
44
+ friend class Http3Server;
45
+
46
+ public:
47
+ using WebTransportRespPromise = JSlikePromise<Http3ServerBackend::WebTransportResponse>;
48
+ using WebTransportRespPromisePtr = std::shared_ptr<Http3ServerBackend::WebTransportRespPromise>;
49
+ Http3ServerJS(const Napi::CallbackInfo &info);
50
+ ~Http3ServerJS();
51
+
52
+ Http3Server *getObj()
53
+ {
54
+ return server_.get();
55
+ }
56
+
57
+ Napi::Env getEnv() override
58
+ {
59
+ return Env();
60
+ }
61
+
62
+ Napi::Object getValue() override
63
+ {
64
+ return Value();
65
+ }
66
+
67
+ void destroy(const Napi::CallbackInfo &info);
68
+
69
+ void addPath(const Napi::CallbackInfo &info);
70
+
71
+ Napi::Value recvPaket(const Napi::CallbackInfo &info);
72
+
73
+ void onCanWrite(const Napi::CallbackInfo &info);
74
+
75
+ void finishSessionRequest(const Napi::CallbackInfo &info);
76
+
77
+ void setJSRequestHandler(const Napi::CallbackInfo &info);
78
+
79
+ void processBufferedChlos(const Napi::CallbackInfo &info);
80
+
81
+ static void InitExports(Napi::Env env, Napi::Object exports)
82
+ {
83
+ Napi::Function tplsrv = DefineClass(env, "Http3WebTransportServer", {InstanceMethod<&Http3ServerJS::destroy>("destroy", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::addPath>("addPath", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::recvPaket>("recvPaket", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::processBufferedChlos>("processBufferedChlos", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::onCanWrite>("onCanWrite", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::finishSessionRequest>("finishSessionRequest", static_cast<napi_property_attributes>(napi_writable | napi_configurable)), InstanceMethod<&Http3ServerJS::setJSRequestHandler>("setJSRequestHandler", static_cast<napi_property_attributes>(napi_writable | napi_configurable))});
84
+ exports.Set("Http3WebTransportServer", tplsrv);
85
+ }
86
+
87
+ void processNewSession(Http3WTSession *session, const std::string &path, Napi::Reference<Napi::Value> *header);
88
+ void processNewSessionRequest(WebTransportSession *session, const spdy::Http2HeaderBlock &reqheadcopy, WebTransportRespPromisePtr *promise);
89
+
90
+ protected:
91
+ std::unique_ptr<Http3Server> server_;
92
+ };
93
+
94
+ class Http3Server
95
+ {
96
+ friend class Http3ServerJS;
97
+
98
+ public:
99
+ Http3Server(Http3ServerJS *js,
100
+ std::unique_ptr<ProofSource> proof_source,
101
+ const char *secret,
102
+ QuicConfig config);
103
+
104
+ Http3Server(const Http3Server &) = delete;
105
+ Http3Server &operator=(const Http3Server &) = delete;
106
+
107
+ ~Http3Server();
108
+
109
+ void Destroy();
110
+
111
+ bool ProcessPacket(const QuicSocketAddress &self_address,
112
+ const QuicSocketAddress &peer_address,
113
+ const QuicReceivedPacket &packet);
114
+ void ProcessBufferedChlos();
115
+
116
+ void OnCanWrite();
117
+
118
+ Http3ServerJS *getJS() { return js_; };
119
+
120
+ private:
121
+ Http3ServerJS *js_;
122
+
123
+ QuicPacketCount packets_dropped_;
124
+ std::unique_ptr<QuicPacketReader> packet_reader_;
125
+ std::unique_ptr<QuicDispatcher> dispatcher_;
126
+ // config_ contains non-crypto parameters that are negotiated in the crypto
127
+ // handshake.
128
+ QuicConfig config_;
129
+ // crypto_config_ contains crypto parameters for the handshake.
130
+ QuicCryptoServerConfig crypto_config_;
131
+ // crypto_config_options_ contains crypto parameters for the handshake.
132
+ QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
133
+
134
+ // Used to generate current supported versions.
135
+ QuicVersionManager version_manager_;
136
+
137
+ Http3ServerBackend http3_server_backend_; // unowned.
138
+
139
+ // Connection ID length expected to be read on incoming IETF short headers.
140
+ uint8_t expected_server_connection_id_length_;
141
+
142
+ QuicDispatcher *CreateQuicDispatcher();
143
+
144
+ DeterministicConnectionIdGenerator connection_id_generator_;
145
+ };
146
+
147
+ }
148
+
149
+ #endif