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

Commit d50a241

Browse files
committed
Add functionalities to HeaderUtilities
- Add allocation free parsing of int32, int64 - Improve performance of converting int64 to string - Add parsing of seconds from header values - Add check for existence of cache directives - Expose CacheControlHeaderValue constants
1 parent b727f0e commit d50a241

File tree

11 files changed

+573
-80
lines changed

11 files changed

+573
-80
lines changed

src/Microsoft.AspNetCore.Http.Abstractions/HostString.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public int? Port
9898
{
9999
return null;
100100
}
101-
101+
102102
return p;
103103
}
104104
}

src/Microsoft.AspNetCore.Http.Abstractions/Internal/ParsingHelpers.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,18 @@ public static void SetHeaderJoined(IHeaderDictionary headers, string key, String
6868
// Quote items that contain comas and are not already quoted.
6969
private static string QuoteIfNeeded(string value)
7070
{
71-
if (!string.IsNullOrWhiteSpace(value) &&
72-
value.Contains(',') &&
71+
if (!string.IsNullOrWhiteSpace(value) &&
72+
value.Contains(',') &&
7373
(value[0] != '"' || value[value.Length - 1] != '"'))
74-
{
74+
{
7575
return $"\"{value}\"";
7676
}
7777
return value;
7878
}
7979

8080
private static string DeQuote(string value)
8181
{
82-
if (!string.IsNullOrWhiteSpace(value) &&
82+
if (!string.IsNullOrWhiteSpace(value) &&
8383
(value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"'))
8484
{
8585
value = value.Substring(1, value.Length - 2);

src/Microsoft.AspNetCore.Http/Internal/ParsingHelpers.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,11 @@ private static string DeQuote(string value)
411411
throw new ArgumentNullException(nameof(headers));
412412
}
413413

414-
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
415414
long value;
416415
var rawValue = headers[HeaderNames.ContentLength];
417416
if (rawValue.Count == 1 &&
418417
!string.IsNullOrWhiteSpace(rawValue[0]) &&
419-
long.TryParse(rawValue[0], styles, CultureInfo.InvariantCulture, out value))
418+
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
420419
{
421420
return value;
422421
}
@@ -433,7 +432,7 @@ public static void SetContentLength(IHeaderDictionary headers, long? value)
433432

434433
if (value.HasValue)
435434
{
436-
headers[HeaderNames.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture);
435+
headers[HeaderNames.ContentLength] = HeaderUtilities.FormatInt64(value.Value);
437436
}
438437
else
439438
{

src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs

Lines changed: 106 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ namespace Microsoft.Net.Http.Headers
1111
{
1212
public class CacheControlHeaderValue
1313
{
14-
private const string MaxAgeString = "max-age";
15-
private const string MaxStaleString = "max-stale";
16-
private const string MinFreshString = "min-fresh";
17-
private const string MustRevalidateString = "must-revalidate";
18-
private const string NoCacheString = "no-cache";
19-
private const string NoStoreString = "no-store";
20-
private const string NoTransformString = "no-transform";
21-
private const string OnlyIfCachedString = "only-if-cached";
22-
private const string PrivateString = "private";
23-
private const string ProxyRevalidateString = "proxy-revalidate";
24-
private const string PublicString = "public";
25-
private const string SharedMaxAgeString = "s-maxage";
14+
public static readonly string PublicString = "public";
15+
public static readonly string PrivateString = "private";
16+
public static readonly string MaxAgeString = "max-age";
17+
public static readonly string SharedMaxAgeString = "s-maxage";
18+
public static readonly string NoCacheString = "no-cache";
19+
public static readonly string NoStoreString = "no-store";
20+
public static readonly string MaxStaleString = "max-stale";
21+
public static readonly string MinFreshString = "min-fresh";
22+
public static readonly string NoTransformString = "no-transform";
23+
public static readonly string OnlyIfCachedString = "only-if-cached";
24+
public static readonly string MustRevalidateString = "must-revalidate";
25+
public static readonly string ProxyRevalidateString = "proxy-revalidate";
2626

2727
// The Cache-Control header is special: It is a header supporting a list of values, but we represent the list
2828
// as _one_ instance of CacheControlHeaderValue. I.e we set 'SupportsMultipleValues' to 'true' since it is
@@ -394,63 +394,120 @@ private static bool TrySetCacheControlValues(
394394
CacheControlHeaderValue cc,
395395
List<NameValueHeaderValue> nameValueList)
396396
{
397-
foreach (NameValueHeaderValue nameValue in nameValueList)
397+
for (var i = 0; i < nameValueList.Count; i++)
398398
{
399+
var nameValue = nameValueList[i];
400+
var name = nameValue.Name;
399401
var success = true;
400-
string name = nameValue.Name.ToLowerInvariant();
401402

402-
switch (name)
403+
switch (name.Length)
403404
{
404-
case NoCacheString:
405-
success = TrySetOptionalTokenList(nameValue, ref cc._noCache, ref cc._noCacheHeaders);
406-
break;
407-
408-
case NoStoreString:
409-
success = TrySetTokenOnlyValue(nameValue, ref cc._noStore);
410-
break;
411-
412-
case MaxAgeString:
413-
success = TrySetTimeSpan(nameValue, ref cc._maxAge);
414-
break;
415-
416-
case MaxStaleString:
417-
success = ((nameValue.Value == null) || TrySetTimeSpan(nameValue, ref cc._maxStaleLimit));
418-
if (success)
405+
case 6:
406+
if (string.Equals(PublicString, name, StringComparison.OrdinalIgnoreCase))
419407
{
420-
cc._maxStale = true;
408+
success = TrySetTokenOnlyValue(nameValue, ref cc._public);
409+
}
410+
else
411+
{
412+
goto default;
421413
}
422414
break;
423415

424-
case MinFreshString:
425-
success = TrySetTimeSpan(nameValue, ref cc._minFresh);
426-
break;
427-
428-
case NoTransformString:
429-
success = TrySetTokenOnlyValue(nameValue, ref cc._noTransform);
416+
case 7:
417+
if (string.Equals(MaxAgeString, name, StringComparison.OrdinalIgnoreCase))
418+
{
419+
success = TrySetTimeSpan(nameValue, ref cc._maxAge);
420+
}
421+
else if(string.Equals(PrivateString, name, StringComparison.OrdinalIgnoreCase))
422+
{
423+
success = TrySetOptionalTokenList(nameValue, ref cc._private, ref cc._privateHeaders);
424+
}
425+
else
426+
{
427+
goto default;
428+
}
430429
break;
431430

432-
case OnlyIfCachedString:
433-
success = TrySetTokenOnlyValue(nameValue, ref cc._onlyIfCached);
431+
case 8:
432+
if (string.Equals(NoCacheString, name, StringComparison.OrdinalIgnoreCase))
433+
{
434+
success = TrySetOptionalTokenList(nameValue, ref cc._noCache, ref cc._noCacheHeaders);
435+
}
436+
else if (string.Equals(NoStoreString, name, StringComparison.OrdinalIgnoreCase))
437+
{
438+
success = TrySetTokenOnlyValue(nameValue, ref cc._noStore);
439+
}
440+
else if (string.Equals(SharedMaxAgeString, name, StringComparison.OrdinalIgnoreCase))
441+
{
442+
success = TrySetTimeSpan(nameValue, ref cc._sharedMaxAge);
443+
}
444+
else
445+
{
446+
goto default;
447+
}
434448
break;
435449

436-
case PublicString:
437-
success = TrySetTokenOnlyValue(nameValue, ref cc._public);
450+
case 9:
451+
if (string.Equals(MaxStaleString, name, StringComparison.OrdinalIgnoreCase))
452+
{
453+
success = ((nameValue.Value == null) || TrySetTimeSpan(nameValue, ref cc._maxStaleLimit));
454+
if (success)
455+
{
456+
cc._maxStale = true;
457+
}
458+
}
459+
else if (string.Equals(MinFreshString, name, StringComparison.OrdinalIgnoreCase))
460+
{
461+
success = TrySetTimeSpan(nameValue, ref cc._minFresh);
462+
}
463+
else
464+
{
465+
goto default;
466+
}
438467
break;
439468

440-
case PrivateString:
441-
success = TrySetOptionalTokenList(nameValue, ref cc._private, ref cc._privateHeaders);
469+
case 12:
470+
if (string.Equals(NoTransformString, name, StringComparison.OrdinalIgnoreCase))
471+
{
472+
success = TrySetTokenOnlyValue(nameValue, ref cc._noTransform);
473+
}
474+
else
475+
{
476+
goto default;
477+
}
442478
break;
443479

444-
case MustRevalidateString:
445-
success = TrySetTokenOnlyValue(nameValue, ref cc._mustRevalidate);
480+
case 14:
481+
if (string.Equals(OnlyIfCachedString, name, StringComparison.OrdinalIgnoreCase))
482+
{
483+
success = TrySetTokenOnlyValue(nameValue, ref cc._onlyIfCached);
484+
}
485+
else
486+
{
487+
goto default;
488+
}
446489
break;
447490

448-
case ProxyRevalidateString:
449-
success = TrySetTokenOnlyValue(nameValue, ref cc._proxyRevalidate);
491+
case 15:
492+
if (string.Equals(MustRevalidateString, name, StringComparison.OrdinalIgnoreCase))
493+
{
494+
success = TrySetTokenOnlyValue(nameValue, ref cc._mustRevalidate);
495+
}
496+
else
497+
{
498+
goto default;
499+
}
450500
break;
451501

452-
case SharedMaxAgeString:
453-
success = TrySetTimeSpan(nameValue, ref cc._sharedMaxAge);
502+
case 16:
503+
if (string.Equals(ProxyRevalidateString, name, StringComparison.OrdinalIgnoreCase))
504+
{
505+
success = TrySetTokenOnlyValue(nameValue, ref cc._proxyRevalidate);
506+
}
507+
else
508+
{
509+
goto default;
510+
}
454511
break;
455512

456513
default:

src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValue.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ public long? Size
104104
get
105105
{
106106
var sizeParameter = NameValueHeaderValue.Find(_parameters, SizeString);
107-
ulong value;
107+
long value;
108108
if (sizeParameter != null)
109109
{
110-
string sizeString = sizeParameter.Value;
111-
if (UInt64.TryParse(sizeString, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
110+
var sizeString = sizeParameter.Value;
111+
if (HeaderUtilities.TryParseInt64(sizeString, out value))
112112
{
113-
return (long)value;
113+
return value;
114114
}
115115
}
116116
return null;

0 commit comments

Comments
 (0)