@@ -43,13 +43,15 @@ const {
43
43
ERR_HTTP2_HEADERS_AFTER_RESPOND ,
44
44
ERR_HTTP2_HEADERS_SENT ,
45
45
ERR_HTTP2_INVALID_INFO_STATUS ,
46
+ ERR_HTTP2_INVALID_ORIGIN ,
46
47
ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH ,
47
48
ERR_HTTP2_INVALID_SESSION ,
48
49
ERR_HTTP2_INVALID_SETTING_VALUE ,
49
50
ERR_HTTP2_INVALID_STREAM ,
50
51
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK ,
51
52
ERR_HTTP2_NESTED_PUSH ,
52
53
ERR_HTTP2_NO_SOCKET_MANIPULATION ,
54
+ ERR_HTTP2_ORIGIN_LENGTH ,
53
55
ERR_HTTP2_OUT_OF_STREAMS ,
54
56
ERR_HTTP2_PAYLOAD_FORBIDDEN ,
55
57
ERR_HTTP2_PING_CANCEL ,
@@ -148,6 +150,7 @@ const kInfoHeaders = Symbol('sent-info-headers');
148
150
const kLocalSettings = Symbol ( 'local-settings' ) ;
149
151
const kOptions = Symbol ( 'options' ) ;
150
152
const kOwner = owner_symbol ;
153
+ const kOrigin = Symbol ( 'origin' ) ;
151
154
const kProceed = Symbol ( 'proceed' ) ;
152
155
const kProtocol = Symbol ( 'protocol' ) ;
153
156
const kProxySocket = Symbol ( 'proxy-socket' ) ;
@@ -209,6 +212,7 @@ const {
209
212
HTTP_STATUS_NO_CONTENT ,
210
213
HTTP_STATUS_NOT_MODIFIED ,
211
214
HTTP_STATUS_SWITCHING_PROTOCOLS ,
215
+ HTTP_STATUS_MISDIRECTED_REQUEST ,
212
216
213
217
STREAM_OPTION_EMPTY_PAYLOAD ,
214
218
STREAM_OPTION_GET_TRAILERS
@@ -299,6 +303,11 @@ function onSessionHeaders(handle, id, cat, flags, headers) {
299
303
} else {
300
304
event = endOfStream ? 'trailers' : 'headers' ;
301
305
}
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
+ }
302
311
debug ( `Http2Stream ${ id } [Http2Session ` +
303
312
`${ sessionName ( type ) } ]: emitting stream '${ event } ' event` ) ;
304
313
process . nextTick ( emit , stream , event , obj , flags , headers ) ;
@@ -429,6 +438,39 @@ function onAltSvc(stream, origin, alt) {
429
438
session . emit ( 'altsvc' , alt , origin , stream ) ;
430
439
}
431
440
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
+
432
474
// Receiving a GOAWAY frame from the connected peer is a signal that no
433
475
// new streams should be created. If the code === NGHTTP2_NO_ERROR, we
434
476
// are going to send our close, but allow existing frames to close
@@ -782,6 +824,7 @@ function setupHandle(socket, type, options) {
782
824
handle . onframeerror = onFrameError ;
783
825
handle . ongoawaydata = onGoawayData ;
784
826
handle . onaltsvc = onAltSvc ;
827
+ handle . onorigin = onOrigin ;
785
828
786
829
if ( typeof options . selectPadding === 'function' )
787
830
handle . ongetpadding = onSelectPadding ( options . selectPadding ) ;
@@ -808,6 +851,12 @@ function setupHandle(socket, type, options) {
808
851
options . settings : { } ;
809
852
810
853
this . settings ( settings ) ;
854
+
855
+ if ( type === NGHTTP2_SESSION_SERVER &&
856
+ Array . isArray ( options . origins ) ) {
857
+ this . origin ( ...options . origins ) ;
858
+ }
859
+
811
860
process . nextTick ( emit , this , 'connect' , this , socket ) ;
812
861
}
813
862
@@ -947,23 +996,7 @@ class Http2Session extends EventEmitter {
947
996
get originSet ( ) {
948
997
if ( ! this . encrypted || this . destroyed )
949
998
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 ) ) ;
967
1000
}
968
1001
969
1002
// True if the Http2Session is still waiting for the socket to connect
@@ -1338,6 +1371,40 @@ class ServerHttp2Session extends Http2Session {
1338
1371
1339
1372
this [ kHandle ] . altsvc ( stream , origin || '' , alt ) ;
1340
1373
}
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
+
1341
1408
}
1342
1409
1343
1410
// ClientHttp2Session instances have to wait for the socket to connect after
@@ -1406,6 +1473,8 @@ class ClientHttp2Session extends Http2Session {
1406
1473
1407
1474
const stream = new ClientHttp2Stream ( this , undefined , undefined , { } ) ;
1408
1475
stream [ kSentHeaders ] = headers ;
1476
+ stream [ kOrigin ] = `${ headers [ HTTP2_HEADER_SCHEME ] } ://` +
1477
+ `${ headers [ HTTP2_HEADER_AUTHORITY ] } ` ;
1409
1478
1410
1479
// Close the writable side of the stream if options.endStream is set.
1411
1480
if ( options . endStream )
0 commit comments