@@ -119,6 +119,146 @@ function _addHeaderLines(headers, n) {
119
119
}
120
120
121
121
122
+ // This function is used to help avoid the lowercasing of a field name if it
123
+ // matches a 'traditional cased' version of a field name. It then returns the
124
+ // lowercased name to both avoid calling toLowerCase() a second time and to
125
+ // indicate whether the field was a 'no duplicates' field. If a field is not a
126
+ // 'no duplicates' field, a `0` byte is prepended as a flag. The one exception
127
+ // to this is the Set-Cookie header which is indicated by a `1` byte flag, since
128
+ // it is an 'array' field and thus is treated differently in _addHeaderLines().
129
+ // TODO: perhaps http_parser could be returning both raw and lowercased versions
130
+ // of known header names to avoid us having to call toLowerCase() for those
131
+ // headers.
132
+ /* eslint-disable max-len */
133
+ // 'array' header list is taken from:
134
+ // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
135
+ /* eslint-enable max-len */
136
+ function matchKnownFields ( field ) {
137
+ var low = false ;
138
+ while ( true ) {
139
+ switch ( field ) {
140
+ case 'Content-Type' :
141
+ case 'content-type' :
142
+ return 'content-type' ;
143
+ case 'Content-Length' :
144
+ case 'content-length' :
145
+ return 'content-length' ;
146
+ case 'User-Agent' :
147
+ case 'user-agent' :
148
+ return 'user-agent' ;
149
+ case 'Referer' :
150
+ case 'referer' :
151
+ return 'referer' ;
152
+ case 'Host' :
153
+ case 'host' :
154
+ return 'host' ;
155
+ case 'Authorization' :
156
+ case 'authorization' :
157
+ return 'authorization' ;
158
+ case 'Proxy-Authorization' :
159
+ case 'proxy-authorization' :
160
+ return 'proxy-authorization' ;
161
+ case 'If-Modified-Since' :
162
+ case 'if-modified-since' :
163
+ return 'if-modified-since' ;
164
+ case 'If-Unmodified-Since' :
165
+ case 'if-unmodified-since' :
166
+ return 'if-unmodified-since' ;
167
+ case 'From' :
168
+ case 'from' :
169
+ return 'from' ;
170
+ case 'Location' :
171
+ case 'location' :
172
+ return 'location' ;
173
+ case 'Max-Forwards' :
174
+ case 'max-forwards' :
175
+ return 'max-forwards' ;
176
+ case 'Retry-After' :
177
+ case 'retry-after' :
178
+ return 'retry-after' ;
179
+ case 'ETag' :
180
+ case 'etag' :
181
+ return 'etag' ;
182
+ case 'Last-Modified' :
183
+ case 'last-modified' :
184
+ return 'last-modified' ;
185
+ case 'Server' :
186
+ case 'server' :
187
+ return 'server' ;
188
+ case 'Age' :
189
+ case 'age' :
190
+ return 'age' ;
191
+ case 'Expires' :
192
+ case 'expires' :
193
+ return 'expires' ;
194
+ case 'Set-Cookie' :
195
+ case 'set-cookie' :
196
+ return '\u0001' ;
197
+ // The fields below are not used in _addHeaderLine(), but they are common
198
+ // headers where we can avoid toLowerCase() if the mixed or lower case
199
+ // versions match the first time through.
200
+ case 'Transfer-Encoding' :
201
+ case 'transfer-encoding' :
202
+ return '\u0000transfer-encoding' ;
203
+ case 'Date' :
204
+ case 'date' :
205
+ return '\u0000date' ;
206
+ case 'Connection' :
207
+ case 'connection' :
208
+ return '\u0000connection' ;
209
+ case 'Cache-Control' :
210
+ case 'cache-control' :
211
+ return '\u0000cache-control' ;
212
+ case 'Vary' :
213
+ case 'vary' :
214
+ return '\u0000vary' ;
215
+ case 'Content-Encoding' :
216
+ case 'content-encoding' :
217
+ return '\u0000content-encoding' ;
218
+ case 'Cookie' :
219
+ case 'cookie' :
220
+ return '\u0000cookie' ;
221
+ case 'Origin' :
222
+ case 'origin' :
223
+ return '\u0000origin' ;
224
+ case 'Upgrade' :
225
+ case 'upgrade' :
226
+ return '\u0000upgrade' ;
227
+ case 'Expect' :
228
+ case 'expect' :
229
+ return '\u0000expect' ;
230
+ case 'If-Match' :
231
+ case 'if-match' :
232
+ return '\u0000if-match' ;
233
+ case 'If-None-Match' :
234
+ case 'if-none-match' :
235
+ return '\u0000if-none-match' ;
236
+ case 'Accept' :
237
+ case 'accept' :
238
+ return '\u0000accept' ;
239
+ case 'Accept-Encoding' :
240
+ case 'accept-encoding' :
241
+ return '\u0000accept-encoding' ;
242
+ case 'Accept-Language' :
243
+ case 'accept-language' :
244
+ return '\u0000accept-language' ;
245
+ case 'X-Forwarded-For' :
246
+ case 'x-forwarded-for' :
247
+ return '\u0000x-forwarded-for' ;
248
+ case 'X-Forwarded-Host' :
249
+ case 'x-forwarded-host' :
250
+ return '\u0000x-forwarded-host' ;
251
+ case 'X-Forwarded-Proto' :
252
+ case 'x-forwarded-proto' :
253
+ return '\u0000x-forwarded-proto' ;
254
+ default :
255
+ if ( low )
256
+ return '\u0000' + field ;
257
+ field = field . toLowerCase ( ) ;
258
+ low = true ;
259
+ }
260
+ }
261
+ }
122
262
// Add the given (field, value) pair to the message
123
263
//
124
264
// Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
@@ -128,51 +268,27 @@ function _addHeaderLines(headers, n) {
128
268
// always joined.
129
269
IncomingMessage . prototype . _addHeaderLine = _addHeaderLine ;
130
270
function _addHeaderLine ( field , value , dest ) {
131
- field = field . toLowerCase ( ) ;
132
- switch ( field ) {
133
- // Array headers:
134
- case 'set-cookie' :
135
- if ( dest [ field ] !== undefined ) {
136
- dest [ field ] . push ( value ) ;
137
- } else {
138
- dest [ field ] = [ value ] ;
139
- }
140
- break ;
141
-
142
- /* eslint-disable max-len */
143
- // list is taken from:
144
- // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
145
- /* eslint-enable max-len */
146
- case 'content-type' :
147
- case 'content-length' :
148
- case 'user-agent' :
149
- case 'referer' :
150
- case 'host' :
151
- case 'authorization' :
152
- case 'proxy-authorization' :
153
- case 'if-modified-since' :
154
- case 'if-unmodified-since' :
155
- case 'from' :
156
- case 'location' :
157
- case 'max-forwards' :
158
- case 'retry-after' :
159
- case 'etag' :
160
- case 'last-modified' :
161
- case 'server' :
162
- case 'age' :
163
- case 'expires' :
164
- // drop duplicates
165
- if ( dest [ field ] === undefined )
166
- dest [ field ] = value ;
167
- break ;
168
-
169
- default :
170
- // make comma-separated list
171
- if ( typeof dest [ field ] === 'string' ) {
172
- dest [ field ] += ', ' + value ;
173
- } else {
174
- dest [ field ] = value ;
175
- }
271
+ field = matchKnownFields ( field ) ;
272
+ var flag = field . charCodeAt ( 0 ) ;
273
+ if ( flag === 0 ) {
274
+ field = field . slice ( 1 ) ;
275
+ // Make comma-separated list
276
+ if ( typeof dest [ field ] === 'string' ) {
277
+ dest [ field ] += ', ' + value ;
278
+ } else {
279
+ dest [ field ] = value ;
280
+ }
281
+ } else if ( flag === 1 ) {
282
+ // Array header -- only Set-Cookie at the moment
283
+ if ( dest [ 'set-cookie' ] !== undefined ) {
284
+ dest [ 'set-cookie' ] . push ( value ) ;
285
+ } else {
286
+ dest [ 'set-cookie' ] = [ value ] ;
287
+ }
288
+ } else {
289
+ // Drop duplicates
290
+ if ( dest [ field ] === undefined )
291
+ dest [ field ] = value ;
176
292
}
177
293
}
178
294
0 commit comments