@@ -232,52 +232,65 @@ exports.httpSocketSetup = httpSocketSetup;
232232 * per the rules defined in RFC 7230
233233 * See https://tools.ietf.org/html/rfc7230#section-3.2.6
234234 *
235+ * Allowed characters in an HTTP token:
236+ * ^_`a-z 94-122
237+ * A-Z 65-90
238+ * - 45
239+ * 0-9 48-57
240+ * ! 33
241+ * #$%&' 35-39
242+ * *+ 42-43
243+ * . 46
244+ * | 124
245+ * ~ 126
246+ *
235247 * This implementation of checkIsHttpToken() loops over the string instead of
236248 * using a regular expression since the former is up to 180% faster with v8 4.9
237249 * depending on the string length (the shorter the string, the larger the
238250 * performance difference)
251+ *
252+ * Additionally, checkIsHttpToken() is currently designed to be inlinable by v8,
253+ * so take care when making changes to the implementation so that the source
254+ * code size does not exceed v8's default max_inlined_source_size setting.
239255 **/
256+ function isValidTokenChar ( ch ) {
257+ if ( ch >= 94 && ch <= 122 )
258+ return true ;
259+ if ( ch >= 65 && ch <= 90 )
260+ return true ;
261+ if ( ch === 45 )
262+ return true ;
263+ if ( ch >= 48 && ch <= 57 )
264+ return true ;
265+ if ( ch === 34 || ch === 40 || ch === 41 || ch === 44 )
266+ return false ;
267+ if ( ch >= 33 && ch <= 46 )
268+ return true ;
269+ if ( ch === 124 || ch === 126 )
270+ return true ;
271+ return false ;
272+ }
240273function checkIsHttpToken ( val ) {
241274 if ( typeof val !== 'string' || val . length === 0 )
242275 return false ;
243-
244- for ( var i = 0 , len = val . length ; i < len ; i ++ ) {
245- var ch = val . charCodeAt ( i ) ;
246-
247- if ( ch >= 65 && ch <= 90 ) // A-Z
248- continue ;
249-
250- if ( ch >= 97 && ch <= 122 ) // a-z
251- continue ;
252-
253- // ^ => 94
254- // _ => 95
255- // ` => 96
256- // | => 124
257- // ~ => 126
258- if ( ch === 94 || ch === 95 || ch === 96 || ch === 124 || ch === 126 )
259- continue ;
260-
261- if ( ch >= 48 && ch <= 57 ) // 0-9
262- continue ;
263-
264- // ! => 33
265- // # => 35
266- // $ => 36
267- // % => 37
268- // & => 38
269- // ' => 39
270- // * => 42
271- // + => 43
272- // - => 45
273- // . => 46
274- if ( ch >= 33 && ch <= 46 ) {
275- if ( ch === 34 || ch === 40 || ch === 41 || ch === 44 )
276+ if ( ! isValidTokenChar ( val . charCodeAt ( 0 ) ) )
277+ return false ;
278+ const len = val . length ;
279+ if ( len > 1 ) {
280+ if ( ! isValidTokenChar ( val . charCodeAt ( 1 ) ) )
281+ return false ;
282+ if ( len > 2 ) {
283+ if ( ! isValidTokenChar ( val . charCodeAt ( 2 ) ) )
276284 return false ;
277- continue ;
285+ if ( len > 3 ) {
286+ if ( ! isValidTokenChar ( val . charCodeAt ( 3 ) ) )
287+ return false ;
288+ for ( var i = 4 ; i < len ; i ++ ) {
289+ if ( ! isValidTokenChar ( val . charCodeAt ( i ) ) )
290+ return false ;
291+ }
292+ }
278293 }
279-
280- return false ;
281294 }
282295 return true ;
283296}
0 commit comments