@@ -117,6 +117,7 @@ const {
117117 isUint32,
118118 validateAbortSignal,
119119 validateBoolean,
120+ validateOneOf,
120121 validateBuffer,
121122 validateFunction,
122123 validateInt32,
@@ -148,6 +149,7 @@ const {
148149 getStreamState,
149150 isPayloadMeaningless,
150151 kAuthority,
152+ kHttpValidation,
151153 kSensitiveHeaders,
152154 kStrictSingleValueFields,
153155 kSocket,
@@ -1325,6 +1327,8 @@ class Http2Session extends EventEmitter {
13251327 this [ kHandle ] = undefined ;
13261328 this [ kStrictSingleValueFields ] =
13271329 options . strictSingleValueFields ;
1330+ this [ kHttpValidation ] =
1331+ options . httpValidation ;
13281332
13291333 // Do not use nagle's algorithm
13301334 if ( typeof socket . setNoDelay === 'function' )
@@ -2390,6 +2394,7 @@ class Http2Stream extends Duplex {
23902394 headers ,
23912395 assertValidPseudoHeaderTrailer ,
23922396 this . session [ kStrictSingleValueFields ] ,
2397+ this . session [ kHttpValidation ] ,
23932398 ) ;
23942399 this [ kSentTrailers ] = headers ;
23952400
@@ -2603,6 +2608,7 @@ function prepareResponseHeaders(stream, headersParam, options) {
26032608 headers ,
26042609 assertValidPseudoHeaderResponse ,
26052610 stream . session [ kStrictSingleValueFields ] ,
2611+ stream . session [ kHttpValidation ] ,
26062612 ) ;
26072613
26082614 return { headers, headersList, statusCode } ;
@@ -2710,6 +2716,7 @@ function processRespondWithFD(self, fd, headers, offset = 0, length = -1,
27102716 headers ,
27112717 assertValidPseudoHeaderResponse ,
27122718 self . session [ kStrictSingleValueFields ] ,
2719+ self . session [ kHttpValidation ] ,
27132720 ) ;
27142721 } catch ( err ) {
27152722 if ( self . ownsFd )
@@ -2941,6 +2948,7 @@ class ServerHttp2Stream extends Http2Stream {
29412948 headers ,
29422949 assertValidPseudoHeader ,
29432950 this . session [ kStrictSingleValueFields ] ,
2951+ this . session [ kHttpValidation ] ,
29442952 ) ;
29452953
29462954 const streamOptions = options . endStream ? STREAM_OPTION_EMPTY_PAYLOAD : 0 ;
@@ -3209,6 +3217,7 @@ class ServerHttp2Stream extends Http2Stream {
32093217 headers ,
32103218 assertValidPseudoHeaderResponse ,
32113219 this . session [ kStrictSingleValueFields ] ,
3220+ this . session [ kHttpValidation ] ,
32123221 ) ;
32133222 if ( ! this [ kInfoHeaders ] )
32143223 this [ kInfoHeaders ] = [ headers ] ;
@@ -3386,6 +3395,16 @@ function initializeOptions(options) {
33863395 options . strictSingleValueFields = true ;
33873396 }
33883397
3398+ const httpValidation = options . httpValidation ;
3399+ if ( httpValidation !== undefined ) {
3400+ validateOneOf ( httpValidation , 'options.httpValidation' ,
3401+ [ 'strict' , 'relaxed' , 'insecure' ] ) ;
3402+ if ( httpValidation !== 'strict' ) {
3403+ // In relaxed/insecure mode, disable strict single-value fields
3404+ // and use lenient header value validation
3405+ options . strictSingleValueFields = false ;
3406+ }
3407+ }
33893408
33903409 // Initialize http1Options bag for HTTP/1 fallback when allowHTTP1 is true.
33913410 // This bag is passed to storeHTTPOptions() to configure HTTP/1 server
@@ -3607,6 +3626,17 @@ function connect(authority, options, listener) {
36073626 options . strictSingleValueFields = true ;
36083627 }
36093628
3629+ const httpValidation = options . httpValidation ;
3630+ if ( httpValidation !== undefined ) {
3631+ validateOneOf ( httpValidation , 'options.httpValidation' ,
3632+ [ 'strict' , 'relaxed' , 'insecure' ] ) ;
3633+ if ( httpValidation !== 'strict' ) {
3634+ // In relaxed/insecure mode, disable strict single-value fields
3635+ // and use lenient header value validation
3636+ options . strictSingleValueFields = false ;
3637+ }
3638+ }
3639+
36103640 if ( typeof authority === 'string' )
36113641 authority = new URL ( authority ) ;
36123642
0 commit comments