Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit 8c4b2dc

Browse files
committed
#758 Convert the header parsers to use StringSegment
1 parent 6e87b0f commit 8c4b2dc

29 files changed

+405
-418
lines changed

Diff for: src/Microsoft.AspNetCore.Http.Extensions/HttpRequestMultipartExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static string GetMultipartBoundary(this HttpRequest request)
2020
{
2121
return string.Empty;
2222
}
23-
return HeaderUtilities.RemoveQuotes(mediaType.Boundary);
23+
return HeaderUtilities.RemoveQuotes(mediaType.Boundary).ToString();
2424
}
2525
}
2626
}

Diff for: src/Microsoft.AspNetCore.Http/Features/FormFeature.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Threading.Tasks;
99
using Microsoft.AspNetCore.Http.Internal;
1010
using Microsoft.AspNetCore.WebUtilities;
11+
using Microsoft.Extensions.Primitives;
1112
using Microsoft.Net.Http.Headers;
1213

1314
namespace Microsoft.AspNetCore.Http.Features
@@ -293,30 +294,30 @@ private bool HasFormDataContentDisposition(ContentDispositionHeaderValue content
293294
{
294295
// Content-Disposition: form-data; name="key";
295296
return contentDisposition != null && contentDisposition.DispositionType.Equals("form-data")
296-
&& string.IsNullOrEmpty(contentDisposition.FileName) && string.IsNullOrEmpty(contentDisposition.FileNameStar);
297+
&& StringSegment.IsNullOrEmpty(contentDisposition.FileName) && StringSegment.IsNullOrEmpty(contentDisposition.FileNameStar);
297298
}
298299

299300
private bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
300301
{
301302
// Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg"
302303
return contentDisposition != null && contentDisposition.DispositionType.Equals("form-data")
303-
&& (!string.IsNullOrEmpty(contentDisposition.FileName) || !string.IsNullOrEmpty(contentDisposition.FileNameStar));
304+
&& (!StringSegment.IsNullOrEmpty(contentDisposition.FileName) || !StringSegment.IsNullOrEmpty(contentDisposition.FileNameStar));
304305
}
305306

306307
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq"
307308
// The spec says 70 characters is a reasonable limit.
308309
private static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
309310
{
310311
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary);
311-
if (string.IsNullOrWhiteSpace(boundary))
312+
if (StringSegment.IsNullOrEmpty(boundary))
312313
{
313314
throw new InvalidDataException("Missing content-type boundary.");
314315
}
315316
if (boundary.Length > lengthLimit)
316317
{
317318
throw new InvalidDataException($"Multipart boundary length limit {lengthLimit} exceeded.");
318319
}
319-
return boundary;
320+
return boundary.ToString();
320321
}
321322
}
322323
}

Diff for: src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ public static RequestCookieCollection Parse(IList<string> values)
7575
for (var i = 0; i < cookies.Count; i++)
7676
{
7777
var cookie = cookies[i];
78-
var name = Uri.UnescapeDataString(cookie.Name);
79-
var value = Uri.UnescapeDataString(cookie.Value);
78+
var name = Uri.UnescapeDataString(cookie.Name.Value);
79+
var value = Uri.UnescapeDataString(cookie.Value.Value);
8080
store[name] = value;
8181
}
8282

Diff for: src/Microsoft.AspNetCore.WebUtilities/FileMultipartSection.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ public FileMultipartSection(MultipartSection section, ContentDispositionHeaderVa
3939
Section = section;
4040
_contentDispositionHeader = header;
4141

42-
Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name) ?? string.Empty;
42+
Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name).ToString();
4343
FileName = HeaderUtilities.RemoveQuotes(
44-
_contentDispositionHeader.FileNameStar ??
45-
_contentDispositionHeader.FileName ??
46-
string.Empty);
44+
_contentDispositionHeader.FileNameStar.HasValue ?
45+
_contentDispositionHeader.FileNameStar :
46+
_contentDispositionHeader.FileName).ToString();
4747
}
4848

4949
/// <summary>

Diff for: src/Microsoft.AspNetCore.WebUtilities/FormMultipartSection.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public FormMultipartSection(MultipartSection section, ContentDispositionHeaderVa
3838

3939
Section = section;
4040
_contentDispositionHeader = header;
41-
Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name);
41+
Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name).ToString();
4242
}
4343

4444
/// <summary>

Diff for: src/Microsoft.Net.Http.Headers/BaseHeaderParser.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using Microsoft.Extensions.Primitives;
5+
46
namespace Microsoft.Net.Http.Headers
57
{
68
internal abstract class BaseHeaderParser<T> : HttpHeaderParser<T>
@@ -10,9 +12,9 @@ protected BaseHeaderParser(bool supportsMultipleValues)
1012
{
1113
}
1214

13-
protected abstract int GetParsedValueLength(string value, int startIndex, out T parsedValue);
15+
protected abstract int GetParsedValueLength(StringSegment value, int startIndex, out T parsedValue);
1416

15-
public sealed override bool TryParseValue(string value, ref int index, out T parsedValue)
17+
public sealed override bool TryParseValue(StringSegment value, ref int index, out T parsedValue)
1618
{
1719
parsedValue = default(T);
1820

@@ -21,7 +23,7 @@ public sealed override bool TryParseValue(string value, ref int index, out T par
2123
// Accept: text/xml; q=1
2224
// Accept:
2325
// Accept: text/plain; q=0.2
24-
if (string.IsNullOrEmpty(value) || (index == value.Length))
26+
if (StringSegment.IsNullOrEmpty(value) || (index == value.Length))
2527
{
2628
return SupportsMultipleValues;
2729
}

Diff for: src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs

+34-33
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics.Contracts;
77
using System.Globalization;
88
using System.Text;
9+
using Microsoft.Extensions.Primitives;
910

1011
namespace Microsoft.Net.Http.Headers
1112
{
@@ -32,10 +33,10 @@ public class CacheControlHeaderValue
3233
private static readonly HttpHeaderParser<CacheControlHeaderValue> Parser
3334
= new GenericHeaderParser<CacheControlHeaderValue>(true, GetCacheControlLength);
3435

35-
private static readonly Action<string> CheckIsValidTokenAction = CheckIsValidToken;
36+
private static readonly Action<StringSegment> CheckIsValidTokenAction = CheckIsValidToken;
3637

3738
private bool _noCache;
38-
private ICollection<string> _noCacheHeaders;
39+
private ICollection<StringSegment> _noCacheHeaders;
3940
private bool _noStore;
4041
private TimeSpan? _maxAge;
4142
private TimeSpan? _sharedMaxAge;
@@ -46,7 +47,7 @@ private static readonly HttpHeaderParser<CacheControlHeaderValue> Parser
4647
private bool _onlyIfCached;
4748
private bool _public;
4849
private bool _private;
49-
private ICollection<string> _privateHeaders;
50+
private ICollection<StringSegment> _privateHeaders;
5051
private bool _mustRevalidate;
5152
private bool _proxyRevalidate;
5253
private IList<NameValueHeaderValue> _extensions;
@@ -62,13 +63,13 @@ public bool NoCache
6263
set { _noCache = value; }
6364
}
6465

65-
public ICollection<string> NoCacheHeaders
66+
public ICollection<StringSegment> NoCacheHeaders
6667
{
6768
get
6869
{
6970
if (_noCacheHeaders == null)
7071
{
71-
_noCacheHeaders = new ObjectCollection<string>(CheckIsValidTokenAction);
72+
_noCacheHeaders = new ObjectCollection<StringSegment>(CheckIsValidTokenAction);
7273
}
7374
return _noCacheHeaders;
7475
}
@@ -134,13 +135,13 @@ public bool Private
134135
set { _private = value; }
135136
}
136137

137-
public ICollection<string> PrivateHeaders
138+
public ICollection<StringSegment> PrivateHeaders
138139
{
139140
get
140141
{
141142
if (_privateHeaders == null)
142143
{
143-
_privateHeaders = new ObjectCollection<string>(CheckIsValidTokenAction);
144+
_privateHeaders = new ObjectCollection<StringSegment>(CheckIsValidTokenAction);
144145
}
145146
return _privateHeaders;
146147
}
@@ -259,13 +260,13 @@ public override bool Equals(object obj)
259260
}
260261

261262
if (!HeaderUtilities.AreEqualCollections(_noCacheHeaders, other._noCacheHeaders,
262-
StringComparer.OrdinalIgnoreCase))
263+
StringSegmentComparer.OrdinalIgnoreCase))
263264
{
264265
return false;
265266
}
266267

267268
if (!HeaderUtilities.AreEqualCollections(_privateHeaders, other._privateHeaders,
268-
StringComparer.OrdinalIgnoreCase))
269+
StringSegmentComparer.OrdinalIgnoreCase))
269270
{
270271
return false;
271272
}
@@ -299,15 +300,15 @@ public override int GetHashCode()
299300
{
300301
foreach (var noCacheHeader in _noCacheHeaders)
301302
{
302-
result = result ^ StringComparer.OrdinalIgnoreCase.GetHashCode(noCacheHeader);
303+
result = result ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(noCacheHeader);
303304
}
304305
}
305306

306307
if ((_privateHeaders != null) && (_privateHeaders.Count > 0))
307308
{
308309
foreach (var privateHeader in _privateHeaders)
309310
{
310-
result = result ^ StringComparer.OrdinalIgnoreCase.GetHashCode(privateHeader);
311+
result = result ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(privateHeader);
311312
}
312313
}
313314

@@ -322,7 +323,7 @@ public override int GetHashCode()
322323
return result;
323324
}
324325

325-
public static CacheControlHeaderValue Parse(string input)
326+
public static CacheControlHeaderValue Parse(StringSegment input)
326327
{
327328
int index = 0;
328329
// Cache-Control is unusual because there are no required values so the parser will succeed for an empty string, but still return null.
@@ -334,7 +335,7 @@ public static CacheControlHeaderValue Parse(string input)
334335
return result;
335336
}
336337

337-
public static bool TryParse(string input, out CacheControlHeaderValue parsedValue)
338+
public static bool TryParse(StringSegment input, out CacheControlHeaderValue parsedValue)
338339
{
339340
int index = 0;
340341
// Cache-Control is unusual because there are no required values so the parser will succeed for an empty string, but still return null.
@@ -346,13 +347,13 @@ public static bool TryParse(string input, out CacheControlHeaderValue parsedValu
346347
return false;
347348
}
348349

349-
private static int GetCacheControlLength(string input, int startIndex, out CacheControlHeaderValue parsedValue)
350+
private static int GetCacheControlLength(StringSegment input, int startIndex, out CacheControlHeaderValue parsedValue)
350351
{
351352
Contract.Requires(startIndex >= 0);
352353

353354
parsedValue = null;
354355

355-
if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
356+
if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
356357
{
357358
return 0;
358359
}
@@ -403,7 +404,7 @@ private static bool TrySetCacheControlValues(
403404
switch (name.Length)
404405
{
405406
case 6:
406-
if (string.Equals(PublicString, name, StringComparison.OrdinalIgnoreCase))
407+
if (StringSegment.Equals(PublicString, name, StringComparison.OrdinalIgnoreCase))
407408
{
408409
success = TrySetTokenOnlyValue(nameValue, ref cc._public);
409410
}
@@ -414,11 +415,11 @@ private static bool TrySetCacheControlValues(
414415
break;
415416

416417
case 7:
417-
if (string.Equals(MaxAgeString, name, StringComparison.OrdinalIgnoreCase))
418+
if (StringSegment.Equals(MaxAgeString, name, StringComparison.OrdinalIgnoreCase))
418419
{
419420
success = TrySetTimeSpan(nameValue, ref cc._maxAge);
420421
}
421-
else if(string.Equals(PrivateString, name, StringComparison.OrdinalIgnoreCase))
422+
else if(StringSegment.Equals(PrivateString, name, StringComparison.OrdinalIgnoreCase))
422423
{
423424
success = TrySetOptionalTokenList(nameValue, ref cc._private, ref cc._privateHeaders);
424425
}
@@ -429,15 +430,15 @@ private static bool TrySetCacheControlValues(
429430
break;
430431

431432
case 8:
432-
if (string.Equals(NoCacheString, name, StringComparison.OrdinalIgnoreCase))
433+
if (StringSegment.Equals(NoCacheString, name, StringComparison.OrdinalIgnoreCase))
433434
{
434435
success = TrySetOptionalTokenList(nameValue, ref cc._noCache, ref cc._noCacheHeaders);
435436
}
436-
else if (string.Equals(NoStoreString, name, StringComparison.OrdinalIgnoreCase))
437+
else if (StringSegment.Equals(NoStoreString, name, StringComparison.OrdinalIgnoreCase))
437438
{
438439
success = TrySetTokenOnlyValue(nameValue, ref cc._noStore);
439440
}
440-
else if (string.Equals(SharedMaxAgeString, name, StringComparison.OrdinalIgnoreCase))
441+
else if (StringSegment.Equals(SharedMaxAgeString, name, StringComparison.OrdinalIgnoreCase))
441442
{
442443
success = TrySetTimeSpan(nameValue, ref cc._sharedMaxAge);
443444
}
@@ -448,15 +449,15 @@ private static bool TrySetCacheControlValues(
448449
break;
449450

450451
case 9:
451-
if (string.Equals(MaxStaleString, name, StringComparison.OrdinalIgnoreCase))
452+
if (StringSegment.Equals(MaxStaleString, name, StringComparison.OrdinalIgnoreCase))
452453
{
453454
success = ((nameValue.Value == null) || TrySetTimeSpan(nameValue, ref cc._maxStaleLimit));
454455
if (success)
455456
{
456457
cc._maxStale = true;
457458
}
458459
}
459-
else if (string.Equals(MinFreshString, name, StringComparison.OrdinalIgnoreCase))
460+
else if (StringSegment.Equals(MinFreshString, name, StringComparison.OrdinalIgnoreCase))
460461
{
461462
success = TrySetTimeSpan(nameValue, ref cc._minFresh);
462463
}
@@ -467,7 +468,7 @@ private static bool TrySetCacheControlValues(
467468
break;
468469

469470
case 12:
470-
if (string.Equals(NoTransformString, name, StringComparison.OrdinalIgnoreCase))
471+
if (StringSegment.Equals(NoTransformString, name, StringComparison.OrdinalIgnoreCase))
471472
{
472473
success = TrySetTokenOnlyValue(nameValue, ref cc._noTransform);
473474
}
@@ -478,7 +479,7 @@ private static bool TrySetCacheControlValues(
478479
break;
479480

480481
case 14:
481-
if (string.Equals(OnlyIfCachedString, name, StringComparison.OrdinalIgnoreCase))
482+
if (StringSegment.Equals(OnlyIfCachedString, name, StringComparison.OrdinalIgnoreCase))
482483
{
483484
success = TrySetTokenOnlyValue(nameValue, ref cc._onlyIfCached);
484485
}
@@ -489,7 +490,7 @@ private static bool TrySetCacheControlValues(
489490
break;
490491

491492
case 15:
492-
if (string.Equals(MustRevalidateString, name, StringComparison.OrdinalIgnoreCase))
493+
if (StringSegment.Equals(MustRevalidateString, name, StringComparison.OrdinalIgnoreCase))
493494
{
494495
success = TrySetTokenOnlyValue(nameValue, ref cc._mustRevalidate);
495496
}
@@ -500,7 +501,7 @@ private static bool TrySetCacheControlValues(
500501
break;
501502

502503
case 16:
503-
if (string.Equals(ProxyRevalidateString, name, StringComparison.OrdinalIgnoreCase))
504+
if (StringSegment.Equals(ProxyRevalidateString, name, StringComparison.OrdinalIgnoreCase))
504505
{
505506
success = TrySetTokenOnlyValue(nameValue, ref cc._proxyRevalidate);
506507
}
@@ -538,7 +539,7 @@ private static bool TrySetTokenOnlyValue(NameValueHeaderValue nameValue, ref boo
538539
private static bool TrySetOptionalTokenList(
539540
NameValueHeaderValue nameValue,
540541
ref bool boolField,
541-
ref ICollection<string> destination)
542+
ref ICollection<StringSegment> destination)
542543
{
543544
Contract.Requires(nameValue != null);
544545

@@ -582,10 +583,10 @@ private static bool TrySetOptionalTokenList(
582583

583584
if (destination == null)
584585
{
585-
destination = new ObjectCollection<string>(CheckIsValidTokenAction);
586+
destination = new ObjectCollection<StringSegment>(CheckIsValidTokenAction);
586587
}
587588

588-
destination.Add(valueString.Substring(current, tokenLength));
589+
destination.Add(valueString.Subsegment(current, tokenLength));
589590

590591
current = current + tokenLength;
591592
}
@@ -637,10 +638,10 @@ private static void AppendValueWithSeparatorIfRequired(StringBuilder sb, string
637638
sb.Append(value);
638639
}
639640

640-
private static void AppendValues(StringBuilder sb, IEnumerable<string> values)
641+
private static void AppendValues(StringBuilder sb, IEnumerable<StringSegment> values)
641642
{
642643
var first = true;
643-
foreach (string value in values)
644+
foreach (var value in values)
644645
{
645646
if (first)
646647
{
@@ -655,7 +656,7 @@ private static void AppendValues(StringBuilder sb, IEnumerable<string> values)
655656
}
656657
}
657658

658-
private static void CheckIsValidToken(string item)
659+
private static void CheckIsValidToken(StringSegment item)
659660
{
660661
HeaderUtilities.CheckValidToken(item, nameof(item));
661662
}

0 commit comments

Comments
 (0)