@fails-components/webtransport-transport-http3-quiche 1.0.10 → 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
@@ -1,11 +1,12 @@
1
1
  export const wtrouter: any;
2
2
  export const quicheInit: any;
3
3
  export function checkQuicheInit(args?: {
4
- quicheLogVerbose?: number | undefined;
4
+ quicheLogVerbose?: import("./types.js").QUICHE_LOG | undefined;
5
5
  path?: string | undefined;
6
6
  } | undefined): void;
7
7
  export const Http3WebTransportClient: any;
8
8
  export const Http3WebTransportServer: any;
9
9
  export { Http3WebTransportClientSocket } from "./clientsocket.js";
10
10
  export { Http3WebTransportServerSocket } from "./serversocket.js";
11
+ export type QUICHE_LOG = import('./types.js').QUICHE_LOG;
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.js"],"names":[],"mappings":"AA0BA,2BAAuC;AACvC,6BAA6C;AAOtC;;;qBAON;AAED,0CAAuE;AACvE,0CAAuE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.js"],"names":[],"mappings":"AA8BA,2BAAuC;AACvC,6BAA6C;AAOtC;;;qBAON;AAED,0CAAuE;AACvE,0CAAuE;;;yBAxC1D,OAAO,YAAY,EAAE,UAAU"}
@@ -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,qBAKC;IA9BD,+BAGC;IAPC,iBAAoB;IACpB,gBAAmB;IAQrB;;OAEG;IAEH,mDAHW,OAAO,SAAS,EAAE,mBAAmB,WAiB/C;CAQF"}
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"}
@@ -11,10 +11,16 @@ export interface Logger {
11
11
  error: (formatter: any, ...args: any[]) => void;
12
12
  trace: (formatter: any, ...args: any[]) => void;
13
13
  }
14
+ export type QUICHE_LOG_OFF = -1;
15
+ export type QUICHE_LOG_INFO = 0;
16
+ export type QUICHE_LOG_WARNING = 1;
17
+ export type QUICHE_LOG_ERROR = 2;
18
+ export type QUICHE_LOG_FATAL = 3;
19
+ export type QUICHE_LOG = QUICHE_LOG_OFF | QUICHE_LOG_INFO | QUICHE_LOG_WARNING | QUICHE_LOG_ERROR | QUICHE_LOG_FATAL;
14
20
  export interface HttpWebTransportInit extends WebTransportOptions {
15
21
  host: string;
16
22
  port: string | number;
17
- quicheLogVerbose?: number;
23
+ quicheLogVerbose?: QUICHE_LOG;
18
24
  forceIpv6?: boolean;
19
25
  localPort?: number;
20
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACpB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAG,UAAU,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAC,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAChD;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACpB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAG,UAAU,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAC,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAChD;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,CAAA;AAC/B,MAAM,MAAM,eAAe,GAAG,CAAC,CAAA;AAC/B,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAA;AAClC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAChC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAChC,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,eAAe,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,gBAAgB,CAAA;AAElH,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,UAAU,CAAA;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB"}
package/lib/index.js CHANGED
@@ -5,6 +5,10 @@ import * as url from 'url'
5
5
  import { arch, platform } from 'node:process'
6
6
  import { logger } from './utils.js'
7
7
 
8
+ /**
9
+ * @typedef {import('./types.js').QUICHE_LOG} QUICHE_LOG
10
+ */
11
+
8
12
  const log = logger(`webtransport:native(${process?.pid})`)
9
13
 
10
14
  const binplatform = platform + '_' + arch
@@ -30,7 +34,7 @@ export const quicheInit = wtrouter.quicheInit
30
34
  let quicheInited = false
31
35
 
32
36
  /**
33
- * @param {{quicheLogVerbose?: Number, path?: string}} [args]
37
+ * @param {{quicheLogVerbose?: QUICHE_LOG, path?: string}} [args]
34
38
  */
35
39
  export const checkQuicheInit = function (args) {
36
40
  if (!quicheInited) {
package/lib/socket.js CHANGED
@@ -110,8 +110,12 @@ export class Http3WebTransportSocket {
110
110
  }
111
111
 
112
112
  packetSendCB() {
113
- // @ts-ignore
114
- if (this.socketInt.getSendQueueCount() === 0 && this.blocked) {
113
+ if (
114
+ !this.closed &&
115
+ // @ts-ignore
116
+ this.socketInt.getSendQueueCount() === 0 &&
117
+ this.blocked
118
+ ) {
115
119
  this.cobj.onCanWrite()
116
120
  }
117
121
  }
package/lib/types.ts CHANGED
@@ -16,11 +16,17 @@ export interface UDPServerSocketSend {
16
16
  trace: (formatter: any, ...args: any[]) => void
17
17
  }
18
18
 
19
+ export type QUICHE_LOG_OFF = -1
20
+ export type QUICHE_LOG_INFO = 0
21
+ export type QUICHE_LOG_WARNING = 1
22
+ export type QUICHE_LOG_ERROR = 2
23
+ export type QUICHE_LOG_FATAL = 3
24
+ export type QUICHE_LOG = QUICHE_LOG_OFF | QUICHE_LOG_INFO | QUICHE_LOG_WARNING | QUICHE_LOG_ERROR | QUICHE_LOG_FATAL
25
+
19
26
  export interface HttpWebTransportInit extends WebTransportOptions {
20
27
  host: string
21
28
  port: string | number
22
- quicheLogVerbose?: number
29
+ quicheLogVerbose?: QUICHE_LOG
23
30
  forceIpv6?: boolean
24
31
  localPort?: number
25
32
  }
26
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fails-components/webtransport-transport-http3-quiche",
3
- "version": "1.0.10",
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
  ".": {
@@ -532,7 +532,7 @@ namespace quic
532
532
  if (wait_for_encryption_)
533
533
  {
534
534
  if (EncryptionBeingEstablished())
535
- return false;
535
+ return true;
536
536
  wait_for_encryption_ = false;
537
537
  ParsedQuicVersion version = UnsupportedQuicVersion();
538
538
  if (session_ != nullptr && !CanReconnectWithDifferentVersion(&version) && !session_->connection()->connected())
@@ -569,11 +569,6 @@ namespace quic
569
569
  recheck = true;
570
570
  }
571
571
 
572
- if (checkSession())
573
- {
574
- recheck = true;
575
- }
576
-
577
572
  return recheck;
578
573
  }
579
574
 
@@ -826,16 +821,18 @@ namespace quic
826
821
 
827
822
  if (client_->connectionrecheck_)
828
823
  {
829
- client_->connectionrecheck_ = !client_->handleConnecting();
824
+ client_->connectionrecheck_ = client_->handleConnecting();
830
825
  }
826
+ if (client_->needsToCheckForSession()) client_->checkSession();
831
827
  }
832
828
 
833
829
  void Http3ClientJS::onCanWrite(const Napi::CallbackInfo &info)
834
830
  {
835
831
  if (client_->connectionrecheck_)
836
832
  {
837
- client_->connectionrecheck_ = !client_->handleConnecting();
833
+ client_->connectionrecheck_ = client_->handleConnecting();
838
834
  }
835
+ if (client_->needsToCheckForSession()) client_->checkSession();
839
836
  client_->OnCanWrite();
840
837
  }
841
838
 
package/src/http3client.h CHANGED
@@ -349,6 +349,10 @@ namespace quic
349
349
 
350
350
  bool checkSession();
351
351
 
352
+ bool needsToCheckForSession() {
353
+ return finish_stream_open_.size() > 0 && session_->CanOpenNextOutgoingBidirectionalStream();
354
+ }
355
+
352
356
  // Read oldest received response and remove it from closed_stream_states_.
353
357
  // void ReadNextResponse();
354
358
 
@@ -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";
@@ -83,34 +83,46 @@ namespace quic
83
83
  void Http3WTStream::doCanRead()
84
84
  {
85
85
  // if (pause_reading_) return ; // back pressure folks!
86
+ WebTransportStream::PeekResult pr;
87
+ pr = stream_->PeekNextReadableRegion();
88
+
89
+ if (pr.fin_next && pr.peeked_data.size() == 0) {
90
+ bool fin = stream_->SkipBytes(0);
91
+ if (fin) {
92
+ getJS()->signalFinOnly();
93
+ return;
94
+ }
95
+ }
86
96
 
87
97
  if (pause_reading_ && !drain_reads_)
88
98
  {
89
99
  can_read_pending_ = true;
90
100
  return; // back pressure folks!
91
101
  }
92
- size_t readable = stream_->ReadableBytes();
93
102
  bool read = false;
94
- while (readable > 0)
103
+ while (!pr.peeked_data.empty())
95
104
  {
96
105
  Http3WTStreamJS::StreamReadBuffer rbuf(js_);
97
- rbuf.getBuffer(readable);
106
+ rbuf.getBuffer(stream_->ReadableBytes());
98
107
 
99
108
  size_t remainSize = rbuf.bufferSize();
100
109
  uint32_t writepos = 0;
101
110
 
102
- while (readable > 0 && remainSize > 0) {
103
- size_t len = remainSize;
104
- WebTransportStream::ReadResult result =
105
- stream_->Read(absl::Span<char>(((char *)rbuf.bufferData()) + writepos, len));
111
+ while (!pr.peeked_data.empty() && remainSize > 0) {
112
+ size_t len = std::min(remainSize, pr.peeked_data.size());
113
+ if (len > 0) memcpy(((char *)rbuf.bufferData()) + writepos,pr.peeked_data.data(), len);
114
+ bool fin = stream_->SkipBytes(len);
106
115
  QUIC_DVLOG(1) << "Attempted reading on WebTransport stream "
107
- << ", bytes read: " << result.bytes_read;
108
- writepos += result.bytes_read;
109
- remainSize -= result.bytes_read;
110
- readable = stream_->ReadableBytes();
111
- if (result.fin) rbuf.setFin();
116
+ << ", bytes read: " << len;
117
+ writepos += len;
118
+ remainSize -= len;
119
+ pr = stream_->PeekNextReadableRegion();
120
+ if (fin) {
121
+ rbuf.setFin();
122
+ break;
123
+ }
112
124
  }
113
- rbuf.commitBuffer(writepos, readable == 0);
125
+ rbuf.commitBuffer(writepos, pr.has_data());
114
126
  }
115
127
  }
116
128
 
@@ -142,8 +154,10 @@ namespace quic
142
154
  if (send_fin_)
143
155
  {
144
156
  bool success = stream_->SendFin();
145
- if (success)
157
+ if (success) {
146
158
  fin_was_sent_ = true;
159
+ getJS()->processStreamNetworkFinish(NetworkTask::streamFinal);
160
+ }
147
161
  }
148
162
  }
149
163
 
@@ -165,6 +179,17 @@ namespace quic
165
179
  }
166
180
  }
167
181
 
182
+
183
+ void Http3WTStreamJS::signalFinOnly() {
184
+ Napi::HandleScope scope(Env());
185
+ Napi::Object retObj = Napi::Object::New(Env());
186
+ Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
187
+ retObj.Set("fin", true);
188
+ Napi::Value bufferVal = objVal.Get("commitReadBuffer").As<Napi::Function>().Call(objVal, {retObj});
189
+ }
190
+
191
+
192
+
168
193
  void Http3WTStreamJS::processStreamNetworkFinish(NetworkTask task)
169
194
  {
170
195
  Napi::HandleScope scope(Env());
@@ -317,6 +317,7 @@ namespace quic
317
317
  void processStreamWrite(Napi::ObjectReference *bufferhandle, bool success);
318
318
  void processStreamNetworkFinish(NetworkTask task);
319
319
  void processStreamRecvSignal(WebTransportStreamError error_code, NetworkTask task);
320
+ void signalFinOnly();
320
321
  };
321
322
  }
322
323
 
@@ -38,7 +38,7 @@ namespace quic
38
38
  }
39
39
 
40
40
  quiche_cmd_line.push_back(std::string("-v"));
41
- if (lobj.Has("quicheLogVerbose") && lobj.Get("quicheLogVerbose").IsFunction())
41
+ if (lobj.Has("quicheLogVerbose") && lobj.Get("quicheLogVerbose").IsNumber())
42
42
  {
43
43
  Napi::Value verboseValue = (lobj).Get("quicheLogVerbose");
44
44
  quiche_cmd_line.push_back(verboseValue.ToString().Utf8Value());
@@ -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;