@@ -15,6 +15,7 @@ const {
1515} = primordials ;
1616
1717const {
18+ _checkInvalidHeaderChar : checkInvalidHeaderChar ,
1819 _checkIsHttpToken : checkIsHttpToken ,
1920} = require ( '_http_common' ) ;
2021
@@ -26,11 +27,13 @@ const {
2627 ERR_HTTP2_CONNECT_SCHEME ,
2728 ERR_HTTP2_HEADER_SINGLE_VALUE ,
2829 ERR_HTTP2_INVALID_CONNECTION_HEADERS ,
30+ ERR_HTTP2_INVALID_HEADER_VALUE ,
2931 ERR_HTTP2_INVALID_PSEUDOHEADER : { HideStackFramesError : ERR_HTTP2_INVALID_PSEUDOHEADER } ,
3032 ERR_HTTP2_INVALID_SETTING_VALUE ,
3133 ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS ,
3234 ERR_INVALID_ARG_TYPE ,
3335 ERR_INVALID_HTTP_TOKEN ,
36+ ERR_UNESCAPED_CHARACTERS ,
3437 } ,
3538 getMessage,
3639 hideStackFrames,
@@ -40,6 +43,7 @@ const {
4043const kAuthority = Symbol ( 'authority' ) ;
4144const kSensitiveHeaders = Symbol ( 'sensitiveHeaders' ) ;
4245const kStrictSingleValueFields = Symbol ( 'strictSingleValueFields' ) ;
46+ const kHttpValidation = Symbol ( 'httpValidation' ) ;
4347const kSocket = Symbol ( 'socket' ) ;
4448const kProtocol = Symbol ( 'protocol' ) ;
4549const kProxySocket = Symbol ( 'proxySocket' ) ;
@@ -120,6 +124,23 @@ const kValidPseudoHeaders = new SafeSet([
120124 HTTP2_HEADER_PROTOCOL ,
121125] ) ;
122126
127+ const INVALID_PATH_REGEX = / [ ^ \u0021 - \u00ff ] / ;
128+
129+ function assertValidHeaderValue ( name , value , httpValidation ) {
130+ if ( name === ':path' && INVALID_PATH_REGEX . test ( value ) ) {
131+ throw new ERR_UNESCAPED_CHARACTERS ( 'Request path' ) ;
132+ }
133+
134+ if ( httpValidation === 'insecure' ) {
135+ return ;
136+ }
137+
138+ const lenient = httpValidation === 'relaxed' ;
139+ if ( checkInvalidHeaderChar ( value , lenient ) ) {
140+ throw new ERR_HTTP2_INVALID_HEADER_VALUE ( value , name ) ;
141+ }
142+ }
143+
123144// This set contains headers that are permitted to have only a single
124145// value. Multiple instances must not be specified.
125146const kSingleValueFields = new SafeSet ( [
@@ -692,6 +713,7 @@ function prepareRequestHeadersArray(headers, session) {
692713 rawHeaders ,
693714 assertValidPseudoHeader ,
694715 session [ kStrictSingleValueFields ] ,
716+ session [ kHttpValidation ] ?? 'strict' ,
695717 ) ;
696718
697719 return {
@@ -737,6 +759,7 @@ function prepareRequestHeadersObject(headers, session) {
737759 headersObject ,
738760 assertValidPseudoHeader ,
739761 session [ kStrictSingleValueFields ] ,
762+ session [ kHttpValidation ] ?? 'strict' ,
740763 ) ;
741764
742765 return {
@@ -765,7 +788,9 @@ const kNoHeaderFlags = StringFromCharCode(NGHTTP2_NV_FLAG_NONE);
765788 */
766789function buildNgHeaderString ( arrayOrMap ,
767790 validatePseudoHeaderValue ,
768- strictSingleValueFields ) {
791+ strictSingleValueFields ,
792+ httpValidation ) {
793+ const validateHeaderValues = httpValidation !== undefined ;
769794 let headers = '' ;
770795 let pseudoHeaders = '' ;
771796 let count = 0 ;
@@ -806,6 +831,8 @@ function buildNgHeaderString(arrayOrMap,
806831 const err = validatePseudoHeaderValue ( key ) ;
807832 if ( err !== undefined )
808833 throw err ;
834+ if ( validateHeaderValues )
835+ assertValidHeaderValue ( key , value , httpValidation ) ;
809836 pseudoHeaders += `${ key } \0${ value } \0${ flags } ` ;
810837 count ++ ;
811838 return ;
@@ -819,11 +846,15 @@ function buildNgHeaderString(arrayOrMap,
819846 if ( isArray ) {
820847 for ( let j = 0 ; j < value . length ; ++ j ) {
821848 const val = String ( value [ j ] ) ;
849+ if ( validateHeaderValues )
850+ assertValidHeaderValue ( key , val , httpValidation ) ;
822851 headers += `${ key } \0${ val } \0${ flags } ` ;
823852 }
824853 count += value . length ;
825854 return ;
826855 }
856+ if ( validateHeaderValues )
857+ assertValidHeaderValue ( key , value , httpValidation ) ;
827858 headers += `${ key } \0${ value } \0${ flags } ` ;
828859 count ++ ;
829860 }
@@ -982,6 +1013,7 @@ module.exports = {
9821013 isPayloadMeaningless,
9831014 kAuthority,
9841015 kSensitiveHeaders,
1016+ kHttpValidation,
9851017 kStrictSingleValueFields,
9861018 kSocket,
9871019 kProtocol,
0 commit comments