@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.
- package/CMakeLists.txt +42 -111
- package/build.js +4 -4
- package/dist/lib/dom.d.ts +6 -0
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/event-loop.d.ts +8 -3
- package/dist/lib/event-loop.d.ts.map +1 -1
- package/dist/lib/server.d.ts +3 -2
- package/dist/lib/server.d.ts.map +1 -1
- package/dist/lib/session.d.ts +78 -18
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/stream.d.ts +13 -5
- package/dist/lib/stream.d.ts.map +1 -1
- package/dist/lib/transport.d.ts.map +1 -1
- package/dist/lib/types.d.ts +11 -2
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/webtransport.d.ts +22 -0
- package/dist/lib/webtransport.d.ts.map +1 -1
- package/dist/test/bidirectional-streams.spec.d.ts.map +1 -1
- package/dist/test/datagrams.spec.d.ts.map +1 -1
- package/dist/test/fixtures/p-timeout.d.ts +8 -0
- package/dist/test/fixtures/p-timeout.d.ts.map +1 -0
- package/dist/test/fixtures/read-stream.d.ts.map +1 -1
- package/dist/test/unidirectional-streams.spec.d.ts.map +1 -1
- package/lib/dom.ts +7 -2
- package/lib/event-loop.js +13 -7
- package/lib/server.js +1 -1
- package/lib/session.js +71 -21
- package/lib/stream.js +137 -12
- package/lib/transport.js +3 -1
- package/lib/types.ts +13 -2
- package/lib/webtransport.js +31 -0
- package/package.json +5 -4
- package/platform/base/strings/utf_ostream_operators.h +5 -0
- package/platform/quiche/quic/core/io/socket_win.inc +3 -0
- package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_export_impl.h +3 -9
- package/platform/quiche_platform_impl/quiche_server_stats_impl.h +1 -22
- package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +1 -4
- package/platform/quiche_platform_impl/quiche_time_utils_impl.h +1 -13
- package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +9 -0
- package/readme.md +3 -1
- package/src/http3client.cc +13 -29
- package/src/http3client.h +2 -6
- package/src/http3clientsession.cc +51 -40
- package/src/http3clientsession.h +44 -31
- package/src/http3clientstream.cc +17 -0
- package/src/http3clientstream.h +10 -0
- package/src/http3eventloop.cc +81 -61
- package/src/http3eventloop.h +10 -7
- package/src/http3server.cc +1 -1
- package/src/http3serversession.cc +1 -136
- package/src/http3serversession.h +7 -77
- package/src/http3serverstream.cc +0 -49
- package/src/http3serverstream.h +0 -5
- package/src/http3wtsessionvisitor.cc +1 -1
- package/src/http3wtsessionvisitor.h +24 -37
- package/src/http3wtstreamvisitor.cc +35 -8
- package/src/http3wtstreamvisitor.h +81 -3
- package/test/bidirectional-streams.spec.js +16 -7
- package/test/datagrams.spec.js +31 -20
- package/test/fixtures/p-timeout.js +33 -0
- package/test/fixtures/read-stream.js +4 -1
- package/test/unidirectional-streams.spec.js +24 -15
- package/platform/net/quiche/common/platform/impl/quiche_flags_impl.h +0 -12
- package/platform/poll.h +0 -2
- package/platform/quiche/quic/core/io/quic_poll_event_loop.h +0 -8
- package/platform/quiche_platform_impl/quic_testvalue_impl.h +0 -19
- package/platform/quiche_platform_impl/quic_udp_socket_winsock.cc +0 -732
- package/platform/quiche_platform_impl/quiche_time_utils_impl.cc +0 -43
- 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: (
|
|
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: (
|
|
63
|
+
pull: async (
|
|
64
|
+
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
65
|
+
) => {
|
|
51
66
|
if (this.readableclosed) {
|
|
52
67
|
return Promise.resolve()
|
|
53
68
|
}
|
|
54
|
-
|
|
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
|
-
|
|
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.
|
|
308
|
+
if (args.buffergrow && !this.readableclosed) {
|
|
309
|
+
this.incomingbufferfilled += args.buffergrow
|
|
201
310
|
// console.log('stream read received', args.data, Date.now())
|
|
202
|
-
this.
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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
|
package/lib/webtransport.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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": [
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
#ifndef
|
|
2
|
-
#define
|
|
1
|
+
#ifndef QUICHE_EXPORT_IMPL_HEADER
|
|
2
|
+
#define QUICHE_EXPORT_IMPL_HEADER
|
|
3
3
|
|
|
4
|
-
|
|
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/
|
|
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
|
|
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)
|
package/src/http3client.cc
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
1080
|
-
|
|
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 &
|
|
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
|
|
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
|
|
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.
|