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

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
@@ -609,6 +611,8 @@ third_party/quiche/quiche/quic/core/quic_alarm_factory.h
609
611
  third_party/quiche/quiche/quic/core/quic_arena_scoped_ptr.h
610
612
  third_party/quiche/quiche/quic/core/quic_bandwidth.cc
611
613
  third_party/quiche/quiche/quic/core/quic_bandwidth.h
614
+ third_party/quiche/quiche/quic/core/quic_blocked_writer_list.cc
615
+ third_party/quiche/quiche/quic/core/quic_blocked_writer_list.h
612
616
  third_party/quiche/quiche/quic/core/quic_blocked_writer_interface.h
613
617
  third_party/quiche/quiche/quic/core/quic_buffered_packet_store.cc
614
618
  third_party/quiche/quiche/quic/core/quic_buffered_packet_store.h
@@ -621,6 +625,8 @@ third_party/quiche/quiche/quic/core/quic_config.cc
621
625
  third_party/quiche/quiche/quic/core/quic_config.h
622
626
  third_party/quiche/quiche/quic/core/quic_connection.cc
623
627
  third_party/quiche/quiche/quic/core/quic_connection.h
628
+ third_party/quiche/quiche/quic/core/quic_connection_alarms.cc
629
+ third_party/quiche/quiche/quic/core/quic_connection_alarms.h
624
630
  third_party/quiche/quiche/quic/core/quic_connection_context.cc
625
631
  third_party/quiche/quiche/quic/core/quic_connection_context.h
626
632
  third_party/quiche/quiche/quic/core/quic_connection_id.cc
package/build.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { arch, argv, env, platform } from 'node:process'
2
2
  import { spawn } from 'node:child_process'
3
- import { cp, rename, mkdtemp, rm, access, readdir } from 'node:fs/promises'
3
+ import { cp, rename, mkdtemp, rm, access } from 'node:fs/promises'
4
4
  import { constants } from 'node:fs'
5
5
  import path from 'node:path'
6
- import pkg from './package.json' assert { type: 'json' }
6
+ import pkg from './package.json' with { type: 'json' }
7
7
  import { tmpdir } from 'node:os'
8
8
 
9
9
  const binplatform = platform + '_' + arch
@@ -87,7 +87,7 @@ const extractthirdparty = async () => {
87
87
  'transports/http3-quiche/third_party/googleurl',
88
88
  'transports/http3-quiche/third_party/protobuf'
89
89
  ]
90
- for (let mod in submodules) {
90
+ for (const mod in submodules) {
91
91
  const sub = submodules[mod]
92
92
  await callGit(
93
93
  [
@@ -141,8 +141,8 @@ const prebuild = (args) => {
141
141
 
142
142
  proc.on('close', (code) => {
143
143
  console.log(`child process exited with code ${code}`)
144
- if (code == 0) resolve()
145
- else reject()
144
+ if (code === 0) resolve()
145
+ else reject(new Error(`child process exited with code ${code}`))
146
146
  })
147
147
  })
148
148
  }
@@ -237,7 +237,7 @@ if (argv.length > 2) {
237
237
  process.exit(1)
238
238
  }
239
239
  break
240
- case 'install': {
240
+ case 'install':
241
241
  try {
242
242
  const pbres = await prebuildInstall([
243
243
  '-r',
@@ -261,7 +261,7 @@ if (argv.length > 2) {
261
261
  console.error('Building binary failed: ', error)
262
262
  process.exit(1)
263
263
  }
264
- } break
264
+ break
265
265
  case 'build':
266
266
  try {
267
267
  await execbuild(['build', ...platformargs])
@@ -1 +1 @@
1
- {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../lib/socket.js"],"names":[],"mappings":"AAqEA;IACE;;OAEG;IACH,kBAFW,OAAO,4BAA4B,EAAE,oBAAoB,GAAC,SAAS,EAa7E;IAVC,0CAA0C;IAE1C,WAFW,OAAO,YAAY,EAAE,MAAM,CAEZ;IAE1B,UAAqB;IACrB,oBAAuB;IAgCzB,qBASC;IAlCD,+BAGC;IAPC,iBAAoB;IACpB,gBAAmB;IAQrB;;OAEG;IAEH,mDAHW,OAAO,SAAS,EAAE,mBAAmB,WAiB/C;CAYF"}
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../lib/socket.js"],"names":[],"mappings":"AAqEA;IACE;;OAEG;IAEH,kBAHW,OAAO,4BAA4B,EAAE,oBAAoB,GAAC,SAAS,EAc7E;IAVC,0CAA0C;IAE1C,WAFW,OAAO,YAAY,EAAE,MAAM,CAEZ;IAE1B,UAAqB;IACrB,oBAAuB;IAgCzB,qBASC;IAlCD,+BAGC;IAPC,iBAAoB;IACpB,gBAAmB;IAQrB;;OAEG;IAEH,mDAHW,OAAO,SAAS,EAAE,mBAAmB,WAiB/C;CAYF"}
@@ -0,0 +1,51 @@
1
+
2
+ import js from "@eslint/js"
3
+ import promise from "eslint-plugin-promise"
4
+ import babelParser from "@babel/eslint-parser"
5
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
6
+ import globals from "globals";
7
+
8
+ export default [
9
+ js.configs.recommended,
10
+ eslintPluginPrettierRecommended,
11
+ {
12
+ plugins: {
13
+ promise
14
+ },
15
+ languageOptions: {
16
+ globals: {
17
+ ...globals.node
18
+
19
+ },
20
+ parser: babelParser,
21
+ ecmaVersion: 2020,
22
+ parserOptions: {
23
+ ecmaFeatures: {
24
+ legacyDecorators: true,
25
+ jsx: true
26
+ },
27
+ requireConfigFile: false,
28
+ }
29
+ },
30
+ ignores: [
31
+ "build/*",
32
+ "dist/*",
33
+ "node_modules/*",
34
+ ".snapshots/*",
35
+ "*.min.js"
36
+ ],
37
+ rules: {
38
+ "space-before-function-paren": 0,
39
+ "import/export": 0,
40
+ "promise/catch-or-return": "error",
41
+ "no-useless-return": 1,
42
+ "camelcase": 1,
43
+ },
44
+ },
45
+ {
46
+ files: ["test/*.spec.js"],
47
+ rules: {
48
+ "no-undef": 0
49
+ }
50
+ },
51
+ ];
package/lib/socket.js CHANGED
@@ -71,6 +71,7 @@ export class Http3WebTransportSocket {
71
71
  /**
72
72
  * @param {import('../../../main/lib/types.js').HttpWebTransportInit|undefined} args
73
73
  */
74
+ // eslint-disable-next-line no-unused-vars
74
75
  constructor(args) {
75
76
  /** @type {import('node:dgram').Socket} */
76
77
  // @ts-ignore
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.2",
4
4
  "description": "A component to add webtransport support (server and client) to node.js, transport using libquiche",
5
5
  "exports": {
6
6
  ".": {
@@ -48,15 +48,15 @@
48
48
  "@babel/eslint-parser": "^7.17.0",
49
49
  "@babel/plugin-syntax-import-attributes": "^7.23.3",
50
50
  "@types/node": "^18.15.3",
51
- "eslint": "^7.32.0",
52
- "eslint-config-prettier": "^7.2.0",
51
+ "eslint": "^9.3.0",
52
+ "eslint-config-prettier": "^9.1.0",
53
53
  "eslint-config-standard": "^16.0.2",
54
54
  "eslint-plugin-import": "^2.25.2",
55
55
  "eslint-plugin-node": "^11.1.0",
56
- "eslint-plugin-prettier": "^3.4.1",
56
+ "eslint-plugin-prettier": "^5.1.3",
57
57
  "eslint-plugin-promise": "^4.3.1",
58
58
  "eslint-plugin-standard": "^4.1.0",
59
- "prettier": "^2.4.1",
59
+ "prettier": "^3.2.5",
60
60
  "typescript": "^4.8.4"
61
61
  },
62
62
  "binary": {
@@ -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";
@@ -67,6 +67,11 @@ namespace quic
67
67
 
68
68
  Napi::Object Init(Napi::Env env, Napi::Object exports)
69
69
  {
70
+ #ifdef _MSC_VER
71
+ // work around clangcl bug
72
+ napi_value dummy;
73
+ napi_create_double(env,2.0, &dummy);
74
+ #endif
70
75
  Http3Constructors *constr = new Http3Constructors();
71
76
 
72
77
  Http3ServerJS::InitExports(env, exports);
@@ -134,10 +134,11 @@ namespace quic
134
134
  alarmref_.Unref();
135
135
  timerset_ = false;
136
136
  }
137
+ auto val = Napi::Value::From(alarmjs_->Env(), timedelay);
137
138
 
138
139
  Napi::Value timeoutobj = NapiAlarmJS::FAILSsetTimeoutAlarm_.Call({
139
140
  alarmjs_->Value().As<Napi::Object>(),
140
- Napi::Value::From(alarmjs_->Env(), timedelay),
141
+ val,
141
142
  });
142
143
  alarmref_ = Napi::Reference<Napi::Object>::New(timeoutobj.As<Napi::Object>(), 1);
143
144
  timerset_ = true;