@fails-components/webtransport-transport-http3-quiche 1.0.11 → 1.1.0

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 CHANGED
@@ -539,6 +539,8 @@ third_party/quiche/quiche/quic/core/http/quic_spdy_stream.cc
539
539
  third_party/quiche/quiche/quic/core/http/quic_spdy_stream.h
540
540
  third_party/quiche/quiche/quic/core/http/quic_spdy_stream_body_manager.cc
541
541
  third_party/quiche/quiche/quic/core/http/quic_spdy_stream_body_manager.h
542
+ third_party/quiche/quiche/quic/core/http/metadata_decoder.cc
543
+ third_party/quiche/quiche/quic/core/http/metadata_decoder.h
542
544
  third_party/quiche/quiche/quic/core/http/spdy_utils.cc
543
545
  third_party/quiche/quiche/quic/core/http/spdy_utils.h
544
546
  third_party/quiche/quiche/quic/core/http/web_transport_http3.cc
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fails-components/webtransport-transport-http3-quiche",
3
- "version": "1.0.11",
3
+ "version": "1.1.0",
4
4
  "description": "A component to add webtransport support (server and client) to node.js, transport using libquiche",
5
5
  "exports": {
6
6
  ".": {
@@ -91,8 +91,8 @@ namespace quic
91
91
  Http3ServerJS::Http3ServerJS(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Http3ServerJS>(info)
92
92
  {
93
93
  std::string secret;
94
- std::string cert;
95
- std::string privkey;
94
+ std::vector<std::string> cert;
95
+ std::vector<std::string> privkey;
96
96
 
97
97
  QuicConfig sconfig;
98
98
  if (!info[0].IsUndefined())
@@ -113,7 +113,16 @@ namespace quic
113
113
  if (lobj.Has("cert") && !(lobj).Get("cert").IsEmpty())
114
114
  {
115
115
  Napi::Value certValue = (lobj).Get("cert");
116
- cert = certValue.ToString().Utf8Value();
116
+ if (!certValue.IsArray()) {
117
+ cert.push_back(certValue.ToString().Utf8Value());
118
+ } else {
119
+ Napi::Array certArray = certValue.As<Napi::Array>();
120
+ if (certArray.Length() < 1) Napi::Error::New(Env(), "No cert in array for Http3Server").ThrowAsJavaScriptException();
121
+ for (uint32_t i = 0; i < certArray.Length(); i++) {
122
+ Napi::Value curval = certArray.Get(i);
123
+ cert.push_back(curval.ToString().Utf8Value());
124
+ }
125
+ }
117
126
  }
118
127
  else
119
128
  {
@@ -123,13 +132,23 @@ namespace quic
123
132
  if (lobj.Has("privKey") && !(lobj).Get("privKey").IsEmpty())
124
133
  {
125
134
  Napi::Value keyValue = (lobj).Get("privKey");
126
- privkey = keyValue.ToString().Utf8Value();
135
+ if (!keyValue.IsArray()) {
136
+ privkey.push_back(keyValue.ToString().Utf8Value());
137
+ } else {
138
+ Napi::Array keyArray = keyValue.As<Napi::Array>();
139
+ if (keyArray.Length() < 1) Napi::Error::New(Env(), "No key in array for Http3Server").ThrowAsJavaScriptException();
140
+ for (uint32_t i = 0; i < keyArray.Length(); i++) {
141
+ Napi::Value curval = keyArray.Get(i);
142
+ privkey.push_back(curval.ToString().Utf8Value());
143
+ }
144
+ }
127
145
  }
128
146
  else
129
147
  {
130
148
  Napi::Error::New(Env(), "No privKey set for Http3Server").ThrowAsJavaScriptException();
131
149
  return;
132
150
  }
151
+ if (privkey.size() != cert.size()) Napi::Error::New(Env(), "Key and cert array length for Http3Server do not match").ThrowAsJavaScriptException();
133
152
  if (lobj.Has("maxConnections") && !(lobj).Get("maxConnections").IsEmpty())
134
153
  {
135
154
  Napi::Value maxconnValue = (lobj).Get("maxConnections");
@@ -176,10 +195,10 @@ namespace quic
176
195
  }
177
196
  // Callback *callback, int port, std::unique_ptr<ProofSource> proof_source, const char *secret
178
197
 
179
- std::stringstream certstream(cert, std::ios_base::in);
198
+ std::stringstream certstream(cert[0], std::ios_base::in);
180
199
  quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain(new ProofSource::Chain(CertificateView::LoadPemFromStream(&certstream)));
181
200
 
182
- std::stringstream privkeystream(privkey, std::ios_base::in);
201
+ std::stringstream privkeystream(privkey[0], std::ios_base::in);
183
202
 
184
203
  auto certprivkey = CertificatePrivateKey::LoadPemFromStream(&privkeystream);
185
204
  if (certprivkey == nullptr)
@@ -194,6 +213,25 @@ namespace quic
194
213
  Napi::Error::New(Env(), "LoadPemFromStream cert failed for Http3Server").ThrowAsJavaScriptException();
195
214
  return;
196
215
  }
216
+ // add additional certs to proof source
217
+ for (size_t i = 1; i < cert.size(); i++)
218
+ {
219
+ std::stringstream addcertstream(cert[0], std::ios_base::in);
220
+ quiche::QuicheReferenceCountedPointer<ProofSource::Chain> addchain(new ProofSource::Chain(CertificateView::LoadPemFromStream(&addcertstream)));
221
+ std::stringstream addprivkeystream(privkey[0], std::ios_base::in);
222
+ auto addcertprivkey = CertificatePrivateKey::LoadPemFromStream(&privkeystream);
223
+ if (addcertprivkey == nullptr)
224
+ {
225
+ Napi::Error::New(Env(), "LoadPemFromStream addprivKey failed for Http3Server").ThrowAsJavaScriptException();
226
+ return;
227
+ }
228
+
229
+ if (!proofsource->AddCertificateChain(addchain, std::move(*addcertprivkey)))
230
+ {
231
+ Napi::Error::New(Env(), "AddCertificateChain failed for Http3Server").ThrowAsJavaScriptException();
232
+ return;
233
+ }
234
+ }
197
235
 
198
236
  server_ = std::make_unique<Http3Server>(this, std::move(proofsource), secret.c_str(), sconfig);
199
237
 
@@ -207,7 +245,7 @@ namespace quic
207
245
  }
208
246
 
209
247
  Http3ServerJS::~Http3ServerJS()
210
- {
248
+ {
211
249
  }
212
250
 
213
251
  void Http3ServerJS::destroy(const Napi::CallbackInfo &info)
@@ -357,7 +395,7 @@ namespace quic
357
395
  }
358
396
  }*/
359
397
 
360
- void Http3ServerJS::processNewSession(Http3WTSession *session, const std::string &path, Napi::Reference<Napi::Value> *header)
398
+ void Http3ServerJS::processNewSession(Http3WTSession *session, const std::string &path, Napi::Reference<Napi::Value> *header, Napi::Reference<Napi::Value> *userData)
361
399
  {
362
400
  Napi::HandleScope scope(Env());
363
401
 
@@ -378,12 +416,17 @@ namespace quic
378
416
  retObj.Set("header", header->Value());
379
417
  header->Unref();
380
418
  }
419
+ if (userData)
420
+ {
421
+ retObj.Set("userData", userData->Value());
422
+ userData->Unref();
423
+ }
381
424
  objVal.Get("onHttpWTSessionVisitor")
382
425
  .As<Napi::Function>()
383
426
  .Call(objVal, {retObj});
384
427
  }
385
428
 
386
- void Http3ServerJS::processNewSessionRequest(WebTransportSession *session, const spdy::Http2HeaderBlock &reqhead, WebTransportRespPromisePtr *promise)
429
+ void Http3ServerJS::processNewSessionRequest(WebTransportSession *session, const spdy::Http2HeaderBlock &reqhead, WebTransportRespPromisePtr promise)
387
430
  {
388
431
  Napi::HandleScope scope(Env());
389
432
 
@@ -401,10 +444,11 @@ namespace quic
401
444
  }
402
445
  retObj.Set("header", headObj);
403
446
  // delete reqheadcopy; // we own it and must free it!
404
-
447
+
448
+ WebTransportRespPromisePtr *prompointer = new WebTransportRespPromisePtr(promise);
405
449
  // promise
406
450
  Napi::External<WebTransportRespPromisePtr> promObj =
407
- Napi::External<WebTransportRespPromisePtr>::New(Env(), promise,
451
+ Napi::External<WebTransportRespPromisePtr>::New(Env(), prompointer,
408
452
  [](Napi::Env /*env*/, WebTransportRespPromisePtr *ref)
409
453
  {
410
454
  delete ref; // we own it and must delete it
@@ -419,6 +463,7 @@ namespace quic
419
463
  // does it outlife everything?
420
464
  });
421
465
  retObj.Set("session", wtsObj);
466
+ retObj.Set("protocol", "http3:libquiche");
422
467
 
423
468
  objVal.Get("onSessionRequest")
424
469
  .As<Napi::Function>()
@@ -465,7 +510,7 @@ namespace quic
465
510
  path = pathValue.ToString().Utf8Value();
466
511
  }
467
512
  else
468
- return Napi::Error::New(Env(), "No status code passed for finishSessionRequest").ThrowAsJavaScriptException();
513
+ return Napi::Error::New(Env(), "No path passed for finishSessionRequest").ThrowAsJavaScriptException();
469
514
  WebTransportSession *session = nullptr;
470
515
  if (lobj.Has("session") && !(lobj).Get("session").IsEmpty())
471
516
  {
@@ -487,6 +532,7 @@ namespace quic
487
532
 
488
533
  Http3ServerBackend::WebTransportRespPromisePtr *prom = promise.Data();
489
534
  Napi::Reference<Napi::Value> *headerValue = nullptr;
535
+ Napi::Reference<Napi::Value> *userDataValue = nullptr;
490
536
  if (status == 200)
491
537
  {
492
538
 
@@ -498,7 +544,14 @@ namespace quic
498
544
  headerValue = new Napi::Reference<Napi::Value>(Env(), ref);
499
545
  }
500
546
  else
501
- return Napi::Error::New(Env(), "No status code passed for finishSessionRequest").ThrowAsJavaScriptException();
547
+ return Napi::Error::New(Env(), "No header passed for finishSessionRequest").ThrowAsJavaScriptException();
548
+ if (lobj.Has("userData") && !(lobj).Get("userData").IsEmpty())
549
+ {
550
+ napi_ref ref;
551
+ napi_status status = napi_create_reference(Env(), lobj.Get("userData"), 1, &ref);
552
+ NAPI_THROW_IF_FAILED(Env(), status, Reference<Napi::Value>());
553
+ userDataValue = new Napi::Reference<Napi::Value>(Env(), ref);
554
+ }
502
555
  }
503
556
  if (status != 200)
504
557
  {
@@ -514,7 +567,7 @@ namespace quic
514
567
  wtsession->init(session);
515
568
  response->visitor =
516
569
  std::make_unique<Http3WTSession::Visitor>(wtsession);
517
- processNewSession(static_cast<Http3WTSession *>(wtsession), path, headerValue);
570
+ processNewSession(static_cast<Http3WTSession *>(wtsession), path, headerValue, userDataValue);
518
571
  (*prom)->resolve(std::move(response));
519
572
  }
520
573
  }
package/src/http3server.h CHANGED
@@ -84,8 +84,8 @@ namespace quic
84
84
  exports.Set("Http3WebTransportServer", tplsrv);
85
85
  }
86
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);
87
+ void processNewSession(Http3WTSession *session, const std::string &path, Napi::Reference<Napi::Value> *header, Napi::Reference<Napi::Value> *userData);
88
+ void processNewSessionRequest(WebTransportSession *session, const spdy::Http2HeaderBlock &reqheadcopy, WebTransportRespPromisePtr promise);
89
89
 
90
90
  protected:
91
91
  std::unique_ptr<Http3Server> server_;
@@ -67,27 +67,28 @@ namespace quic
67
67
  }
68
68
  std::string path(path_it->second);
69
69
 
70
+ if (jshandlerequesthandler_)
71
+ {
72
+ // first step pass header block along, due to thread safety, we need to copy
73
+ // not necessary anymore
74
+
75
+ // second step inform the js side
76
+ server_->getJS()->processNewSessionRequest(session, request_headers, promise);
77
+ return promise;
78
+ }
79
+
70
80
  if (paths_.find(path) != paths_.end())
71
- { // to do handle our web transport paths
81
+ { // to do handle our web transport paths, if no handler is present
72
82
  std::unique_ptr<WebTransportResponse> response = std::make_unique<WebTransportResponse>();
73
83
  Http3WTSession *wtsession = new Http3WTSession();
74
84
  wtsession->init(session);
75
85
  response->response_headers[":status"] = "200";
76
86
  response->visitor =
77
87
  std::make_unique<Http3WTSession::Visitor>(wtsession);
78
- server_->getJS()->processNewSession(static_cast<Http3WTSession *>(wtsession), path, nullptr);
88
+ server_->getJS()->processNewSession(static_cast<Http3WTSession *>(wtsession), path, nullptr, nullptr);
79
89
  promise->resolve(std::move(response));
80
90
  return promise;
81
91
  }
82
- else if (jshandlerequesthandler_)
83
- {
84
- // first step pass header block along, due to thread safety, we need to copy
85
- // not necessary anymore
86
-
87
- // second step inform the js side
88
- server_->getJS()->processNewSessionRequest(session, request_headers, &promise);
89
- return promise;
90
- }
91
92
 
92
93
  std::unique_ptr<WebTransportResponse> response = std::make_unique<WebTransportResponse>();
93
94
  response->response_headers[":status"] = "404";
@@ -134,10 +134,17 @@ namespace quic
134
134
  alarmref_.Unref();
135
135
  timerset_ = false;
136
136
  }
137
+ auto val = Napi::Value::From(alarmjs_->Env(), timedelay);
138
+ // Workaround for problem on windows plattform
139
+ if (val.ToNumber().DoubleValue() != timedelay) {
140
+ // printf("val %lg %lg\n", val.ToNumber().DoubleValue(), timedelay);
141
+ val = Napi::Value::From(alarmjs_->Env(), timedelay);
142
+ // printf("val2 %lg %lg\n", val.ToNumber().DoubleValue(), timedelay);
143
+ }
137
144
 
138
145
  Napi::Value timeoutobj = NapiAlarmJS::FAILSsetTimeoutAlarm_.Call({
139
146
  alarmjs_->Value().As<Napi::Object>(),
140
- Napi::Value::From(alarmjs_->Env(), timedelay),
147
+ val,
141
148
  });
142
149
  alarmref_ = Napi::Reference<Napi::Object>::New(timeoutobj.As<Napi::Object>(), 1);
143
150
  timerset_ = true;