@@ -11,45 +11,6 @@ internal static partial class HttpKnownHeaderNames
1111        private  const  string  Gzip  =  "gzip" ; 
1212        private  const  string  Deflate  =  "deflate" ; 
1313
14-         /// <summary> 
15-         /// Gets a known header name string from a matching char[] array segment, using a case-sensitive 
16-         /// ordinal comparison. Used to avoid allocating new strings for known header names. 
17-         /// </summary> 
18-         public  static bool  TryGetHeaderName ( char [ ]  array ,  int  startIndex ,  int  length ,  [ NotNullWhen ( true ) ]  out  string ?  name ) 
19-         { 
20-             CharArrayHelpers . DebugAssertArrayInputs ( array ,  startIndex ,  length ) ; 
21- 
22-             return  TryGetHeaderName ( 
23-                 array ,  startIndex ,  length , 
24-                 static  ( arr ,  index )  =>  arr [ index ] , 
25-                 static  ( known ,  arr ,  start ,  len )  =>  known . AsSpan ( ) . SequenceEqual ( arr . AsSpan ( start ,  len ) ) , 
26-                 out  name ) ; 
27-         } 
28- 
29-         /// <summary> 
30-         /// Gets a known header name string from a matching IntPtr buffer, using a case-sensitive 
31-         /// ordinal comparison. Used to avoid allocating new strings for known header names. 
32-         /// </summary> 
33-         public  static unsafe  bool  TryGetHeaderName ( IntPtr  buffer ,  int  length ,  out  string ?  name ) 
34-         { 
35-             Debug . Assert ( length  >=  0 ) ; 
36- 
37-             if  ( buffer  ==  IntPtr . Zero ) 
38-             { 
39-                 name  =  null ; 
40-                 return  false ; 
41-             } 
42- 
43-             // We always pass 0 for the startIndex, as buffer should already point to the start. 
44-             const  int  startIndex  =  0 ; 
45- 
46-             return  TryGetHeaderName ( 
47-                 buffer ,  startIndex ,  length , 
48-                 static  ( buf ,  index )  =>  ( char ) ( ( byte * ) buf ) [ index ] , 
49-                 static  ( known ,  buf ,  start ,  len )  =>  EqualsOrdinal ( known ,  buf ,  len ) , 
50-                 out  name ) ; 
51-         } 
52- 
5314        public  static string  GetHeaderValue ( string  name ,  ReadOnlySpan < char >  value ) 
5415        { 
5516            Debug . Assert ( name  !=  null ) ; 
@@ -80,18 +41,12 @@ public static string GetHeaderValue(string name, ReadOnlySpan<char> value)
8041            return  value . ToString ( ) ; 
8142        } 
8243
83-         private   static   bool   TryGetHeaderName < T > ( 
84-              T   key ,   int   startIndex ,   int   length , 
85-              Func < T ,   int ,   char >   charAt , 
86-              Func < string ,   T ,   int ,   int ,   bool >   equals , 
87-              [ NotNullWhen ( true ) ]  out  string ?  name ) 
44+         /// <summary> 
45+         /// Gets a known header name string from a matching span segment, using a case-sensitive 
46+         /// ordinal comparison. Used to avoid allocating new strings for known header names. 
47+         /// </summary> 
48+         public   static   bool   TryGetHeaderName ( ReadOnlySpan < char >   nameSpan ,  [ NotNullWhen ( true ) ]  out  string ?  name ) 
8849        { 
89-             Debug . Assert ( key  !=  null ) ; 
90-             Debug . Assert ( startIndex  >=  0 ) ; 
91-             Debug . Assert ( length  >=  0 ) ; 
92-             Debug . Assert ( charAt  !=  null ) ; 
93-             Debug . Assert ( equals  !=  null ) ; 
94- 
9550            // When adding a new constant, add it to HttpKnownHeaderNames.cs as well. 
9651
9752            // The lookup works as follows: first switch on the length of the passed-in key. 
@@ -112,13 +67,13 @@ private static bool TryGetHeaderName<T>(
11267
11368            string  potentialHeader ; 
11469
115-             switch  ( length ) 
70+             switch  ( nameSpan . Length ) 
11671            { 
11772                case  2 : 
11873                    potentialHeader  =  TE ;  goto  TryMatch ;  // TE 
11974
12075                case  3 : 
121-                     switch  ( charAt ( key ,   startIndex ) ) 
76+                     switch  ( nameSpan [ 0 ] ) 
12277                    { 
12378                        case  'A' :  potentialHeader  =  Age ;  goto  TryMatch ;  // [A]ge 
12479                        case  'P' :  potentialHeader  =  P3P ;  goto  TryMatch ;  // [P]3P 
@@ -128,7 +83,7 @@ private static bool TryGetHeaderName<T>(
12883                    break ; 
12984
13085                case  4 : 
131-                     switch  ( charAt ( key ,   startIndex ) ) 
86+                     switch  ( nameSpan [ 0 ] ) 
13287                    { 
13388                        case  'D' :  potentialHeader  =  Date ;  goto  TryMatch ;  // [D]ate 
13489                        case  'E' :  potentialHeader  =  ETag ;  goto  TryMatch ;  // [E]Tag 
@@ -140,15 +95,15 @@ private static bool TryGetHeaderName<T>(
14095                    break ; 
14196
14297                case  5 : 
143-                     switch  ( charAt ( key ,   startIndex ) ) 
98+                     switch  ( nameSpan [ 0 ] ) 
14499                    { 
145100                        case  'A' :  potentialHeader  =  Allow ;  goto  TryMatch ;  // [A]llow 
146101                        case  'R' :  potentialHeader  =  Range ;  goto  TryMatch ;  // [R]ange 
147102                    } 
148103                    break ; 
149104
150105                case  6 : 
151-                     switch  ( charAt ( key ,   startIndex ) ) 
106+                     switch  ( nameSpan [ 0 ] ) 
152107                    { 
153108                        case  'A' :  potentialHeader  =  Accept ;  goto  TryMatch ;  // [A]ccept 
154109                        case  'C' :  potentialHeader  =  Cookie ;  goto  TryMatch ;  // [C]ookie 
@@ -160,7 +115,7 @@ private static bool TryGetHeaderName<T>(
160115                    break ; 
161116
162117                case  7 : 
163-                     switch  ( charAt ( key ,   startIndex ) ) 
118+                     switch  ( nameSpan [ 0 ] ) 
164119                    { 
165120                        case  'A' :  potentialHeader  =  AltSvc ;  goto  TryMatch ;   // [A]lt-Svc 
166121                        case  'C' :  potentialHeader  =  Cookie2 ;  goto  TryMatch ;  // [C]ookie2 
@@ -173,7 +128,7 @@ private static bool TryGetHeaderName<T>(
173128                    break ; 
174129
175130                case  8 : 
176-                     switch  ( charAt ( key ,   startIndex   +   3 ) ) 
131+                     switch  ( nameSpan [ 3 ] ) 
177132                    { 
178133                        case  'M' :  potentialHeader  =  IfMatch ;  goto  TryMatch ;   // If-[M]atch 
179134                        case  'R' :  potentialHeader  =  IfRange ;  goto  TryMatch ;   // If-[R]ange 
@@ -182,7 +137,7 @@ private static bool TryGetHeaderName<T>(
182137                    break ; 
183138
184139                case  10 : 
185-                     switch  ( charAt ( key ,   startIndex ) ) 
140+                     switch  ( nameSpan [ 0 ] ) 
186141                    { 
187142                        case  'C' :  potentialHeader  =  Connection ;  goto  TryMatch ;  // [C]onnection 
188143                        case  'K' :  potentialHeader  =  KeepAlive ;  goto  TryMatch ;   // [K]eep-Alive 
@@ -192,7 +147,7 @@ private static bool TryGetHeaderName<T>(
192147                    break ; 
193148
194149                case  11 : 
195-                     switch  ( charAt ( key ,   startIndex ) ) 
150+                     switch  ( nameSpan [ 0 ] ) 
196151                    { 
197152                        case  'C' :  potentialHeader  =  ContentMD5 ;  goto  TryMatch ;  // [C]ontent-MD5 
198153                        case  'R' :  potentialHeader  =  RetryAfter ;  goto  TryMatch ;  // [R]etry-After 
@@ -201,7 +156,7 @@ private static bool TryGetHeaderName<T>(
201156                    break ; 
202157
203158                case  12 : 
204-                     switch  ( charAt ( key ,   startIndex   +   2 ) ) 
159+                     switch  ( nameSpan [ 2 ] ) 
205160                    { 
206161                        case  'c' :  potentialHeader  =  AcceptPatch ;  goto  TryMatch ;  // Ac[c]ept-Patch 
207162                        case  'n' :  potentialHeader  =  ContentType ;  goto  TryMatch ;  // Co[n]tent-Type 
@@ -213,7 +168,7 @@ private static bool TryGetHeaderName<T>(
213168                    break ; 
214169
215170                case  13 : 
216-                     switch  ( charAt ( key ,   startIndex   +   6 ) ) 
171+                     switch  ( nameSpan [ 6 ] ) 
217172                    { 
218173                        case  '-' :  potentialHeader  =  AcceptRanges ;  goto  TryMatch ;   // Accept[-]Ranges 
219174                        case  'i' :  potentialHeader  =  Authorization ;  goto  TryMatch ;  // Author[i]zation 
@@ -225,15 +180,15 @@ private static bool TryGetHeaderName<T>(
225180                    break ; 
226181
227182                case  14 : 
228-                     switch  ( charAt ( key ,   startIndex ) ) 
183+                     switch  ( nameSpan [ 0 ] ) 
229184                    { 
230185                        case  'A' :  potentialHeader  =  AcceptCharset ;  goto  TryMatch ;  // [A]ccept-Charset 
231186                        case  'C' :  potentialHeader  =  ContentLength ;  goto  TryMatch ;  // [C]ontent-Length 
232187                    } 
233188                    break ; 
234189
235190                case  15 : 
236-                     switch  ( charAt ( key ,   startIndex   +   7 ) ) 
191+                     switch  ( nameSpan [ 7 ] ) 
237192                    { 
238193                        case  '-' :  potentialHeader  =  XFrameOptions ;  goto  TryMatch ;   // X-Frame[-]Options 
239194                        case  'm' :  potentialHeader  =  XUACompatible ;  goto  TryMatch ;   // X-UA-Co[m]patible 
@@ -244,7 +199,7 @@ private static bool TryGetHeaderName<T>(
244199                    break ; 
245200
246201                case  16 : 
247-                     switch  ( charAt ( key ,   startIndex   +   11 ) ) 
202+                     switch  ( nameSpan [ 11 ] ) 
248203                    { 
249204                        case  'o' :  potentialHeader  =  ContentEncoding ;  goto  TryMatch ;  // Content-Enc[o]ding 
250205                        case  'g' :  potentialHeader  =  ContentLanguage ;  goto  TryMatch ;  // Content-Lan[g]uage 
@@ -256,7 +211,7 @@ private static bool TryGetHeaderName<T>(
256211                    break ; 
257212
258213                case  17 : 
259-                     switch  ( charAt ( key ,   startIndex ) ) 
214+                     switch  ( nameSpan [ 0 ] ) 
260215                    { 
261216                        case  'I' :  potentialHeader  =  IfModifiedSince ;  goto  TryMatch ;   // [I]f-Modified-Since 
262217                        case  'S' :  potentialHeader  =  SecWebSocketKey ;  goto  TryMatch ;   // [S]ec-WebSocket-Key 
@@ -265,15 +220,15 @@ private static bool TryGetHeaderName<T>(
265220                    break ; 
266221
267222                case  18 : 
268-                     switch  ( charAt ( key ,   startIndex ) ) 
223+                     switch  ( nameSpan [ 0 ] ) 
269224                    { 
270225                        case  'P' :  potentialHeader  =  ProxyAuthenticate ;  goto  TryMatch ;  // [P]roxy-Authenticate 
271226                        case  'X' :  potentialHeader  =  XContentDuration ;  goto  TryMatch ;   // [X]-Content-Duration 
272227                    } 
273228                    break ; 
274229
275230                case  19 : 
276-                     switch  ( charAt ( key ,   startIndex ) ) 
231+                     switch  ( nameSpan [ 0 ] ) 
277232                    { 
278233                        case  'C' :  potentialHeader  =  ContentDisposition ;  goto  TryMatch ;  // [C]ontent-Disposition 
279234                        case  'I' :  potentialHeader  =  IfUnmodifiedSince ;  goto  TryMatch ;   // [I]f-Unmodified-Since 
@@ -288,7 +243,7 @@ private static bool TryGetHeaderName<T>(
288243                    potentialHeader  =  SecWebSocketVersion ;  goto  TryMatch ;  // Sec-WebSocket-Version 
289244
290245                case  22 : 
291-                     switch  ( charAt ( key ,   startIndex ) ) 
246+                     switch  ( nameSpan [ 0 ] ) 
292247                    { 
293248                        case  'A' :  potentialHeader  =  AccessControlMaxAge ;  goto  TryMatch ;   // [A]ccess-Control-Max-Age 
294249                        case  'S' :  potentialHeader  =  SecWebSocketProtocol ;  goto  TryMatch ;  // [S]ec-WebSocket-Protocol 
@@ -303,7 +258,7 @@ private static bool TryGetHeaderName<T>(
303258                    potentialHeader  =  SecWebSocketExtensions ;  goto  TryMatch ;  // Sec-WebSocket-Extensions 
304259
305260                case  25 : 
306-                     switch  ( charAt ( key ,   startIndex ) ) 
261+                     switch  ( nameSpan [ 0 ] ) 
307262                    { 
308263                        case  'S' :  potentialHeader  =  StrictTransportSecurity ;  goto  TryMatch ;  // [S]trict-Transport-Security 
309264                        case  'U' :  potentialHeader  =  UpgradeInsecureRequests ;  goto  TryMatch ;  // [U]pgrade-Insecure-Requests 
@@ -314,7 +269,7 @@ private static bool TryGetHeaderName<T>(
314269                    potentialHeader  =  AccessControlAllowOrigin ;  goto  TryMatch ;  // Access-Control-Allow-Origin 
315270
316271                case  28 : 
317-                     switch  ( charAt ( key ,   startIndex   +   21 ) ) 
272+                     switch  ( nameSpan [ 21 ] ) 
318273                    { 
319274                        case  'H' :  potentialHeader  =  AccessControlAllowHeaders ;  goto  TryMatch ;  // Access-Control-Allow-[H]eaders 
320275                        case  'M' :  potentialHeader  =  AccessControlAllowMethods ;  goto  TryMatch ;  // Access-Control-Allow-[M]ethods 
@@ -331,57 +286,17 @@ private static bool TryGetHeaderName<T>(
331286            name  =  null ; 
332287            return  false ; 
333288
334-              TryMatch : 
289+         TryMatch : 
335290            Debug . Assert ( potentialHeader  !=  null ) ; 
336-             return  TryMatch ( potentialHeader ,  key ,  startIndex ,  length ,  equals ,  out  name ) ; 
337-         } 
338- 
339-         /// <summary> 
340-         /// Returns true if <paramref name="known"/> matches the <paramref name="key"/> char[] array segment, 
341-         /// using an ordinal comparison. 
342-         /// </summary> 
343-         private  static bool  TryMatch < T > ( string  known ,  T  key ,  int  startIndex ,  int  length ,  Func < string ,  T ,  int ,  int ,  bool >  equals ,  [ NotNullWhen ( true ) ]  out  string ?  name ) 
344-         { 
345-             Debug . Assert ( known  !=  null ) ; 
346-             Debug . Assert ( known . Length  >  0 ) ; 
347-             Debug . Assert ( startIndex  >=  0 ) ; 
348-             Debug . Assert ( length  >  0 ) ; 
349-             Debug . Assert ( equals  !=  null ) ; 
350- 
351-             // The lengths should be equal because this method is only called 
352-             // from within a "switch (length) { ... }". 
353-             Debug . Assert ( known . Length  ==  length ) ; 
354291
355-             if  ( equals ( known ,   key ,   startIndex ,   length ) ) 
292+             if  ( nameSpan . SequenceEqual ( potentialHeader . AsSpan ( ) ) ) 
356293            { 
357-                 name  =  known ; 
294+                 name  =  potentialHeader ; 
358295                return  true ; 
359296            } 
360297
361298            name  =  null ; 
362299            return  false ; 
363300        } 
364- 
365-         private  static unsafe  bool  EqualsOrdinal ( string  left ,  IntPtr  right ,  int  rightLength ) 
366-         { 
367-             Debug . Assert ( left  !=  null ) ; 
368-             Debug . Assert ( right  !=  IntPtr . Zero ) ; 
369-             Debug . Assert ( rightLength  >  0 ) ; 
370- 
371-             // At this point the lengths have already been determined to be equal. 
372-             Debug . Assert ( left . Length  ==  rightLength ) ; 
373- 
374-             byte *  pRight  =  ( byte * ) right ; 
375- 
376-             for  ( int  i  =  0 ;  i  <  left . Length ;  i ++ ) 
377-             { 
378-                 if  ( left [ i ]  !=  pRight [ i ] ) 
379-                 { 
380-                     return  false ; 
381-                 } 
382-             } 
383- 
384-             return  true ; 
385-         } 
386301    } 
387302} 
0 commit comments