22
33const {
44 BigInt,
5- FunctionPrototypeBind,
65 NumberIsInteger,
7- SymbolAsyncDispose ,
6+ PromiseReject ,
87} = primordials ;
98
109const {
@@ -17,29 +16,25 @@ if (!process.features.quic || !getOptionValue('--experimental-quic')) {
1716
1817// Internal, experimental HTTP/3 layer over node:quic.
1918//
20- // A QuicSession created without an application is a raw QUIC session.
21- // Attaching an Http3Session makes it an HTTP/3 one, and from then on its
22- // streams are HTTP/3 request streams.
19+ // An Http3Session is started on a QuicConnection that has no session yet,
20+ // and from then on the connection's streams are HTTP/3 request streams.
2321
2422const {
23+ QuicSessionBase,
2524 createApplicationStream,
26- getQuicSessionHandle,
27- getQuicSessionState,
28- isQuicSession,
25+ getApplicationCallback,
26+ isServerConnection,
2927 setApplicationCallback,
3028} = require ( 'internal/quic/quic' ) ;
3129
3230const {
33- kInspect,
3431 kPrivateConstructor,
3532} = require ( 'internal/quic/symbols' ) ;
3633const { kEmptyObject } = require ( 'internal/util' ) ;
37- const { inspect } = require ( 'internal/util/inspect' ) ;
3834
3935const {
4036 QUIC_APPLICATION_HTTP3 ,
4137 STREAM_DIRECTION_BIDIRECTIONAL : kStreamDirectionBidirectional ,
42- kHttp3Settings,
4338} = internalBinding ( 'quic' ) ;
4439
4540const {
@@ -50,7 +45,6 @@ const {
5045
5146const {
5247 codes : {
53- ERR_ILLEGAL_CONSTRUCTOR ,
5448 ERR_INVALID_ARG_TYPE ,
5549 ERR_INVALID_STATE ,
5650 ERR_OUT_OF_RANGE ,
@@ -117,196 +111,75 @@ function prepareH3Settings(settings) {
117111 } ;
118112}
119113
120- function checkAttachable ( session , state ) {
121- if ( session . destroyed ) {
122- throw new ERR_INVALID_STATE (
123- 'An application cannot be attached to a destroyed QUIC session' ) ;
124- }
125- if ( state . applicationType !== 0 ) {
126- throw new ERR_INVALID_STATE (
127- 'The QUIC session already has an application attached' ) ;
128- }
129- }
130-
131- class Http3Session {
132- #session;
133- #onstream;
134- #ongoaway;
135- #onorigin;
136- #onsettings;
137- #onerror;
138-
114+ class Http3Session extends QuicSessionBase {
139115 /**
140- * Attaches HTTP/3 to a QuicSession that has not yet become active .
141- * @param {QuicSession } session the QUIC session to attach to
116+ * Starts HTTP/3 on a QuicConnection that has no session yet .
117+ * @param {QuicConnection } connection
142118 * @param {object } [options]
143119 * @param {ApplicationOptions } [options.settings]
144120 * @param {Function } [options.ongoaway]
145121 * @param {Function } [options.onorigin]
146122 * @param {Function } [options.onsettings]
147123 * @returns {Http3Session }
148124 */
149- static from ( session , options ) {
150- return new Http3Session ( kPrivateConstructor , session , options ) ;
125+ static start ( connection , options ) {
126+ return new Http3Session ( kPrivateConstructor , connection , options ) ;
151127 }
152128
153- constructor ( privateSymbol , session , options = kEmptyObject ) {
154- if ( privateSymbol !== kPrivateConstructor ) {
155- throw new ERR_ILLEGAL_CONSTRUCTOR ( ) ;
156- }
157- if ( ! isQuicSession ( session ) ) {
158- throw new ERR_INVALID_ARG_TYPE ( 'session' , 'QuicSession' , session ) ;
159- }
129+ constructor ( privateSymbol , connection , options = kEmptyObject ) {
160130 validateObject ( options , 'options' ) ;
161131 const { ongoaway, onorigin, onsettings, settings } = options ;
162132 if ( ongoaway !== undefined ) validateFunction ( ongoaway , 'options.ongoaway' ) ;
163133 if ( onorigin !== undefined ) validateFunction ( onorigin , 'options.onorigin' ) ;
164134 if ( onsettings !== undefined ) {
165135 validateFunction ( onsettings , 'options.onsettings' ) ;
166136 }
167- const state = getQuicSessionState ( session ) ;
168-
169137 let preparedSettings ;
170138 if ( settings !== undefined ) {
171139 validateObject ( settings , 'options.settings' ) ;
172140 preparedSettings = prepareH3Settings ( settings ) ;
173141 }
174142
175- // Reading settings could call getters and go into JS, so do this after:
176- checkAttachable ( session , state ) ;
143+ // Reading settings could call getters and go into JS, so start after:
144+ super ( privateSymbol , connection , QUIC_APPLICATION_HTTP3 , preparedSettings ) ;
177145
178- const handle = getQuicSessionHandle ( session ) ;
179- if ( preparedSettings !== undefined ) handle [ kHttp3Settings ] = preparedSettings ;
180- state . applicationType = QUIC_APPLICATION_HTTP3 ;
181- this . #session = session ;
182- if ( ongoaway !== undefined ) {
183- this . #ongoaway = ongoaway ;
184- setApplicationCallback ( session , 'ongoaway' , this . #bind( ongoaway ) ) ;
185- }
186- if ( onorigin !== undefined ) {
187- this . #onorigin = onorigin ;
188- setApplicationCallback ( session , 'onorigin' , this . #bind( onorigin ) ) ;
189- }
190- if ( onsettings !== undefined ) {
191- this . #onsettings = onsettings ;
192- setApplicationCallback ( session , 'onapplication' , this . #bind( onsettings ) ) ;
193- }
146+ if ( ongoaway !== undefined ) this . ongoaway = ongoaway ;
147+ if ( onorigin !== undefined ) this . onorigin = onorigin ;
148+ if ( onsettings !== undefined ) this . onsettings = onsettings ;
194149 }
195150
196- /**
197- * The QUIC session carrying this HTTP/3 session
198- * @type {QuicSession }
199- */
200- get quicSession ( ) { return this . #session; }
201-
202151 /**
203152 * The settings in effect, including any update from the peer's SETTINGS
204153 * frame, which may arrive after the session opens. Null once destroyed.
205154 * @type {ApplicationOptions|null }
206155 */
207- get settings ( ) { return this . #session. applicationOptions ; }
208-
209- /** @type {quic.QuicSession.Stats } */
210- get stats ( ) { return this . #session. stats ; }
211-
212- // Ensure that 'this' in callbacks registered here is the Http3Session
213- #bind( fn ) {
214- return fn === undefined ? undefined : FunctionPrototypeBind ( fn , this ) ;
215- }
216-
217- /**
218- * Called with each request stream the client opens. HTTP/3 has no
219- * server-initiated requests, so this never fires on a client session.
220- * @type {Function|undefined }
221- */
222- get onstream ( ) { return this . #onstream; }
223- set onstream ( fn ) {
224- if ( fn !== undefined ) validateFunction ( fn , 'onstream' ) ;
225- setApplicationCallback ( this . #session, 'onstream' , this . #bind( fn ) ) ;
226- this . #onstream = fn ;
227- }
156+ get settings ( ) { return this . connection . applicationOptions ; }
228157
229158 /** @type {Function|undefined } */
230- get ongoaway ( ) { return this . #ongoaway; }
231- set ongoaway ( fn ) {
232- if ( fn !== undefined ) validateFunction ( fn , 'ongoaway' ) ;
233- setApplicationCallback ( this . #session, 'ongoaway' , this . #bind( fn ) ) ;
234- this . #ongoaway = fn ;
235- }
159+ get ongoaway ( ) { return getApplicationCallback ( this . connection , 'ongoaway' ) ; }
160+ set ongoaway ( fn ) { setApplicationCallback ( this . connection , 'ongoaway' , fn , this ) ; }
236161
237162 /** @type {Function|undefined } */
238- get onorigin ( ) { return this . #onorigin; }
239- set onorigin ( fn ) {
240- if ( fn !== undefined ) validateFunction ( fn , 'onorigin' ) ;
241- setApplicationCallback ( this . #session, 'onorigin' , this . #bind( fn ) ) ;
242- this . #onorigin = fn ;
243- }
163+ get onorigin ( ) { return getApplicationCallback ( this . connection , 'onorigin' ) ; }
164+ set onorigin ( fn ) { setApplicationCallback ( this . connection , 'onorigin' , fn , this ) ; }
244165
245166 /** @type {Function|undefined } */
246- get onsettings ( ) { return this . #onsettings ; }
167+ get onsettings ( ) { return getApplicationCallback ( this . connection , 'onapplication' ) ; }
247168 set onsettings ( fn ) {
248- if ( fn !== undefined ) validateFunction ( fn , 'onsettings' ) ;
249- setApplicationCallback ( this . #session, 'onapplication' , this . #bind( fn ) ) ;
250- this . #onsettings = fn ;
169+ setApplicationCallback ( this . connection , 'onapplication' , fn , this , 'onsettings' ) ;
251170 }
252171
253- /**
254- * Called with a session error after the QUIC session's own onerror, which
255- * stays the transport-level handler. Either may be set independently.
256- * @type {Function|undefined }
257- */
258- get onerror ( ) { return this . #onerror; }
259- set onerror ( fn ) {
260- if ( fn !== undefined ) validateFunction ( fn , 'onerror' ) ;
261- setApplicationCallback ( this . #session, 'onapperror' , this . #bind( fn ) ) ;
262- this . #onerror = fn ;
263- }
264-
265- /** @type {Promise<object> } */
266- get opened ( ) { return this . #session. opened ; }
267-
268- /** @type {Promise<void> } */
269- get closed ( ) { return this . #session. closed ; }
270-
271- /** @type {boolean } */
272- get closing ( ) { return this . #session. closing ; }
273-
274- /** @type {boolean } */
275- get destroyed ( ) { return this . #session. destroyed ; }
276-
277172 /**
278173 * Opens a request stream.
279174 * @returns {Promise<QuicStream> }
280175 */
281- async createBidirectionalStream ( options ) {
282- if ( getQuicSessionState ( this . #session) . isServer ) {
283- throw new ERR_INVALID_STATE (
284- 'Server sessions cannot open HTTP/3 request streams' ) ;
285- }
286- return await createApplicationStream (
287- this . #session, kStreamDirectionBidirectional , options ) ;
288- }
289-
290- close ( options ) { return this . #session. close ( options ) ; }
291-
292- destroy ( error , options ) { return this . #session. destroy ( error , options ) ; }
293-
294- async [ SymbolAsyncDispose ] ( ) { await this . close ( ) ; }
295-
296- [ kInspect ] ( depth , options ) {
297- if ( depth < 0 ) {
298- return 'Http3Session { }' ;
176+ createBidirectionalStream ( options ) {
177+ if ( isServerConnection ( this . connection ) ) {
178+ return PromiseReject ( new ERR_INVALID_STATE (
179+ 'Server sessions cannot open HTTP/3 request streams' ) ) ;
299180 }
300- const opts = {
301- __proto__ : null ,
302- ...options ,
303- depth : options . depth == null ? null : options . depth - 1 ,
304- } ;
305- return `Http3Session ${ inspect ( {
306- quicSession : this . #session,
307- settings : this . settings ,
308- destroyed : this . destroyed ,
309- } , opts ) } `;
181+ return createApplicationStream (
182+ this . connection , kStreamDirectionBidirectional , options ) ;
310183 }
311184}
312185
0 commit comments