@@ -2541,8 +2541,31 @@ function callStreamClose(stream) {
2541
2541
stream . close ( ) ;
2542
2542
}
2543
2543
2544
- function processHeaders ( oldHeaders , options ) {
2545
- assertIsObject ( oldHeaders , 'headers' ) ;
2544
+ function prepareResponseHeaders ( stream , headersParam , options ) {
2545
+ let headers ;
2546
+ let statusCode ;
2547
+
2548
+ if ( ArrayIsArray ( headersParam ) ) {
2549
+ ( {
2550
+ headers,
2551
+ statusCode,
2552
+ } = prepareResponseHeadersArray ( headersParam , options ) ) ;
2553
+ stream [ kRawHeaders ] = headers ;
2554
+ } else {
2555
+ ( {
2556
+ headers,
2557
+ statusCode,
2558
+ } = prepareResponseHeadersObject ( headersParam , options ) ) ;
2559
+ stream [ kSentHeaders ] = headers ;
2560
+ }
2561
+
2562
+ const headersList = buildNgHeaderString ( headers , assertValidPseudoHeaderResponse ) ;
2563
+
2564
+ return { headers, headersList, statusCode } ;
2565
+ }
2566
+
2567
+ function prepareResponseHeadersObject ( oldHeaders , options ) {
2568
+ assertIsObject ( oldHeaders , 'headers' , [ 'Object' , 'Array' ] ) ;
2546
2569
const headers = { __proto__ : null } ;
2547
2570
2548
2571
if ( oldHeaders !== null && oldHeaders !== undefined ) {
@@ -2563,23 +2586,58 @@ function processHeaders(oldHeaders, options) {
2563
2586
headers [ HTTP2_HEADER_DATE ] ??= utcDate ( ) ;
2564
2587
}
2565
2588
2589
+ validatePreparedResponseHeaders ( headers , statusCode ) ;
2590
+
2591
+ return {
2592
+ headers,
2593
+ statusCode : headers [ HTTP2_HEADER_STATUS ] ,
2594
+ } ;
2595
+ }
2596
+
2597
+ function prepareResponseHeadersArray ( headers , options ) {
2598
+ let statusCode ;
2599
+ let isDateSet = false ;
2600
+
2601
+ for ( let i = 0 ; i < headers . length ; i += 2 ) {
2602
+ const header = headers [ i ] . toLowerCase ( ) ;
2603
+ const value = headers [ i + 1 ] ;
2604
+
2605
+ if ( header === HTTP2_HEADER_STATUS ) {
2606
+ statusCode = value | 0 ;
2607
+ } else if ( header === HTTP2_HEADER_DATE ) {
2608
+ isDateSet = true ;
2609
+ }
2610
+ }
2611
+
2612
+ if ( ! statusCode ) {
2613
+ statusCode = HTTP_STATUS_OK ;
2614
+ headers . unshift ( HTTP2_HEADER_STATUS , statusCode ) ;
2615
+ }
2616
+
2617
+ if ( ! isDateSet && ( options . sendDate == null || options . sendDate ) ) {
2618
+ headers . push ( HTTP2_HEADER_DATE , utcDate ( ) ) ;
2619
+ }
2620
+
2621
+ validatePreparedResponseHeaders ( headers , statusCode ) ;
2622
+
2623
+ return { headers, statusCode } ;
2624
+ }
2625
+
2626
+ function validatePreparedResponseHeaders ( headers , statusCode ) {
2566
2627
// This is intentionally stricter than the HTTP/1 implementation, which
2567
2628
// allows values between 100 and 999 (inclusive) in order to allow for
2568
2629
// backwards compatibility with non-spec compliant code. With HTTP/2,
2569
2630
// we have the opportunity to start fresh with stricter spec compliance.
2570
2631
// This will have an impact on the compatibility layer for anyone using
2571
2632
// non-standard, non-compliant status codes.
2572
2633
if ( statusCode < 200 || statusCode > 599 )
2573
- throw new ERR_HTTP2_STATUS_INVALID ( headers [ HTTP2_HEADER_STATUS ] ) ;
2634
+ throw new ERR_HTTP2_STATUS_INVALID ( statusCode ) ;
2574
2635
2575
2636
const neverIndex = headers [ kSensitiveHeaders ] ;
2576
2637
if ( neverIndex !== undefined && ! ArrayIsArray ( neverIndex ) )
2577
2638
throw new ERR_INVALID_ARG_VALUE ( 'headers[http2.neverIndex]' , neverIndex ) ;
2578
-
2579
- return headers ;
2580
2639
}
2581
2640
2582
-
2583
2641
function onFileUnpipe ( ) {
2584
2642
const stream = this . sink [ kOwner ] ;
2585
2643
if ( stream . ownsFd )
@@ -2882,7 +2940,7 @@ class ServerHttp2Stream extends Http2Stream {
2882
2940
}
2883
2941
2884
2942
// Initiate a response on this Http2Stream
2885
- respond ( headers , options ) {
2943
+ respond ( headersParam , options ) {
2886
2944
if ( this . destroyed || this . closed )
2887
2945
throw new ERR_HTTP2_INVALID_STREAM ( ) ;
2888
2946
if ( this . headersSent )
@@ -2907,15 +2965,16 @@ class ServerHttp2Stream extends Http2Stream {
2907
2965
state . flags |= STREAM_FLAGS_HAS_TRAILERS ;
2908
2966
}
2909
2967
2910
- headers = processHeaders ( headers , options ) ;
2911
- const headersList = buildNgHeaderString ( headers , assertValidPseudoHeaderResponse ) ;
2912
- this [ kSentHeaders ] = headers ;
2968
+ const {
2969
+ headers,
2970
+ headersList,
2971
+ statusCode,
2972
+ } = prepareResponseHeaders ( this , headersParam , options ) ;
2913
2973
2914
2974
state . flags |= STREAM_FLAGS_HEADERS_SENT ;
2915
2975
2916
2976
// Close the writable side if the endStream option is set or status
2917
2977
// is one of known codes with no payload, or it's a head request
2918
- const statusCode = headers [ HTTP2_HEADER_STATUS ] | 0 ;
2919
2978
if ( ! ! options . endStream ||
2920
2979
statusCode === HTTP_STATUS_NO_CONTENT ||
2921
2980
statusCode === HTTP_STATUS_RESET_CONTENT ||
@@ -2945,7 +3004,7 @@ class ServerHttp2Stream extends Http2Stream {
2945
3004
// regular file, here the fd is passed directly. If the underlying
2946
3005
// mechanism is not able to read from the fd, then the stream will be
2947
3006
// reset with an error code.
2948
- respondWithFD ( fd , headers , options ) {
3007
+ respondWithFD ( fd , headersParam , options ) {
2949
3008
if ( this . destroyed || this . closed )
2950
3009
throw new ERR_HTTP2_INVALID_STREAM ( ) ;
2951
3010
if ( this . headersSent )
@@ -2982,8 +3041,11 @@ class ServerHttp2Stream extends Http2Stream {
2982
3041
this [ kUpdateTimer ] ( ) ;
2983
3042
this . ownsFd = false ;
2984
3043
2985
- headers = processHeaders ( headers , options ) ;
2986
- const statusCode = headers [ HTTP2_HEADER_STATUS ] |= 0 ;
3044
+ const {
3045
+ headers,
3046
+ statusCode,
3047
+ } = prepareResponseHeadersObject ( headersParam , options ) ;
3048
+
2987
3049
// Payload/DATA frames are not permitted in these cases
2988
3050
if ( statusCode === HTTP_STATUS_NO_CONTENT ||
2989
3051
statusCode === HTTP_STATUS_RESET_CONTENT ||
@@ -3011,7 +3073,7 @@ class ServerHttp2Stream extends Http2Stream {
3011
3073
// giving the user an opportunity to verify the details and set additional
3012
3074
// headers. If statCheck returns false, the operation is aborted and no
3013
3075
// file details are sent.
3014
- respondWithFile ( path , headers , options ) {
3076
+ respondWithFile ( path , headersParam , options ) {
3015
3077
if ( this . destroyed || this . closed )
3016
3078
throw new ERR_HTTP2_INVALID_STREAM ( ) ;
3017
3079
if ( this . headersSent )
@@ -3042,8 +3104,11 @@ class ServerHttp2Stream extends Http2Stream {
3042
3104
this [ kUpdateTimer ] ( ) ;
3043
3105
this . ownsFd = true ;
3044
3106
3045
- headers = processHeaders ( headers , options ) ;
3046
- const statusCode = headers [ HTTP2_HEADER_STATUS ] |= 0 ;
3107
+ const {
3108
+ headers,
3109
+ statusCode,
3110
+ } = prepareResponseHeadersObject ( headersParam , options ) ;
3111
+
3047
3112
// Payload/DATA frames are not permitted in these cases
3048
3113
if ( statusCode === HTTP_STATUS_NO_CONTENT ||
3049
3114
statusCode === HTTP_STATUS_RESET_CONTENT ||
0 commit comments