@@ -90,6 +90,7 @@ const kMaybeDestroy = Symbol('maybe-destroy');
9090const kLocalSettings = Symbol ( 'local-settings' ) ;
9191const kOptions = Symbol ( 'options' ) ;
9292const kOwner = Symbol ( 'owner' ) ;
93+ const kOrigin = Symbol ( 'origin' ) ;
9394const kProceed = Symbol ( 'proceed' ) ;
9495const kProtocol = Symbol ( 'protocol' ) ;
9596const kProxySocket = Symbol ( 'proxy-socket' ) ;
@@ -152,6 +153,7 @@ const {
152153 HTTP_STATUS_NO_CONTENT ,
153154 HTTP_STATUS_NOT_MODIFIED ,
154155 HTTP_STATUS_SWITCHING_PROTOCOLS ,
156+ HTTP_STATUS_MISDIRECTED_REQUEST ,
155157
156158 STREAM_OPTION_EMPTY_PAYLOAD ,
157159 STREAM_OPTION_GET_TRAILERS
@@ -242,6 +244,11 @@ function onSessionHeaders(handle, id, cat, flags, headers) {
242244 } else {
243245 event = endOfStream ? 'trailers' : 'headers' ;
244246 }
247+ const session = stream . session ;
248+ if ( status === HTTP_STATUS_MISDIRECTED_REQUEST ) {
249+ const originSet = session [ kState ] . originSet = initOriginSet ( session ) ;
250+ originSet . delete ( stream [ kOrigin ] ) ;
251+ }
245252 debug ( `Http2Stream ${ id } [Http2Session ` +
246253 `${ sessionName ( type ) } ]: emitting stream '${ event } ' event` ) ;
247254 process . nextTick ( emit , stream , event , obj , flags , headers ) ;
@@ -404,6 +411,39 @@ function onAltSvc(stream, origin, alt) {
404411 session . emit ( 'altsvc' , alt , origin , stream ) ;
405412}
406413
414+ function initOriginSet ( session ) {
415+ let originSet = session [ kState ] . originSet ;
416+ if ( originSet === undefined ) {
417+ const socket = session [ kSocket ] ;
418+ session [ kState ] . originSet = originSet = new Set ( ) ;
419+ if ( socket . servername != null ) {
420+ let originString = `https://${ socket . servername } ` ;
421+ if ( socket . remotePort != null )
422+ originString += `:${ socket . remotePort } ` ;
423+ // We have to ensure that it is a properly serialized
424+ // ASCII origin string. The socket.servername might not
425+ // be properly ASCII encoded.
426+ originSet . add ( ( new URL ( originString ) ) . origin ) ;
427+ }
428+ }
429+ return originSet ;
430+ }
431+
432+ function onOrigin ( origins ) {
433+ const session = this [ kOwner ] ;
434+ if ( session . destroyed )
435+ return ;
436+ debug ( `Http2Session ${ sessionName ( session [ kType ] ) } : origin received: ` +
437+ `${ origins . join ( ', ' ) } ` ) ;
438+ session [ kUpdateTimer ] ( ) ;
439+ if ( ! session . encrypted || session . destroyed )
440+ return undefined ;
441+ const originSet = initOriginSet ( session ) ;
442+ for ( var n = 0 ; n < origins . length ; n ++ )
443+ originSet . add ( origins [ n ] ) ;
444+ session . emit ( 'origin' , origins ) ;
445+ }
446+
407447// Receiving a GOAWAY frame from the connected peer is a signal that no
408448// new streams should be created. If the code === NGHTTP2_NO_ERROR, we
409449// are going to send our close, but allow existing frames to close
@@ -766,6 +806,7 @@ function setupHandle(socket, type, options) {
766806 handle . onframeerror = onFrameError ;
767807 handle . ongoawaydata = onGoawayData ;
768808 handle . onaltsvc = onAltSvc ;
809+ handle . onorigin = onOrigin ;
769810
770811 if ( typeof options . selectPadding === 'function' )
771812 handle . ongetpadding = onSelectPadding ( options . selectPadding ) ;
@@ -792,6 +833,12 @@ function setupHandle(socket, type, options) {
792833 options . settings : { } ;
793834
794835 this . settings ( settings ) ;
836+
837+ if ( type === NGHTTP2_SESSION_SERVER &&
838+ Array . isArray ( options . origins ) ) {
839+ this . origin ( ...options . origins ) ;
840+ }
841+
795842 process . nextTick ( emit , this , 'connect' , this , socket ) ;
796843}
797844
@@ -930,23 +977,7 @@ class Http2Session extends EventEmitter {
930977 get originSet ( ) {
931978 if ( ! this . encrypted || this . destroyed )
932979 return undefined ;
933-
934- let originSet = this [ kState ] . originSet ;
935- if ( originSet === undefined ) {
936- const socket = this [ kSocket ] ;
937- this [ kState ] . originSet = originSet = new Set ( ) ;
938- if ( socket . servername != null ) {
939- let originString = `https://${ socket . servername } ` ;
940- if ( socket . remotePort != null )
941- originString += `:${ socket . remotePort } ` ;
942- // We have to ensure that it is a properly serialized
943- // ASCII origin string. The socket.servername might not
944- // be properly ASCII encoded.
945- originSet . add ( ( new URL ( originString ) ) . origin ) ;
946- }
947- }
948-
949- return Array . from ( originSet ) ;
980+ return Array . from ( initOriginSet ( this ) ) ;
950981 }
951982
952983 // True if the Http2Session is still waiting for the socket to connect
@@ -1324,6 +1355,41 @@ class ServerHttp2Session extends Http2Session {
13241355
13251356 this [ kHandle ] . altsvc ( stream , origin || '' , alt ) ;
13261357 }
1358+
1359+ // Submits an origin frame to be sent.
1360+ origin ( ...origins ) {
1361+ if ( this . destroyed )
1362+ throw new errors . Error ( 'ERR_HTTP2_INVALID_SESSION' ) ;
1363+
1364+ if ( origins . length === 0 )
1365+ return ;
1366+
1367+ let arr = '' ;
1368+ let len = 0 ;
1369+ const count = origins . length ;
1370+ for ( var i = 0 ; i < count ; i ++ ) {
1371+ let origin = origins [ i ] ;
1372+ if ( typeof origin === 'string' ) {
1373+ origin = ( new URL ( origin ) ) . origin ;
1374+ } else if ( origin != null && typeof origin === 'object' ) {
1375+ origin = origin . origin ;
1376+ }
1377+ if ( typeof origin !== 'string' )
1378+ throw new errors . Error ( 'ERR_INVALID_ARG_TYPE' , 'origin' , 'string' ,
1379+ origin ) ;
1380+ if ( origin === 'null' )
1381+ throw new errors . Error ( 'ERR_HTTP2_INVALID_ORIGIN' ) ;
1382+
1383+ arr += `${ origin } \0` ;
1384+ len += origin . length ;
1385+ }
1386+
1387+ if ( len > 16382 )
1388+ throw new errors . Error ( 'ERR_HTTP2_ORIGIN_LENGTH' ) ;
1389+
1390+ this [ kHandle ] . origin ( arr , count ) ;
1391+ }
1392+
13271393}
13281394
13291395// ClientHttp2Session instances have to wait for the socket to connect after
@@ -1394,6 +1460,8 @@ class ClientHttp2Session extends Http2Session {
13941460
13951461 const stream = new ClientHttp2Stream ( this , undefined , undefined , { } ) ;
13961462 stream [ kSentHeaders ] = headers ;
1463+ stream [ kOrigin ] = `${ headers [ HTTP2_HEADER_SCHEME ] } ://` +
1464+ `${ headers [ HTTP2_HEADER_AUTHORITY ] } ` ;
13971465
13981466 // Close the writable side of the stream if options.endStream is set.
13991467 if ( options . endStream )
0 commit comments