@fails-components/webtransport 0.1.5 → 0.2.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.
Files changed (70) hide show
  1. package/CMakeLists.txt +42 -111
  2. package/build.js +4 -4
  3. package/dist/lib/dom.d.ts +6 -0
  4. package/dist/lib/dom.d.ts.map +1 -1
  5. package/dist/lib/event-loop.d.ts +8 -3
  6. package/dist/lib/event-loop.d.ts.map +1 -1
  7. package/dist/lib/server.d.ts +3 -2
  8. package/dist/lib/server.d.ts.map +1 -1
  9. package/dist/lib/session.d.ts +78 -18
  10. package/dist/lib/session.d.ts.map +1 -1
  11. package/dist/lib/stream.d.ts +13 -5
  12. package/dist/lib/stream.d.ts.map +1 -1
  13. package/dist/lib/transport.d.ts.map +1 -1
  14. package/dist/lib/types.d.ts +11 -2
  15. package/dist/lib/types.d.ts.map +1 -1
  16. package/dist/lib/webtransport.d.ts +22 -0
  17. package/dist/lib/webtransport.d.ts.map +1 -1
  18. package/dist/test/bidirectional-streams.spec.d.ts.map +1 -1
  19. package/dist/test/datagrams.spec.d.ts.map +1 -1
  20. package/dist/test/fixtures/p-timeout.d.ts +8 -0
  21. package/dist/test/fixtures/p-timeout.d.ts.map +1 -0
  22. package/dist/test/fixtures/read-stream.d.ts.map +1 -1
  23. package/dist/test/unidirectional-streams.spec.d.ts.map +1 -1
  24. package/lib/dom.ts +7 -2
  25. package/lib/event-loop.js +13 -7
  26. package/lib/server.js +1 -1
  27. package/lib/session.js +71 -21
  28. package/lib/stream.js +137 -12
  29. package/lib/transport.js +3 -1
  30. package/lib/types.ts +13 -2
  31. package/lib/webtransport.js +31 -0
  32. package/package.json +5 -4
  33. package/platform/base/strings/utf_ostream_operators.h +5 -0
  34. package/platform/quiche/quic/core/io/socket_win.inc +3 -0
  35. package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +7 -0
  36. package/platform/quiche_platform_impl/quiche_export_impl.h +3 -9
  37. package/platform/quiche_platform_impl/quiche_server_stats_impl.h +1 -22
  38. package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +1 -4
  39. package/platform/quiche_platform_impl/quiche_time_utils_impl.h +1 -13
  40. package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +9 -0
  41. package/readme.md +3 -1
  42. package/src/http3client.cc +13 -29
  43. package/src/http3client.h +2 -6
  44. package/src/http3clientsession.cc +51 -40
  45. package/src/http3clientsession.h +44 -31
  46. package/src/http3clientstream.cc +17 -0
  47. package/src/http3clientstream.h +10 -0
  48. package/src/http3eventloop.cc +81 -61
  49. package/src/http3eventloop.h +10 -7
  50. package/src/http3server.cc +1 -1
  51. package/src/http3serversession.cc +1 -136
  52. package/src/http3serversession.h +7 -77
  53. package/src/http3serverstream.cc +0 -49
  54. package/src/http3serverstream.h +0 -5
  55. package/src/http3wtsessionvisitor.cc +1 -1
  56. package/src/http3wtsessionvisitor.h +24 -37
  57. package/src/http3wtstreamvisitor.cc +35 -8
  58. package/src/http3wtstreamvisitor.h +81 -3
  59. package/test/bidirectional-streams.spec.js +16 -7
  60. package/test/datagrams.spec.js +31 -20
  61. package/test/fixtures/p-timeout.js +33 -0
  62. package/test/fixtures/read-stream.js +4 -1
  63. package/test/unidirectional-streams.spec.js +24 -15
  64. package/platform/net/quiche/common/platform/impl/quiche_flags_impl.h +0 -12
  65. package/platform/poll.h +0 -2
  66. package/platform/quiche/quic/core/io/quic_poll_event_loop.h +0 -8
  67. package/platform/quiche_platform_impl/quic_testvalue_impl.h +0 -19
  68. package/platform/quiche_platform_impl/quic_udp_socket_winsock.cc +0 -732
  69. package/platform/quiche_platform_impl/quiche_time_utils_impl.cc +0 -43
  70. package/platform/quiche_platform_impl/socket_winsock.cc +0 -535
package/lib/stream.js CHANGED
@@ -38,22 +38,48 @@ export class Http3WTStream {
38
38
  this.pendingoperation = null
39
39
  this.pendingres = null
40
40
 
41
+ /** @type {Promise<void> | null} */
42
+ this.pendingoperationRead = null
43
+ this.pendingresRead = null
44
+
41
45
  if (this.bidirectional || this.incoming) {
46
+ /** @type {Number} */
47
+ this.incomingbufferfilled = 0
48
+ /** @type {Number} */
49
+ this.incomingbufferreadpos = 0
50
+ if (!this.objint.readbuffer)
51
+ throw new Error('No readbuffer for read stream')
52
+ // @ts-expect-error `getStats` property is missing from ReadableStream
53
+ /** @type {WebTransportReceiveStream} */
42
54
  this.readable = new ReadableStream(
43
55
  {
44
- start: (controller) => {
56
+ start: (
57
+ /** @type {import("stream/web").ReadableByteStreamController} */ controller
58
+ ) => {
45
59
  this.readableController = controller
46
- // @ts-expect-error this.readable could be undefined
47
60
  this.parentobj.addReceiveStream(this.readable, controller)
48
61
  this.objint.startReading()
49
62
  },
50
- pull: (controller) => {
63
+ pull: async (
64
+ /** @type {import("stream/web").ReadableByteStreamController} */ controller
65
+ ) => {
51
66
  if (this.readableclosed) {
52
67
  return Promise.resolve()
53
68
  }
54
- this.objint.startReading()
69
+
70
+ /** @type {Uint8Array} */
71
+ if (this.incomingbufferfilled === 0) {
72
+ this.pendingoperationRead = new Promise((resolve, reject) => {
73
+ this.pendingresRead = resolve
74
+ })
75
+ await this.pendingoperationRead
76
+ }
77
+ if (this.incomingbufferfilled === 0)
78
+ throw new Error('error reading')
79
+
80
+ this.drainBuffer()
55
81
  },
56
- cancel: (reason) => {
82
+ cancel: (/** @type {{ code: number; }} */ reason) => {
57
83
  /** @type {Promise<void>} */
58
84
  const promise = new Promise((resolve, reject) => {
59
85
  this.cancelres = resolve
@@ -67,17 +93,27 @@ export class Http3WTStream {
67
93
  this.readableclosed = true
68
94
  this.objint.stopSending(code)
69
95
  return promise
70
- }
71
- },
72
- { highWaterMark: 4 }
96
+ },
97
+ type: 'bytes',
98
+ autoAllocateChunkSize: 4096 // lets take this as buffer size
99
+ }
100
+ // TODO fix stretegy
73
101
  )
102
+ this.readable.getStats = () => {
103
+ return Promise.resolve({
104
+ timestamp: 0,
105
+ bytesReceived: 0n,
106
+ bytesResd: 0n
107
+ })
108
+ }
74
109
  }
75
110
  if (this.bidirectional || !this.incoming) {
111
+ // @ts-expect-error `getStats` property is missing from WritableStream
112
+ /** @type {WebTransportSendStream} */
76
113
  this.writable = new WritableStream(
77
114
  {
78
115
  start: (controller) => {
79
116
  this.writableController = controller
80
- // @ts-expect-error this.writable could be undefined
81
117
  this.parentobj.addSendStream(this.writable, controller)
82
118
  },
83
119
  write: (chunk, controller) => {
@@ -130,6 +166,14 @@ export class Http3WTStream {
130
166
  },
131
167
  { highWaterMark: 4 }
132
168
  )
169
+ this.writable.getStats = () => {
170
+ return Promise.resolve({
171
+ timestamp: 0,
172
+ bytesWritten: 0n,
173
+ bytesSent: 0n,
174
+ bytesAcknowledged: 0n
175
+ })
176
+ }
133
177
  }
134
178
 
135
179
  /** @type {(() => void) | null} */
@@ -140,6 +184,62 @@ export class Http3WTStream {
140
184
  this.abortres = null
141
185
  }
142
186
 
187
+ drainBuffer() {
188
+ const byob = this.readableController.byobRequest
189
+ // @ts-ignore
190
+ const view = byob?.view
191
+ // @ts-ignore
192
+ if (!(byob?.view instanceof Uint8Array))
193
+ throw new Error('byob view is not a Uint8Array')
194
+ let toread = Math.min(view.byteLength, this.incomingbufferfilled)
195
+ let read = 0
196
+ if (!this.objint.readbuffer)
197
+ throw new Error('No readbuffer in read for read stream')
198
+ if (
199
+ this.incomingbufferreadpos + toread >
200
+ this.objint.readbuffer.byteLength
201
+ ) {
202
+ /** @type {Number} */
203
+ const firstread =
204
+ this.objint.readbuffer.byteLength - this.incomingbufferreadpos
205
+ read += firstread
206
+ toread -= firstread
207
+ const destview = new Uint8Array(
208
+ view.buffer,
209
+ 0 + view.byteOffset,
210
+ firstread
211
+ )
212
+ const srcview = new Uint8Array(
213
+ this.objint.readbuffer,
214
+ this.incomingbufferreadpos,
215
+ firstread
216
+ )
217
+ destview.set(srcview)
218
+ this.incomingbufferreadpos = 0
219
+ }
220
+ {
221
+ const destview = new Uint8Array(
222
+ view.buffer,
223
+ read + view.byteOffset,
224
+ toread
225
+ )
226
+ const srcview = new Uint8Array(
227
+ this.objint.readbuffer,
228
+ this.incomingbufferreadpos,
229
+ toread
230
+ )
231
+ destview.set(srcview)
232
+ read += toread
233
+ this.incomingbufferreadpos =
234
+ (this.incomingbufferreadpos + toread) %
235
+ this.objint.readbuffer.byteLength
236
+ }
237
+ // @ts-ignore
238
+ byob.respond(read)
239
+ this.incomingbufferfilled -= read
240
+ this.objint.updateReadPos(read, this.incomingbufferreadpos)
241
+ }
242
+
143
243
  /**
144
244
  * @param {import('./types').StreamRecvSignalEvent} args
145
245
  * @returns {void}
@@ -190,6 +290,14 @@ export class Http3WTStream {
190
290
  res()
191
291
  }
192
292
  }
293
+ if (this.pendingoperationRead) {
294
+ const res = this.pendingresRead
295
+ this.pendingoperationRead = null
296
+ this.pendingresRead = null
297
+ if (res != null) {
298
+ res()
299
+ }
300
+ }
193
301
  }
194
302
 
195
303
  /**
@@ -197,9 +305,16 @@ export class Http3WTStream {
197
305
  * @returns {void}
198
306
  */
199
307
  onStreamRead(args) {
200
- if (args.data && args.data.length && !this.readableclosed) {
308
+ if (args.buffergrow && !this.readableclosed) {
309
+ this.incomingbufferfilled += args.buffergrow
201
310
  // console.log('stream read received', args.data, Date.now())
202
- this.readableController.enqueue(args.data)
311
+ if (this.pendingoperationRead) {
312
+ // this.readableController.enqueue(data)
313
+ const res = this.pendingresRead
314
+ this.pendingoperationRead = null
315
+ this.pendingresRead = null
316
+ if (res) res()
317
+ }
203
318
  if (
204
319
  this.readableController.desiredSize != null &&
205
320
  this.readableController.desiredSize < 0
@@ -207,6 +322,13 @@ export class Http3WTStream {
207
322
  this.objint.stopReading()
208
323
  }
209
324
  if (args.fin) {
325
+ if (this.incomingbufferfilled > 0) {
326
+ console.log('Warning buffer filled and we got a fin')
327
+ if (this.pendingoperationRead || this.pendingresRead)
328
+ throw new Error('We have pendingoperationRead and a filled buffer?')
329
+
330
+ this.drainBuffer()
331
+ }
210
332
  if (this.cancelres) {
211
333
  const res = this.cancelres
212
334
  this.cancelres = null
@@ -305,7 +427,10 @@ export class Http3WTStream {
305
427
  visitor.onStreamRecvSignal(args)
306
428
  break
307
429
  case 'StreamRead':
308
- if (visitor && Object.prototype.hasOwnProperty.call(args, 'data')) {
430
+ if (
431
+ visitor &&
432
+ Object.prototype.hasOwnProperty.call(args, 'buffergrow')
433
+ ) {
309
434
  visitor.onStreamRead(args)
310
435
  } else {
311
436
  console.log('Stream callback called', visitor, args)
package/lib/transport.js CHANGED
@@ -7,7 +7,9 @@ export class Http3WebTransport {
7
7
  * @param {'server' | 'client'} purpose
8
8
  */
9
9
  constructor(args, purpose) {
10
- const eventloop = Http3EventLoop.getGlobalEventLoop(this).eventloopInt
10
+ const eventloop = Http3EventLoop.getGlobalEventLoop(this, {
11
+ quicheLogVerbose: args.quicheLogVerbose
12
+ }).eventloopInt
11
13
 
12
14
  if (purpose === 'server')
13
15
  this.transportInt = new wtrouter.Http3WebTransportServer(args, eventloop)
package/lib/types.ts CHANGED
@@ -8,6 +8,8 @@ import type { WebTransport } from './dom'
8
8
  writeDatagram: (chunk: Uint8Array) => void
9
9
  orderUnidiStream: () => void
10
10
  orderBidiStream: () => void
11
+ // orderStats: () => void
12
+ notifySessionDraining(): () => void
11
13
  close: (arg: { code: number, reason: string }) => void
12
14
  }
13
15
 
@@ -15,7 +17,9 @@ import type { WebTransport } from './dom'
15
17
  * Native Http3WTStream counterpart
16
18
  */
17
19
  export interface NativeHttp3WTStream {
20
+ updateReadPos(bytesread: Number, pos: Number): unknown
18
21
  jsobj: WebTransportStreamEventHandler
22
+ readbuffer: Uint8Array | undefined
19
23
  startReading: () => void
20
24
  stopReading: () => void
21
25
  stopSending: (code: number) => void
@@ -37,8 +41,9 @@ export interface StreamRecvSignalEvent {
37
41
  export interface StreamReadEvent {
38
42
  object: NativeHttp3WTStream
39
43
  purpose: 'StreamRead'
40
- data?: Uint8Array
44
+ buffergrow?: number
41
45
  fin?: boolean
46
+ success?: boolean
42
47
  }
43
48
 
44
49
  export interface StreamWriteEvent {
@@ -88,6 +93,11 @@ export interface DatagramSendEvent {
88
93
  purpose: 'DatagramSend'
89
94
  }
90
95
 
96
+ export interface GoawayReceivedEvent {
97
+ object: NativeHttp3WTSession
98
+ purpose: 'GoawayReceived'
99
+ }
100
+
91
101
  export interface NewStreamEvent {
92
102
  object: NativeHttp3WTSession
93
103
  purpose: 'Http3WTStreamVisitor'
@@ -102,6 +112,7 @@ export interface WebTransportSessionEventHandler {
102
112
  onClose: (evt: SessionCloseEvent) => void
103
113
  onDatagramReceived: (evt: DatagramReceivedEvent) => void
104
114
  onDatagramSend: (evt: DatagramSendEvent) => void
115
+ onGoAwayReceived: (evt: GoawayReceivedEvent) => void
105
116
  onStream: (evt: NewStreamEvent) => void
106
117
  closeHook?: (() => void) | null
107
118
  }
@@ -174,7 +185,7 @@ export interface Deferred<T = unknown> {
174
185
  reject: (reason?: any) => void
175
186
  }
176
187
 
177
- export type WebTransportSessionState = 'connected' | 'closed' | 'failed'
188
+ export type WebTransportSessionState = 'connected' | 'draining' | 'closed' | 'failed'
178
189
 
179
190
  export interface WebTransportSession extends WebTransport {
180
191
  state: WebTransportSessionState
@@ -42,6 +42,7 @@ export class WebTransport {
42
42
 
43
43
  this.ready = sessionint.ready
44
44
  this.closed = sessionint.closed
45
+ this.draining = sessionint.draining
45
46
 
46
47
  this.datagrams = sessionint.datagrams
47
48
 
@@ -76,6 +77,36 @@ export class WebTransport {
76
77
  })
77
78
  }
78
79
 
80
+ get reliability() {
81
+ const session = sessions.get(this)
82
+
83
+ if (session == null) {
84
+ // should never happen as session is only removed when this instance is garbage collected
85
+ throw new Error('Http3WTSession was undefined')
86
+ }
87
+ return session.reliability
88
+ }
89
+
90
+ get congestionControl() {
91
+ const session = sessions.get(this)
92
+
93
+ if (session == null) {
94
+ // should never happen as session is only removed when this instance is garbage collected
95
+ throw new Error('Http3WTSession was undefined')
96
+ }
97
+ return session.congestionControl
98
+ }
99
+
100
+ getStats() {
101
+ const session = sessions.get(this)
102
+
103
+ if (session == null) {
104
+ // should never happen as session is only removed when this instance is garbage collected
105
+ throw new Error('Http3WTSession was undefined')
106
+ }
107
+ return session.getStats()
108
+ }
109
+
79
110
  /**
80
111
  * @param {WebTransportCloseInfo} [closeinfo]
81
112
  */
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@fails-components/webtransport",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "A component to add webtransport support (server and client) to node.js using libquiche",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.js",
7
7
  "engines": {
8
- "node": ">=16"
8
+ "node": ">=16.5"
9
9
  },
10
10
  "type": "module",
11
11
  "types": "./dist/lib/index.d.ts",
@@ -45,7 +45,7 @@
45
45
  "@types/chai": "^4.3.3",
46
46
  "@types/dirty-chai": "^2.0.2",
47
47
  "@types/mocha": "^10.0.0",
48
- "@types/node": "^18.11.5",
48
+ "@types/node": "^18.15.3",
49
49
  "chai": "^4.3.6",
50
50
  "cmake-js": "^6.3.2",
51
51
  "dirty-chai": "^2.0.1",
@@ -60,7 +60,8 @@
60
60
  "mocha": "^10.1.0",
61
61
  "node-forge": "^1.3.1",
62
62
  "prettier": "^2.4.1",
63
- "typescript": "4.8.4"
63
+ "typescript": "4.8.4",
64
+ "uint8arrays": "^4.0.2"
64
65
  },
65
66
  "binary": {
66
67
  "napi_versions": [
@@ -0,0 +1,5 @@
1
+ // adds string to the includes of google url
2
+ #include <string>
3
+ #warning "Fake utf_stream_operators.h included"
4
+
5
+ #include "third_party/googleurl/base/strings/utf_ostream_operators.h"
@@ -0,0 +1,3 @@
1
+ #include "absl/strings/ascii.h"
2
+ #warning "Fake socketwin included"
3
+ #include "third_party/quiche/quiche/quic/core/io/socket_win.inc"
@@ -0,0 +1,7 @@
1
+ // use default impl
2
+ #ifndef QUICHE_COMMAND_LINE_FLAGS_IMPL
3
+ #define QUICHE_COMMAND_LINE_FLAGS_IMPL
4
+
5
+ #include "third_party/quiche/quiche/common/platform/default/quiche_platform_impl/quiche_command_line_flags_impl.h"
6
+
7
+ #endif
@@ -1,12 +1,6 @@
1
- #ifndef QUICHE_EXPORT_IMPL
2
- #define QUICHE_EXPORT_IMPL
1
+ #ifndef QUICHE_EXPORT_IMPL_HEADER
2
+ #define QUICHE_EXPORT_IMPL_HEADER
3
3
 
4
- // dirty hack to fix absl include error
5
-
6
- #include "absl/types/optional.h"
7
-
8
- #define QUICHE_EXPORT_IMPL
9
- #define QUICHE_EXPORT_PRIVATE_IMPL
10
- #define QUICHE_NO_EXPORT_IMPL
4
+ #include "third_party/quiche/quiche/common/platform/default/quiche_platform_impl/quiche_export_impl.h"
11
5
 
12
6
  #endif
@@ -2,27 +2,6 @@
2
2
  #ifndef QUICHE_SERVER_STATS_IMPL
3
3
  #define QUICHE_SERVER_STATS_IMPL
4
4
 
5
-
6
- // NOLINT(namespace-envoy)
7
- //
8
- // This file is part of the QUICHE platform implementation, and is not to be
9
- // consumed or referenced directly by other Envoy code. It serves purely as a
10
- // porting layer for QUICHE.
11
-
12
- #define QUICHE_SERVER_HISTOGRAM_ENUM_IMPL(name, sample, enum_size, docstring) \
13
- do { \
14
- } while (0)
15
-
16
- #define QUICHE_SERVER_HISTOGRAM_BOOL_IMPL(name, sample, docstring) \
17
- do { \
18
- } while (0)
19
-
20
- #define QUICHE_SERVER_HISTOGRAM_TIMES_IMPL(name, sample, min, max, bucket_count, docstring) \
21
- do { \
22
- } while (0)
23
-
24
- #define QUICHE_SERVER_HISTOGRAM_COUNTS_IMPL(name, sample, min, max, bucket_count, docstring) \
25
- do { \
26
- } while (0)
5
+ #include "third_party/quiche/quiche/common/platform/default/quiche_platform_impl/quiche_server_stats_impl.h"
27
6
 
28
7
  #endif
@@ -4,8 +4,5 @@
4
4
  // found in the LICENSE file.
5
5
  #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_STREAM_BUFFER_ALLOCATOR_IMPL_H_
6
6
  #define NET_QUIC_PLATFORM_IMPL_QUIC_STREAM_BUFFER_ALLOCATOR_IMPL_H_
7
- #include "quiche/common/simple_buffer_allocator.h"
8
- namespace quiche {
9
- using QuicheStreamBufferAllocatorImpl = quiche::SimpleBufferAllocator;
10
- } // namespace quic
7
+ #include "third_party/quiche/quiche/common/platform/default/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h"
11
8
  #endif // NET_QUIC_PLATFORM_IMPL_QUIC_STREAM_BUFFER_ALLOCATOR_IMPL_H_
@@ -8,18 +8,6 @@
8
8
  #ifndef QUICHE_TIME_UTILS_IMPL
9
9
  #define QUICHE_TIME_UTILS_IMPL
10
10
 
11
- #include <cstdint>
12
-
13
- #include "absl/time/civil_time.h"
14
- #include "absl/time/time.h"
15
- #include "absl/types/optional.h"
16
-
17
- namespace quiche {
18
-
19
- // NOLINTNEXTLINE(readability-identifier-naming)
20
- absl::optional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour,
21
- int minute, int second);
22
-
23
- } // namespace quiche
11
+ #include "third_party/quiche/quiche/common/platform/default/quiche_platform_impl/quiche_time_utils_impl.h"
24
12
 
25
13
  #endif
@@ -25,6 +25,15 @@ inline bool GetGooglePacketHeadersFromControlMessageImpl(
25
25
 
26
26
  inline void SetGoogleSocketOptionsImpl(int fd) {}
27
27
 
28
+ inline int GetEcnCmsgArgsPreserveDscpImpl(const int /*fd*/,
29
+ const int /*address_family*/,
30
+ uint8_t /*ecn_codepoint*/,
31
+ int& /*type*/, void* /*value*/,
32
+ socklen_t& /*value_len*/) {
33
+ // TODO(b/273081493): implement this.
34
+ return 0;
35
+ }
36
+
28
37
  } // namespace quic
29
38
 
30
39
  #endif // NET_QUIC_PLATFORM_IMPL_QUIC_UDP_SOCKET_PLATFORM_IMPL_H_
package/readme.md CHANGED
@@ -59,7 +59,7 @@ When testing remember you might need to start chromium based browser with certai
59
59
  ```
60
60
  chrome --ignore-certificate-errors-spki-list=FINGERPRINTOFYOURCERTIFICATE --ignore-certificate-errors --v=2 --enable-logging=stderr --origin-to-force-quic-on=192.168.1.50:8080
61
61
  ```
62
- of course replace IP and fingerprint of your certificate accordingly.
62
+ of course replace IP and fingerprint of your certificate accordingly. However, the author never got this to work and is using this without flags, but supplies instead a fingerprint when opening a WebTransport session. (PR welcome).
63
63
 
64
64
  ## Specification divergence
65
65
 
@@ -76,6 +76,8 @@ They are:
76
76
  * [getStats()](https://www.w3.org/TR/webtransport/#dom-webtransport-getstats)
77
77
  * [reliability](https://www.w3.org/TR/webtransport/#dom-webtransport-reliability)
78
78
 
79
+ The WebTransport client only supports certification validation using fingerprints. Without a fingerprint it will accept any server without certificate checking.
80
+
79
81
  ### WebTransportDatagramDuplexStream
80
82
 
81
83
  * [maxDatagramSize](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-maxdatagramsize)
@@ -63,10 +63,11 @@ namespace quic
63
63
  WriteResult WritePacket(const char *buffer, size_t buf_len,
64
64
  const QuicIpAddress &self_address,
65
65
  const QuicSocketAddress &peer_address,
66
- PerPacketOptions *options) override
66
+ PerPacketOptions *options,
67
+ const quic::QuicPacketWriterParams& wparams) override
67
68
  {
68
69
  WriteResult result = QuicDefaultPacketWriter::WritePacket(
69
- buffer, buf_len, self_address, peer_address, options);
70
+ buffer, buf_len, self_address, peer_address, options, wparams);
70
71
  if (IsWriteBlockedStatus(result.status))
71
72
  {
72
73
  bool success = event_loop_->RearmSocket(fd(), kSocketEventWritable);
@@ -148,7 +149,8 @@ namespace quic
148
149
  connection_in_progress_(false),
149
150
  num_attempts_connect_(0),
150
151
  webtransport_server_support_inform_(false),
151
- connection_debug_visitor_(nullptr)
152
+ connection_debug_visitor_(nullptr),
153
+ priority_(HttpStreamPriority())
152
154
  {
153
155
  set_server_address(server_address);
154
156
  Initialize();
@@ -183,7 +185,7 @@ namespace quic
183
185
 
184
186
  void Http3Client::Initialize()
185
187
  {
186
- priority_ = QuicStreamPriority();
188
+ priority_ = QuicStreamPriority(HttpStreamPriority());
187
189
  connect_attempted_ = false;
188
190
  auto_reconnect_ = false;
189
191
  buffer_body_ = true;
@@ -891,7 +893,6 @@ namespace quic
891
893
  response_ = "";
892
894
  response_complete_ = false;
893
895
  response_headers_complete_ = false;
894
- preliminary_headers_.clear();
895
896
  response_headers_.clear();
896
897
  response_trailers_.clear();
897
898
  bytes_read_ = 0;
@@ -990,21 +991,6 @@ namespace quic
990
991
  return &response_headers_;
991
992
  }
992
993
 
993
- const spdy::Http2HeaderBlock *Http3Client::preliminary_headers() const
994
- {
995
- for (std::pair<QuicStreamId, QuicSpdyClientStream *> stream : open_streams_)
996
- {
997
- size_t bytes_read =
998
- stream.second->stream_bytes_read() + stream.second->header_bytes_read();
999
- if (bytes_read > 0)
1000
- {
1001
- preliminary_headers_ = stream.second->preliminary_headers().Clone();
1002
- break;
1003
- }
1004
- }
1005
- return &preliminary_headers_;
1006
- }
1007
-
1008
994
  const spdy::Http2HeaderBlock &Http3Client::response_trailers() const
1009
995
  {
1010
996
  return response_trailers_;
@@ -1042,7 +1028,7 @@ namespace quic
1042
1028
 
1043
1029
  void Http3Client::OnCompleteResponse(
1044
1030
  QuicStreamId id, const spdy::Http2HeaderBlock &response_headers,
1045
- const std::string &response_body)
1031
+ const absl::string_view &response_body)
1046
1032
  {
1047
1033
  // implement
1048
1034
  }
@@ -1076,8 +1062,11 @@ namespace quic
1076
1062
  QUIC_LOG(ERROR) << "Invalid :status response header: " << status->second;
1077
1063
  }
1078
1064
  latest_response_headers_ = response_headers.DebugString();
1079
- preliminary_response_headers_ =
1080
- client_stream->preliminary_headers().DebugString();
1065
+ for (const Http2HeaderBlock &headers :
1066
+ client_stream->preliminary_headers())
1067
+ {
1068
+ absl::StrAppend(&preliminary_response_headers_, headers.DebugString());
1069
+ }
1081
1070
  latest_response_header_block_ = response_headers.Clone();
1082
1071
  latest_response_body_ = client_stream->data();
1083
1072
  latest_response_trailers_ =
@@ -1101,7 +1090,6 @@ namespace quic
1101
1090
  client_stream->stream_error(), connected(),
1102
1091
  client_stream->headers_decompressed(),
1103
1092
  client_stream->response_headers(),
1104
- client_stream->preliminary_headers(),
1105
1093
  (buffer_body() ? client_stream->data() : ""),
1106
1094
  client_stream->received_trailers(),
1107
1095
  // Use NumBytesConsumed to avoid counting retransmitted stream frames.
@@ -1226,7 +1214,6 @@ namespace quic
1226
1214
  response_complete(other.response_complete),
1227
1215
  response_headers_complete(other.response_headers_complete),
1228
1216
  response_headers(other.response_headers.Clone()),
1229
- preliminary_headers(other.preliminary_headers.Clone()),
1230
1217
  response(other.response),
1231
1218
  response_trailers(other.response_trailers.Clone()),
1232
1219
  bytes_read(other.bytes_read),
@@ -1237,14 +1224,12 @@ namespace quic
1237
1224
  QuicRstStreamErrorCode stream_error, bool response_complete,
1238
1225
  bool response_headers_complete,
1239
1226
  const spdy::Http2HeaderBlock &response_headers,
1240
- const spdy::Http2HeaderBlock &preliminary_headers,
1241
- const std::string &response, const spdy::Http2HeaderBlock &response_trailers,
1227
+ const absl::string_view response, const spdy::Http2HeaderBlock &response_trailers,
1242
1228
  uint64_t bytes_read, uint64_t bytes_written, int64_t response_body_size)
1243
1229
  : stream_error(stream_error),
1244
1230
  response_complete(response_complete),
1245
1231
  response_headers_complete(response_headers_complete),
1246
1232
  response_headers(response_headers.Clone()),
1247
- preliminary_headers(preliminary_headers.Clone()),
1248
1233
  response(response),
1249
1234
  response_trailers(response_trailers.Clone()),
1250
1235
  bytes_read(bytes_read),
@@ -1286,7 +1271,6 @@ namespace quic
1286
1271
  response_ = state.response;
1287
1272
  response_complete_ = state.response_complete;
1288
1273
  response_headers_complete_ = state.response_headers_complete;
1289
- preliminary_headers_ = state.preliminary_headers.Clone();
1290
1274
  response_headers_ = state.response_headers.Clone();
1291
1275
  response_trailers_ = state.response_trailers.Clone();
1292
1276
  bytes_read_ = state.bytes_read;
package/src/http3client.h CHANGED
@@ -180,7 +180,6 @@ namespace quic
180
180
  // Group 2.
181
181
  bool response_headers_complete() const;
182
182
  const spdy::Http2HeaderBlock *response_headers() const;
183
- const spdy::Http2HeaderBlock *preliminary_headers() const;
184
183
  int64_t response_size() const;
185
184
  size_t bytes_read() const;
186
185
  size_t bytes_written() const;
@@ -218,7 +217,7 @@ namespace quic
218
217
  // QuicSpdyClientBase::Reponselistener
219
218
  void OnCompleteResponse(
220
219
  QuicStreamId id, const spdy::Http2HeaderBlock &response_headers,
221
- const std::string &response_body);
220
+ const absl::string_view &response_body);
222
221
 
223
222
  // From QuicClientPushPromiseIndex::Delegate
224
223
  bool CheckVary(const spdy::Http2HeaderBlock &client_request,
@@ -321,8 +320,7 @@ namespace quic
321
320
  PerStreamState(QuicRstStreamErrorCode stream_error, bool response_complete,
322
321
  bool response_headers_complete,
323
322
  const spdy::Http2HeaderBlock &response_headers,
324
- const spdy::Http2HeaderBlock &preliminary_headers,
325
- const std::string &response,
323
+ const absl::string_view response,
326
324
  const spdy::Http2HeaderBlock &response_trailers,
327
325
  uint64_t bytes_read, uint64_t bytes_written,
328
326
  int64_t response_body_size);
@@ -332,7 +330,6 @@ namespace quic
332
330
  bool response_complete;
333
331
  bool response_headers_complete;
334
332
  spdy::Http2HeaderBlock response_headers;
335
- spdy::Http2HeaderBlock preliminary_headers;
336
333
  std::string response;
337
334
  spdy::Http2HeaderBlock response_trailers;
338
335
  uint64_t bytes_read;
@@ -398,7 +395,6 @@ namespace quic
398
395
 
399
396
  bool response_complete_;
400
397
  bool response_headers_complete_;
401
- mutable spdy::Http2HeaderBlock preliminary_headers_;
402
398
  mutable spdy::Http2HeaderBlock response_headers_;
403
399
 
404
400
  // Parsed response trailers (if present), copied from the stream in OnClose.