2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
- using System . Buffers ;
6
5
using System . Collections . Generic ;
7
6
using System . Runtime . CompilerServices ;
8
- using System . Runtime . InteropServices ;
9
- using System . Runtime . Intrinsics ;
10
- using System . Runtime . Intrinsics . X86 ;
11
7
using Microsoft . AspNetCore . Internal ;
8
+ using Microsoft . AspNetCore . WebUtilities ;
12
9
using Microsoft . Extensions . Primitives ;
13
10
14
11
namespace Microsoft . AspNetCore . Http . Features
@@ -19,7 +16,7 @@ namespace Microsoft.AspNetCore.Http.Features
19
16
public class QueryFeature : IQueryFeature
20
17
{
21
18
// Lambda hoisted to static readonly field to improve inlining https://github.com/dotnet/roslyn/issues/13624
22
- private readonly static Func < IFeatureCollection , IHttpRequestFeature ? > _nullRequestFeature = f => null ;
19
+ private static readonly Func < IFeatureCollection , IHttpRequestFeature ? > _nullRequestFeature = f => null ;
23
20
24
21
private FeatureReferences < IHttpRequestFeature > _features ;
25
22
@@ -113,48 +110,10 @@ public IQueryCollection Query
113
110
}
114
111
115
112
var accumulator = new KvpAccumulator ( ) ;
116
- var query = queryString . AsSpan ( ) ;
117
-
118
- if ( query [ 0 ] == '?' )
113
+ var enumerable = new QueryStringEnumerable ( queryString . AsSpan ( ) ) ;
114
+ foreach ( var pair in enumerable )
119
115
{
120
- query = query [ 1 ..] ;
121
- }
122
-
123
- while ( ! query . IsEmpty )
124
- {
125
- var delimiterIndex = query . IndexOf ( '&' ) ;
126
-
127
- var querySegment = delimiterIndex >= 0
128
- ? query . Slice ( 0 , delimiterIndex )
129
- : query ;
130
-
131
- var equalIndex = querySegment . IndexOf ( '=' ) ;
132
-
133
- if ( equalIndex >= 0 )
134
- {
135
- var name = SpanHelper . ReplacePlusWithSpace ( querySegment . Slice ( 0 , equalIndex ) ) ;
136
- var value = SpanHelper . ReplacePlusWithSpace ( querySegment . Slice ( equalIndex + 1 ) ) ;
137
-
138
- accumulator . Append (
139
- Uri . UnescapeDataString ( name ) ,
140
- Uri . UnescapeDataString ( value ) ) ;
141
- }
142
- else
143
- {
144
- if ( ! querySegment . IsEmpty )
145
- {
146
- var name = SpanHelper . ReplacePlusWithSpace ( querySegment ) ;
147
-
148
- accumulator . Append ( Uri . UnescapeDataString ( name ) ) ;
149
- }
150
- }
151
-
152
- if ( delimiterIndex < 0 )
153
- {
154
- break ;
155
- }
156
-
157
- query = query . Slice ( delimiterIndex + 1 ) ;
116
+ accumulator . Append ( pair . DecodeName ( ) , pair . DecodeValue ( ) ) ;
158
117
}
159
118
160
119
return accumulator . HasValues
@@ -171,8 +130,8 @@ internal struct KvpAccumulator
171
130
private AdaptiveCapacityDictionary < string , StringValues > _accumulator ;
172
131
private AdaptiveCapacityDictionary < string , List < string > > _expandingAccumulator ;
173
132
174
- public void Append ( ReadOnlySpan < char > key , ReadOnlySpan < char > value = default )
175
- => Append ( key . ToString ( ) , value . IsEmpty ? string . Empty : value . ToString ( ) ) ;
133
+ public void Append ( ReadOnlySpan < char > key , ReadOnlySpan < char > value )
134
+ => Append ( key . ToString ( ) , value . ToString ( ) ) ;
176
135
177
136
/// <summary>
178
137
/// This API supports infrastructure and is not intended to be used
@@ -263,58 +222,5 @@ public AdaptiveCapacityDictionary<string, StringValues> GetResults()
263
222
return _accumulator ?? new AdaptiveCapacityDictionary < string , StringValues > ( 0 , StringComparer . OrdinalIgnoreCase ) ;
264
223
}
265
224
}
266
-
267
- private static class SpanHelper
268
- {
269
- private static readonly SpanAction < char , IntPtr > s_replacePlusWithSpace = ReplacePlusWithSpaceCore ;
270
-
271
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
272
- public static unsafe string ReplacePlusWithSpace ( ReadOnlySpan < char > span )
273
- {
274
- fixed ( char * ptr = & MemoryMarshal . GetReference ( span ) )
275
- {
276
- return string . Create ( span . Length , ( IntPtr ) ptr , s_replacePlusWithSpace ) ;
277
- }
278
- }
279
-
280
- private static unsafe void ReplacePlusWithSpaceCore ( Span < char > buffer , IntPtr state )
281
- {
282
- fixed ( char * ptr = & MemoryMarshal . GetReference ( buffer ) )
283
- {
284
- var input = ( ushort * ) state . ToPointer ( ) ;
285
- var output = ( ushort * ) ptr ;
286
-
287
- var i = ( nint ) 0 ;
288
- var n = ( nint ) ( uint ) buffer . Length ;
289
-
290
- if ( Sse41 . IsSupported && n >= Vector128 < ushort > . Count )
291
- {
292
- var vecPlus = Vector128 . Create ( ( ushort ) '+' ) ;
293
- var vecSpace = Vector128 . Create ( ( ushort ) ' ' ) ;
294
-
295
- do
296
- {
297
- var vec = Sse2 . LoadVector128 ( input + i ) ;
298
- var mask = Sse2 . CompareEqual ( vec , vecPlus ) ;
299
- var res = Sse41 . BlendVariable ( vec , vecSpace , mask ) ;
300
- Sse2 . Store ( output + i , res ) ;
301
- i += Vector128 < ushort > . Count ;
302
- } while ( i <= n - Vector128 < ushort > . Count ) ;
303
- }
304
-
305
- for ( ; i < n ; ++ i )
306
- {
307
- if ( input [ i ] != '+' )
308
- {
309
- output [ i ] = input [ i ] ;
310
- }
311
- else
312
- {
313
- output [ i ] = ' ' ;
314
- }
315
- }
316
- }
317
- }
318
- }
319
225
}
320
226
}
0 commit comments