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

Commit 3289afe

Browse files
committed
Add check for index advance during parsing
1 parent 779115b commit 3289afe

File tree

2 files changed

+46
-37
lines changed

2 files changed

+46
-37
lines changed

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

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics;
67
using System.Diagnostics.Contracts;
78
using System.Globalization;
89
using Microsoft.Extensions.Primitives;
@@ -200,6 +201,33 @@ internal static int GetNextNonEmptyOrWhitespaceIndex(
200201
return current;
201202
}
202203

204+
private static int AdvanceCacheDirectiveIndex(int current, string headerValue)
205+
{
206+
// Skip until the next potential name
207+
current += HttpRuleParser.GetWhitespaceLength(headerValue, current);
208+
209+
// Skip the value if present
210+
if (current < headerValue.Length && headerValue[current] == '=')
211+
{
212+
current++; // skip '='
213+
current += NameValueHeaderValue.GetValueLength(headerValue, current);
214+
}
215+
216+
// Find the next delimiter
217+
current = headerValue.IndexOf(',', current);
218+
219+
if (current == -1)
220+
{
221+
// If no delimiter found, skip to the end
222+
return headerValue.Length;
223+
}
224+
225+
current++; // skip ','
226+
current += HttpRuleParser.GetWhitespaceLength(headerValue, current);
227+
228+
return current;
229+
}
230+
203231
/// <summary>
204232
/// Try to find a target header value among the set of given header values and parse it as a
205233
/// <see cref="TimeSpan"/>.
@@ -237,6 +265,7 @@ public static bool TryParseSeconds(StringValues headerValues, string targetValue
237265
while (current < headerValues[i].Length)
238266
{
239267
long seconds;
268+
var initial = current;
240269
var tokenLength = HttpRuleParser.GetTokenLength(headerValues[i], current);
241270
if (tokenLength == targetValue.Length
242271
&& string.Compare(headerValues[i], current, targetValue, 0, tokenLength, StringComparison.OrdinalIgnoreCase) == 0
@@ -246,26 +275,15 @@ public static bool TryParseSeconds(StringValues headerValues, string targetValue
246275
value = TimeSpan.FromSeconds(seconds);
247276
return true;
248277
}
249-
else
250-
{
251-
// Skip until the next potential name
252-
current += tokenLength;
253-
current += HttpRuleParser.GetWhitespaceLength(headerValues[i], current);
254278

255-
// Skip the value if present
256-
if (current < headerValues[i].Length && headerValues[i][current] == '=')
257-
{
258-
current++; // skip '='
259-
current += NameValueHeaderValue.GetValueLength(headerValues[i], current);
260-
current += HttpRuleParser.GetWhitespaceLength(headerValues[i], current);
261-
}
279+
current = AdvanceCacheDirectiveIndex(current + tokenLength, headerValues[i]);
262280

263-
// Skip the delimiter
264-
if (current < headerValues[i].Length && headerValues[i][current] == ',')
265-
{
266-
current++; // skip ','
267-
current += HttpRuleParser.GetWhitespaceLength(headerValues[i], current);
268-
}
281+
// Ensure index was advanced
282+
if (current <= initial)
283+
{
284+
Debug.Assert(false, $"Index '{nameof(current)}' not advanced, this is a bug.");
285+
value = null;
286+
return false;
269287
}
270288
}
271289
}
@@ -293,41 +311,30 @@ public static bool ContainsCacheDirective(StringValues cacheControlDirectives, s
293311
return false;
294312
}
295313

296-
297314
for (var i = 0; i < cacheControlDirectives.Count; i++)
298315
{
299316
// Trim leading white space
300317
var current = HttpRuleParser.GetWhitespaceLength(cacheControlDirectives[i], 0);
301318

302319
while (current < cacheControlDirectives[i].Length)
303320
{
321+
var initial = current;
322+
304323
var tokenLength = HttpRuleParser.GetTokenLength(cacheControlDirectives[i], current);
305324
if (tokenLength == targetDirectives.Length
306325
&& string.Compare(cacheControlDirectives[i], current, targetDirectives, 0, tokenLength, StringComparison.OrdinalIgnoreCase) == 0)
307326
{
308327
// Token matches target value
309328
return true;
310329
}
311-
else
312-
{
313-
// Skip until the next potential name
314-
current += tokenLength;
315-
current += HttpRuleParser.GetWhitespaceLength(cacheControlDirectives[i], current);
316330

317-
// Skip the value if present
318-
if (current < cacheControlDirectives[i].Length && cacheControlDirectives[i][current] == '=')
319-
{
320-
current++; // skip '='
321-
current += NameValueHeaderValue.GetValueLength(cacheControlDirectives[i], current);
322-
current += HttpRuleParser.GetWhitespaceLength(cacheControlDirectives[i], current);
323-
}
331+
current = AdvanceCacheDirectiveIndex(current + tokenLength, cacheControlDirectives[i]);
324332

325-
// Skip the delimiter
326-
if (current < cacheControlDirectives[i].Length && cacheControlDirectives[i][current] == ',')
327-
{
328-
current++; // skip ','
329-
current += HttpRuleParser.GetWhitespaceLength(cacheControlDirectives[i], current);
330-
}
333+
// Ensure index was advanced
334+
if (current <= initial)
335+
{
336+
Debug.Assert(false, $"Index '{nameof(current)}' not advanced, this is a bug.");
337+
return false;
331338
}
332339
}
333340
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public void TryParseSeconds_Succeeds(string headerValues, string targetValue, in
7171
[InlineData("directive1", "directive")]
7272
[InlineData("h=directive", "directive")]
7373
[InlineData("directive1, directive2=80", "directive")]
74+
[InlineData("directive1=;, directive2=10", "directive1")]
7475
public void TryParseSeconds_Fails(string headerValues, string targetValue)
7576
{
7677
TimeSpan? value;
@@ -124,6 +125,7 @@ public void FormatInt64_MatchesToString(long value)
124125
[InlineData("directive1", "directive", false)]
125126
[InlineData("h=directive", "directive", false)]
126127
[InlineData("directive1, directive2=80", "directive", false)]
128+
[InlineData("directive1;, directive2=80", "directive", false)]
127129
public void ContainsCacheDirective_MatchesExactValue(string headerValues, string targetValue, bool contains)
128130
{
129131
Assert.Equal(contains, HeaderUtilities.ContainsCacheDirective(new StringValues(headerValues), targetValue));

0 commit comments

Comments
 (0)