@@ -3,6 +3,7 @@ import nodeCommon from '_http_common';
33import IResourceHeaders from '@secret-agent/core-interfaces/IResourceHeaders' ;
44import Log from '@secret-agent/commons/Logger' ;
55import * as http from 'http' ;
6+ import http2 from 'http2' ;
67import { parseRawHeaders } from '../lib/Utils' ;
78import IMitmRequestContext from '../interfaces/IMitmRequestContext' ;
89
@@ -93,7 +94,11 @@ export default class HeadersHandler {
9394 if ( nodeCommon . _checkInvalidHeaderChar ( value ) ) continue ;
9495
9596 if ( Array . isArray ( value ) ) {
96- headers [ canonizedKey ] = [ ...value ] ;
97+ if ( singleValueHttp2Headers . has ( key ) ) {
98+ headers [ canonizedKey ] = value [ 0 ] ;
99+ } else {
100+ headers [ canonizedKey ] = [ ...value ] ;
101+ }
97102 } else {
98103 headers [ canonizedKey ] = value ;
99104 }
@@ -139,6 +144,10 @@ export default class HeadersHandler {
139144 if ( stripHttp1HeadersForH2 . includes ( lowerKey ) ) {
140145 delete ctx . requestHeaders [ key ] ;
141146 }
147+ if ( singleValueHttp2Headers . has ( lowerKey ) ) {
148+ const value = ctx . requestHeaders [ key ] ;
149+ if ( Array . isArray ( value ) && value . length ) ctx . requestHeaders [ key ] = value [ 0 ] ;
150+ }
142151 }
143152 }
144153
@@ -157,11 +166,58 @@ export default class HeadersHandler {
157166}
158167
159168const stripHttp1HeadersForH2 = [
160- 'connection' ,
169+ http2 . constants . HTTP2_HEADER_CONNECTION ,
170+ http2 . constants . HTTP2_HEADER_UPGRADE ,
171+ http2 . constants . HTTP2_HEADER_HTTP2_SETTINGS ,
172+ http2 . constants . HTTP2_HEADER_KEEP_ALIVE ,
173+ http2 . constants . HTTP2_HEADER_PROXY_CONNECTION ,
174+ http2 . constants . HTTP2_HEADER_TRANSFER_ENCODING ,
161175 'host' ,
162- 'keep-alive' ,
163- 'transfer-encoding' ,
164176 'via' ,
165- 'proxy-connection' ,
166177 'forwarded' ,
167178] ;
179+ // This set contains headers that are permitted to have only a single
180+ // value. Multiple instances must not be specified.
181+ // NOTE: some are not exposed in constants, so we're putting strings in place
182+ const singleValueHttp2Headers = new Set ( [
183+ http2 . constants . HTTP2_HEADER_STATUS ,
184+ http2 . constants . HTTP2_HEADER_METHOD ,
185+ http2 . constants . HTTP2_HEADER_AUTHORITY ,
186+ http2 . constants . HTTP2_HEADER_SCHEME ,
187+ http2 . constants . HTTP2_HEADER_PATH ,
188+ ':protocol' ,
189+ 'access-control-allow-credentials' ,
190+ 'access-control-max-age' ,
191+ 'access-control-request-method' ,
192+ http2 . constants . HTTP2_HEADER_AGE ,
193+ http2 . constants . HTTP2_HEADER_AUTHORIZATION ,
194+ http2 . constants . HTTP2_HEADER_CONTENT_ENCODING ,
195+ http2 . constants . HTTP2_HEADER_CONTENT_LANGUAGE ,
196+ http2 . constants . HTTP2_HEADER_CONTENT_LENGTH ,
197+ http2 . constants . HTTP2_HEADER_CONTENT_LOCATION ,
198+ http2 . constants . HTTP2_HEADER_CONTENT_MD5 ,
199+ http2 . constants . HTTP2_HEADER_CONTENT_RANGE ,
200+ http2 . constants . HTTP2_HEADER_CONTENT_TYPE ,
201+ http2 . constants . HTTP2_HEADER_DATE ,
202+ 'dnt' ,
203+ http2 . constants . HTTP2_HEADER_ETAG ,
204+ http2 . constants . HTTP2_HEADER_EXPIRES ,
205+ http2 . constants . HTTP2_HEADER_FROM ,
206+ http2 . constants . HTTP2_HEADER_HOST ,
207+ http2 . constants . HTTP2_HEADER_IF_MATCH ,
208+ http2 . constants . HTTP2_HEADER_IF_MODIFIED_SINCE ,
209+ http2 . constants . HTTP2_HEADER_IF_NONE_MATCH ,
210+ http2 . constants . HTTP2_HEADER_IF_RANGE ,
211+ http2 . constants . HTTP2_HEADER_IF_UNMODIFIED_SINCE ,
212+ http2 . constants . HTTP2_HEADER_LAST_MODIFIED ,
213+ http2 . constants . HTTP2_HEADER_LOCATION ,
214+ http2 . constants . HTTP2_HEADER_MAX_FORWARDS ,
215+ http2 . constants . HTTP2_HEADER_PROXY_AUTHORIZATION ,
216+ http2 . constants . HTTP2_HEADER_RANGE ,
217+ http2 . constants . HTTP2_HEADER_REFERER ,
218+ http2 . constants . HTTP2_HEADER_RETRY_AFTER ,
219+ 'tk' ,
220+ 'upgrade-insecure-requests' ,
221+ http2 . constants . HTTP2_HEADER_USER_AGENT ,
222+ 'x-content-type-options' ,
223+ ] ) ;
0 commit comments