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

Commit 4043a1c

Browse files
committed
Only format non-negative int64 #760
1 parent b9bba9c commit 4043a1c

File tree

12 files changed

+50
-59
lines changed

12 files changed

+50
-59
lines changed

src/Microsoft.AspNetCore.Http.Extensions/HeaderDictionaryTypeExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ internal static void SetDate(this IHeaderDictionary headers, string name, DateTi
156156
{ typeof(RangeHeaderValue), new Func<string, RangeHeaderValue>(value => { RangeHeaderValue result; return RangeHeaderValue.TryParse(value, out result) ? result : null; }) },
157157
{ typeof(EntityTagHeaderValue), new Func<string, EntityTagHeaderValue>(value => { EntityTagHeaderValue result; return EntityTagHeaderValue.TryParse(value, out result) ? result : null; }) },
158158
{ typeof(DateTimeOffset?), new Func<string, DateTimeOffset?>(value => { DateTimeOffset result; return HeaderUtilities.TryParseDate(value, out result) ? result : (DateTimeOffset?)null; }) },
159-
{ typeof(long?), new Func<string, long?>(value => { long result; return HeaderUtilities.TryParseInt64(value, out result) ? result : (long?)null; }) },
159+
{ typeof(long?), new Func<string, long?>(value => { long result; return HeaderUtilities.TryParseNonNegativeInt64(value, out result) ? result : (long?)null; }) },
160160
};
161161

162162
private static IDictionary<Type, object> KnownListParsers = new Dictionary<Type, object>()

src/Microsoft.AspNetCore.Http.Extensions/RequestHeaders.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public long? ContentLength
101101
}
102102
set
103103
{
104-
Headers.Set(HeaderNames.ContentLength, value.HasValue ? HeaderUtilities.FormatInt64(value.Value) : null);
104+
Headers.Set(HeaderNames.ContentLength, value.HasValue ? HeaderUtilities.FormatNonNegativeInt64(value.Value) : null);
105105
}
106106
}
107107

src/Microsoft.AspNetCore.Http.Extensions/ResponseHeaders.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public long? ContentLength
5454
}
5555
set
5656
{
57-
Headers.Set(HeaderNames.ContentLength, value.HasValue ? HeaderUtilities.FormatInt64(value.Value) : null);
57+
Headers.Set(HeaderNames.ContentLength, value.HasValue ? HeaderUtilities.FormatNonNegativeInt64(value.Value) : null);
5858
}
5959
}
6060

src/Microsoft.AspNetCore.Http/HeaderDictionary.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public long? ContentLength
106106
var rawValue = this[HeaderNames.ContentLength];
107107
if (rawValue.Count == 1 &&
108108
!string.IsNullOrWhiteSpace(rawValue[0]) &&
109-
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
109+
HeaderUtilities.TryParseNonNegativeInt64(new StringSegment(rawValue[0]).Trim(), out value))
110110
{
111111
return value;
112112
}
@@ -117,7 +117,7 @@ public long? ContentLength
117117
{
118118
if (value.HasValue)
119119
{
120-
this[HeaderNames.ContentLength] = HeaderUtilities.FormatInt64(value.Value);
120+
this[HeaderNames.ContentLength] = HeaderUtilities.FormatNonNegativeInt64(value.Value);
121121
}
122122
else
123123
{

src/Microsoft.AspNetCore.Owin/DictionaryStringValuesWrapper.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public long? ContentLength
5757

5858
if (rawValue.Length == 1 &&
5959
!string.IsNullOrWhiteSpace(rawValue[0]) &&
60-
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
60+
HeaderUtilities.TryParseNonNegativeInt64(new StringSegment(rawValue[0]).Trim(), out value))
6161
{
6262
return value;
6363
}
@@ -68,7 +68,7 @@ public long? ContentLength
6868
{
6969
if (value.HasValue)
7070
{
71-
Inner[HeaderNames.ContentLength] = (StringValues)HeaderUtilities.FormatInt64(value.Value);
71+
Inner[HeaderNames.ContentLength] = (StringValues)HeaderUtilities.FormatNonNegativeInt64(value.Value);
7272
}
7373
else
7474
{

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ private static bool TrySetTimeSpan(NameValueHeaderValue nameValue, ref TimeSpan?
610610
}
611611

612612
int seconds;
613-
if (!HeaderUtilities.TryParseInt32(nameValue.Value, out seconds))
613+
if (!HeaderUtilities.TryParseNonNegativeInt32(nameValue.Value, out seconds))
614614
{
615615
return false;
616616
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public long? Size
108108
if (sizeParameter != null)
109109
{
110110
var sizeString = sizeParameter.Value;
111-
if (HeaderUtilities.TryParseInt64(sizeString, out value))
111+
if (HeaderUtilities.TryParseNonNegativeInt64(sizeString, out value))
112112
{
113113
return value;
114114
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -354,13 +354,13 @@ private static bool TryCreateContentRange(
354354
parsedValue = null;
355355

356356
long from = 0;
357-
if ((fromLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(fromStartIndex, fromLength), out from))
357+
if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(fromStartIndex, fromLength), out from))
358358
{
359359
return false;
360360
}
361361

362362
long to = 0;
363-
if ((toLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(toStartIndex, toLength), out to))
363+
if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(toStartIndex, toLength), out to))
364364
{
365365
return false;
366366
}
@@ -372,7 +372,7 @@ private static bool TryCreateContentRange(
372372
}
373373

374374
long length = 0;
375-
if ((lengthLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(lengthStartIndex, lengthLength),
375+
if ((lengthLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(lengthStartIndex, lengthLength),
376376
out length))
377377
{
378378
return false;

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

+15-29
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Microsoft.Net.Http.Headers
1212
{
1313
public static class HeaderUtilities
1414
{
15-
private static readonly int _int64MaxStringLength = 20;
15+
private static readonly int _int64MaxStringLength = 19;
1616
private const string QualityName = "q";
1717
internal const string BytesUnit = "bytes";
1818

@@ -269,7 +269,7 @@ public static bool TryParseSeconds(StringValues headerValues, string targetValue
269269
var tokenLength = HttpRuleParser.GetTokenLength(headerValues[i], current);
270270
if (tokenLength == targetValue.Length
271271
&& string.Compare(headerValues[i], current, targetValue, 0, tokenLength, StringComparison.OrdinalIgnoreCase) == 0
272-
&& TryParseInt64FromHeaderValue(current + tokenLength, headerValues[i], out seconds))
272+
&& TryParseNonNegativeInt64FromHeaderValue(current + tokenLength, headerValues[i], out seconds))
273273
{
274274
// Token matches target value and seconds were parsed
275275
value = TimeSpan.FromSeconds(seconds);
@@ -342,7 +342,7 @@ public static bool ContainsCacheDirective(StringValues cacheControlDirectives, s
342342
return false;
343343
}
344344

345-
private static unsafe bool TryParseInt64FromHeaderValue(int startIndex, string headerValue, out long result)
345+
private static unsafe bool TryParseNonNegativeInt64FromHeaderValue(int startIndex, string headerValue, out long result)
346346
{
347347
// Trim leading whitespace
348348
startIndex += HttpRuleParser.GetWhitespaceLength(headerValue, startIndex);
@@ -359,7 +359,7 @@ private static unsafe bool TryParseInt64FromHeaderValue(int startIndex, string h
359359
startIndex += HttpRuleParser.GetWhitespaceLength(headerValue, startIndex);
360360

361361
// Try parse the number
362-
if (TryParseInt64(new StringSegment(headerValue, startIndex, HttpRuleParser.GetNumberLength(headerValue, startIndex, false)), out result))
362+
if (TryParseNonNegativeInt64(new StringSegment(headerValue, startIndex, HttpRuleParser.GetNumberLength(headerValue, startIndex, false)), out result))
363363
{
364364
return true;
365365
}
@@ -368,9 +368,9 @@ private static unsafe bool TryParseInt64FromHeaderValue(int startIndex, string h
368368
return false;
369369
}
370370

371-
internal static bool TryParseInt32(string value, out int result)
371+
internal static bool TryParseNonNegativeInt32(string value, out int result)
372372
{
373-
return TryParseInt32(new StringSegment(value), out result);
373+
return TryParseNonNegativeInt32(new StringSegment(value), out result);
374374
}
375375

376376
/// <summary>
@@ -388,12 +388,12 @@ internal static bool TryParseInt32(string value, out int result)
388388
/// result will be overwritten.
389389
/// </param>
390390
/// <returns><code>true</code> if parsing succeeded; otherwise, <code>false</code>.</returns>
391-
public static bool TryParseInt64(string value, out long result)
391+
public static bool TryParseNonNegativeInt64(string value, out long result)
392392
{
393-
return TryParseInt64(new StringSegment(value), out result);
393+
return TryParseNonNegativeInt64(new StringSegment(value), out result);
394394
}
395395

396-
internal static unsafe bool TryParseInt32(StringSegment value, out int result)
396+
internal static unsafe bool TryParseNonNegativeInt32(StringSegment value, out int result)
397397
{
398398
if (string.IsNullOrEmpty(value.Buffer) || value.Length == 0)
399399
{
@@ -444,7 +444,7 @@ internal static unsafe bool TryParseInt32(StringSegment value, out int result)
444444
/// originally supplied in result will be overwritten.
445445
/// </param>
446446
/// <returns><code>true</code> if parsing succeeded; otherwise, <code>false</code>.</returns>
447-
public static unsafe bool TryParseInt64(StringSegment value, out long result)
447+
public static unsafe bool TryParseNonNegativeInt64(StringSegment value, out long result)
448448
{
449449
if (string.IsNullOrEmpty(value.Buffer) || value.Length == 0)
450450
{
@@ -481,31 +481,22 @@ public static unsafe bool TryParseInt64(StringSegment value, out long result)
481481
}
482482

483483
/// <summary>
484-
/// Converts the signed 64-bit numeric value to its equivalent string representation.
484+
/// Converts the non-negative 64-bit numeric value to its equivalent string representation.
485485
/// </summary>
486486
/// <param name="value">
487487
/// The number to convert.
488488
/// </param>
489489
/// <returns>
490-
/// The string representation of the value of this instance, consisting of a minus sign if the value is
491-
/// negative, and a sequence of digits ranging from 0 to 9 with no leading zeroes.
490+
/// The string representation of the value of this instance, consisting of a sequence of digits ranging from 0 to 9 with no leading zeroes.
492491
/// </returns>
493-
public unsafe static string FormatInt64(long value)
492+
public unsafe static string FormatNonNegativeInt64(long value)
494493
{
495-
var position = _int64MaxStringLength;
496-
var negative = false;
497-
498494
if (value < 0)
499495
{
500-
// Not possible to compute absolute value of MinValue, return the exact string instead.
501-
if (value == long.MinValue)
502-
{
503-
return "-9223372036854775808";
504-
}
505-
negative = true;
506-
value = -value;
496+
throw new ArgumentOutOfRangeException(nameof(value), value, "The value to be formatted must be non-negative.");
507497
}
508498

499+
var position = _int64MaxStringLength;
509500
char* charBuffer = stackalloc char[_int64MaxStringLength];
510501

511502
do
@@ -517,11 +508,6 @@ public unsafe static string FormatInt64(long value)
517508
}
518509
while (value != 0);
519510

520-
if (negative)
521-
{
522-
charBuffer[--position] = '-';
523-
}
524-
525511
return new string(charBuffer, position, _int64MaxStringLength - position);
526512
}
527513

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,14 @@ internal static int GetRangeItemLength(string input, int startIndex, out RangeIt
202202

203203
// Try convert first value to int64
204204
long from = 0;
205-
if ((fromLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(fromStartIndex, fromLength), out from))
205+
if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(fromStartIndex, fromLength), out from))
206206
{
207207
return 0;
208208
}
209209

210210
// Try convert second value to int64
211211
long to = 0;
212-
if ((toLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(toStartIndex, toLength), out to))
212+
if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(toStartIndex, toLength), out to))
213213
{
214214
return 0;
215215
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public override string ToString()
105105

106106
if (MaxAge.HasValue)
107107
{
108-
maxAge = HeaderUtilities.FormatInt64((long)MaxAge.Value.TotalSeconds);
108+
maxAge = HeaderUtilities.FormatNonNegativeInt64((long)MaxAge.Value.TotalSeconds);
109109
length += SeparatorToken.Length + MaxAgeToken.Length + EqualsToken.Length + maxAge.Length;
110110
}
111111

@@ -200,7 +200,7 @@ public void AppendToStringBuilder(StringBuilder builder)
200200

201201
if (MaxAge.HasValue)
202202
{
203-
AppendSegment(builder, MaxAgeToken, HeaderUtilities.FormatInt64((long)MaxAge.Value.TotalSeconds));
203+
AppendSegment(builder, MaxAgeToken, HeaderUtilities.FormatNonNegativeInt64((long)MaxAge.Value.TotalSeconds));
204204
}
205205

206206
if (Domain != null)
@@ -365,7 +365,7 @@ private static int GetSetCookieLength(string input, int startIndex, out SetCooki
365365
}
366366
var numberString = input.Substring(offset, itemLength);
367367
long maxAge;
368-
if (!HeaderUtilities.TryParseInt64(numberString, out maxAge))
368+
if (!HeaderUtilities.TryParseNonNegativeInt64(numberString, out maxAge))
369369
{
370370
// Invalid expiration date, abort
371371
return 0;

test/Microsoft.Net.Http.Headers.Tests/HeaderUtilitiesTest.cs

+18-13
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,20 @@ public void TryParseSeconds_Fails(string headerValues, string targetValue)
8787
[Theory]
8888
[InlineData(0)]
8989
[InlineData(1)]
90-
[InlineData(-1)]
9190
[InlineData(1234567890)]
92-
[InlineData(-1234567890)]
9391
[InlineData(long.MaxValue)]
92+
public void FormatNonNegativeInt64_MatchesToString(long value)
93+
{
94+
Assert.Equal(value.ToString(CultureInfo.InvariantCulture), HeaderUtilities.FormatNonNegativeInt64(value));
95+
}
96+
97+
[Theory]
98+
[InlineData(-1)]
99+
[InlineData(-1234567890)]
94100
[InlineData(long.MinValue)]
95-
[InlineData(long.MinValue + 1)]
96-
public void FormatInt64_MatchesToString(long value)
101+
public void FormatNonNegativeInt64_Throws_ForNegativeValues(long value)
97102
{
98-
Assert.Equal(value.ToString(CultureInfo.InvariantCulture), HeaderUtilities.FormatInt64(value));
103+
Assert.Throws<ArgumentOutOfRangeException>(() => HeaderUtilities.FormatNonNegativeInt64(value));
99104
}
100105

101106
[Theory]
@@ -150,20 +155,20 @@ public void ContainsCacheDirective_MatchesExactValue(string headerValues, string
150155
[InlineData("a")]
151156
[InlineData("1.1")]
152157
[InlineData("9223372036854775808")] // long.MaxValue + 1
153-
public void TryParseInt64_Fails(string valueString)
158+
public void TryParseNonNegativeInt64_Fails(string valueString)
154159
{
155160
long value = 1;
156-
Assert.False(HeaderUtilities.TryParseInt64(valueString, out value));
161+
Assert.False(HeaderUtilities.TryParseNonNegativeInt64(valueString, out value));
157162
Assert.Equal(0, value);
158163
}
159164

160165
[Theory]
161166
[InlineData("0", 0)]
162167
[InlineData("9223372036854775807", 9223372036854775807)] // long.MaxValue
163-
public void TryParseInt64_Succeeds(string valueString, long expected)
168+
public void TryParseNonNegativeInt64_Succeeds(string valueString, long expected)
164169
{
165170
long value = 1;
166-
Assert.True(HeaderUtilities.TryParseInt64(valueString, out value));
171+
Assert.True(HeaderUtilities.TryParseNonNegativeInt64(valueString, out value));
167172
Assert.Equal(expected, value);
168173
}
169174

@@ -175,20 +180,20 @@ public void TryParseInt64_Succeeds(string valueString, long expected)
175180
[InlineData("1.1")]
176181
[InlineData("1,000")]
177182
[InlineData("2147483648")] // int.MaxValue + 1
178-
public void TryParseInt32_Fails(string valueString)
183+
public void TryParseNonNegativeInt32_Fails(string valueString)
179184
{
180185
int value = 1;
181-
Assert.False(HeaderUtilities.TryParseInt32(valueString, out value));
186+
Assert.False(HeaderUtilities.TryParseNonNegativeInt32(valueString, out value));
182187
Assert.Equal(0, value);
183188
}
184189

185190
[Theory]
186191
[InlineData("0", 0)]
187192
[InlineData("2147483647", 2147483647)] // int.MaxValue
188-
public void TryParseInt32_Succeeds(string valueString, long expected)
193+
public void TryParseNonNegativeInt32_Succeeds(string valueString, long expected)
189194
{
190195
int value = 1;
191-
Assert.True(HeaderUtilities.TryParseInt32(valueString, out value));
196+
Assert.True(HeaderUtilities.TryParseNonNegativeInt32(valueString, out value));
192197
Assert.Equal(expected, value);
193198
}
194199
}

0 commit comments

Comments
 (0)