@@ -43,13 +43,15 @@ const {
4343 ERR_HTTP2_HEADERS_AFTER_RESPOND ,
4444 ERR_HTTP2_HEADERS_SENT ,
4545 ERR_HTTP2_INVALID_INFO_STATUS ,
46+ ERR_HTTP2_INVALID_ORIGIN ,
4647 ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH ,
4748 ERR_HTTP2_INVALID_SESSION ,
4849 ERR_HTTP2_INVALID_SETTING_VALUE ,
4950 ERR_HTTP2_INVALID_STREAM ,
5051 ERR_HTTP2_MAX_PENDING_SETTINGS_ACK ,
5152 ERR_HTTP2_NESTED_PUSH ,
5253 ERR_HTTP2_NO_SOCKET_MANIPULATION ,
54+ ERR_HTTP2_ORIGIN_LENGTH ,
5355 ERR_HTTP2_OUT_OF_STREAMS ,
5456 ERR_HTTP2_PAYLOAD_FORBIDDEN ,
5557 ERR_HTTP2_PING_CANCEL ,
@@ -148,6 +150,7 @@ const kInfoHeaders = Symbol('sent-info-headers');
148150const kLocalSettings = Symbol ( 'local-settings' ) ;
149151const kOptions = Symbol ( 'options' ) ;
150152const kOwner = owner_symbol ;
153+ const kOrigin = Symbol ( 'origin' ) ;
151154const kProceed = Symbol ( 'proceed' ) ;
152155const kProtocol = Symbol ( 'protocol' ) ;
153156const kProxySocket = Symbol ( 'proxy-socket' ) ;
@@ -209,6 +212,7 @@ const {
209212 HTTP_STATUS_NO_CONTENT ,
210213 HTTP_STATUS_NOT_MODIFIED ,
211214 HTTP_STATUS_SWITCHING_PROTOCOLS ,
215+ HTTP_STATUS_MISDIRECTED_REQUEST ,
212216
213217 STREAM_OPTION_EMPTY_PAYLOAD ,
214218 STREAM_OPTION_GET_TRAILERS
@@ -299,6 +303,11 @@ function onSessionHeaders(handle, id, cat, flags, headers) {
299303 } else {
300304 event = endOfStream ? 'trailers' : 'headers' ;
301305 }
306+ const session = stream . session ;
307+ if ( status === HTTP_STATUS_MISDIRECTED_REQUEST ) {
308+ const originSet = session [ kState ] . originSet = initOriginSet ( session ) ;
309+ originSet . delete ( stream [ kOrigin ] ) ;
310+ }
302311 debug ( `Http2Stream ${ id } [Http2Session ` +
303312 `${ sessionName ( type ) } ]: emitting stream '${ event } ' event` ) ;
304313 process . nextTick ( emit , stream , event , obj , flags , headers ) ;
@@ -429,6 +438,39 @@ function onAltSvc(stream, origin, alt) {
429438 session . emit ( 'altsvc' , alt , origin , stream ) ;
430439}
431440
441+ function initOriginSet ( session ) {
442+ let originSet = session [ kState ] . originSet ;
443+ if ( originSet === undefined ) {
444+ const socket = session [ kSocket ] ;
445+ session [ kState ] . originSet = originSet = new Set ( ) ;
446+ if ( socket . servername != null ) {
447+ let originString = `https://${ socket . servername } ` ;
448+ if ( socket . remotePort != null )
449+ originString += `:${ socket . remotePort } ` ;
450+ // We have to ensure that it is a properly serialized
451+ // ASCII origin string. The socket.servername might not
452+ // be properly ASCII encoded.
453+ originSet . add ( ( new URL ( originString ) ) . origin ) ;
454+ }
455+ }
456+ return originSet ;
457+ }
458+
459+ function onOrigin ( origins ) {
460+ const session = this [ kOwner ] ;
461+ if ( session . destroyed )
462+ return ;
463+ debug ( `Http2Session ${ sessionName ( session [ kType ] ) } : origin received: ` +
464+ `${ origins . join ( ', ' ) } ` ) ;
465+ session [ kUpdateTimer ] ( ) ;
466+ if ( ! session . encrypted || session . destroyed )
467+ return undefined ;
468+ const originSet = initOriginSet ( session ) ;
469+ for ( var n = 0 ; n < origins . length ; n ++ )
470+ originSet . add ( origins [ n ] ) ;
471+ session . emit ( 'origin' , origins ) ;
472+ }
473+
432474// Receiving a GOAWAY frame from the connected peer is a signal that no
433475// new streams should be created. If the code === NGHTTP2_NO_ERROR, we
434476// are going to send our close, but allow existing frames to close
@@ -782,6 +824,7 @@ function setupHandle(socket, type, options) {
782824 handle . onframeerror = onFrameError ;
783825 handle . ongoawaydata = onGoawayData ;
784826 handle . onaltsvc = onAltSvc ;
827+ handle . onorigin = onOrigin ;
785828
786829 if ( typeof options . selectPadding === 'function' )
787830 handle . ongetpadding = onSelectPadding ( options . selectPadding ) ;
@@ -808,6 +851,12 @@ function setupHandle(socket, type, options) {
808851 options . settings : { } ;
809852
810853 this . settings ( settings ) ;
854+
855+ if ( type === NGHTTP2_SESSION_SERVER &&
856+ Array . isArray ( options . origins ) ) {
857+ this . origin ( ...options . origins ) ;
858+ }
859+
811860 process . nextTick ( emit , this , 'connect' , this , socket ) ;
812861}
813862
@@ -947,23 +996,7 @@ class Http2Session extends EventEmitter {
947996 get originSet ( ) {
948997 if ( ! this . encrypted || this . destroyed )
949998 return undefined ;
950-
951- let originSet = this [ kState ] . originSet ;
952- if ( originSet === undefined ) {
953- const socket = this [ kSocket ] ;
954- this [ kState ] . originSet = originSet = new Set ( ) ;
955- if ( socket . servername != null ) {
956- let originString = `https://${ socket . servername } ` ;
957- if ( socket . remotePort != null )
958- originString += `:${ socket . remotePort } ` ;
959- // We have to ensure that it is a properly serialized
960- // ASCII origin string. The socket.servername might not
961- // be properly ASCII encoded.
962- originSet . add ( ( new URL ( originString ) ) . origin ) ;
963- }
964- }
965-
966- return Array . from ( originSet ) ;
999+ return Array . from ( initOriginSet ( this ) ) ;
9671000 }
9681001
9691002 // True if the Http2Session is still waiting for the socket to connect
@@ -1338,6 +1371,40 @@ class ServerHttp2Session extends Http2Session {
13381371
13391372 this [ kHandle ] . altsvc ( stream , origin || '' , alt ) ;
13401373 }
1374+
1375+ // Submits an origin frame to be sent.
1376+ origin ( ...origins ) {
1377+ if ( this . destroyed )
1378+ throw new ERR_HTTP2_INVALID_SESSION ( ) ;
1379+
1380+ if ( origins . length === 0 )
1381+ return ;
1382+
1383+ let arr = '' ;
1384+ let len = 0 ;
1385+ const count = origins . length ;
1386+ for ( var i = 0 ; i < count ; i ++ ) {
1387+ let origin = origins [ i ] ;
1388+ if ( typeof origin === 'string' ) {
1389+ origin = ( new URL ( origin ) ) . origin ;
1390+ } else if ( origin != null && typeof origin === 'object' ) {
1391+ origin = origin . origin ;
1392+ }
1393+ if ( typeof origin !== 'string' )
1394+ throw new ERR_INVALID_ARG_TYPE ( 'origin' , 'string' , origin ) ;
1395+ if ( origin === 'null' )
1396+ throw new ERR_HTTP2_INVALID_ORIGIN ( ) ;
1397+
1398+ arr += `${ origin } \0` ;
1399+ len += origin . length ;
1400+ }
1401+
1402+ if ( len > 16382 )
1403+ throw new ERR_HTTP2_ORIGIN_LENGTH ( ) ;
1404+
1405+ this [ kHandle ] . origin ( arr , count ) ;
1406+ }
1407+
13411408}
13421409
13431410// ClientHttp2Session instances have to wait for the socket to connect after
@@ -1406,6 +1473,8 @@ class ClientHttp2Session extends Http2Session {
14061473
14071474 const stream = new ClientHttp2Stream ( this , undefined , undefined , { } ) ;
14081475 stream [ kSentHeaders ] = headers ;
1476+ stream [ kOrigin ] = `${ headers [ HTTP2_HEADER_SCHEME ] } ://` +
1477+ `${ headers [ HTTP2_HEADER_AUTHORITY ] } ` ;
14091478
14101479 // Close the writable side of the stream if options.endStream is set.
14111480 if ( options . endStream )
0 commit comments