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

Commit 56cdc67

Browse files
committed
Add extra contentlength tests
1 parent 0697e35 commit 56cdc67

File tree

6 files changed

+168
-24
lines changed

6 files changed

+168
-24
lines changed

src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.Generated.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9839,7 +9839,7 @@ protected void CopyToFast(ref MemoryPoolIterator output)
98399839
if (ContentLength.HasValue)
98409840
{
98419841
output.CopyFrom(_headerBytes, 592, 18);
9842-
output.CopyFromNumeric(ContentLength.Value);
9842+
output.CopyFromNumeric((ulong)ContentLength.Value);
98439843

98449844
tempBits &= ~-9223372036854775808L;
98459845
if(tempBits == 0)

src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
1313
{
1414
public abstract class FrameHeaders : IHeaderDictionary
1515
{
16+
private long? _contentLength;
1617
protected bool _isReadOnly;
1718
protected Dictionary<string, StringValues> MaybeUnknown;
1819
protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase));
1920

20-
public long? ContentLength { get; set; }
21+
public long? ContentLength {
22+
get { return _contentLength; }
23+
set
24+
{
25+
if (value.HasValue && value.Value < 0)
26+
{
27+
ThrowInvalidResponseContentLengthException(value.Value);
28+
}
29+
_contentLength = value;
30+
}
31+
}
2132

2233
StringValues IHeaderDictionary.this[string key]
2334
{
@@ -424,6 +435,11 @@ public static unsafe TransferCoding GetFinalTransferCoding(StringValues transfer
424435
return transferEncodingOptions;
425436
}
426437

438+
protected static void ThrowInvalidResponseContentLengthException(long value)
439+
{
440+
throw new ArgumentOutOfRangeException($"Invalid Content-Length: \"{value}\". Value must be a positive integral number.");
441+
}
442+
427443
protected static void ThrowInvalidResponseContentLengthException(string value)
428444
{
429445
throw new InvalidOperationException($"Invalid Content-Length: \"{value}\". Value must be a positive integral number.");

src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/MemoryPoolIterator.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
1313
{
1414
public struct MemoryPoolIterator
1515
{
16-
private const int _maxPositiveLongByteLength = 19;
16+
private const int _maxULongByteLength = 20;
1717
private const ulong _xorPowerOfTwoToHighByte = (0x07ul |
1818
0x06ul << 8 |
1919
0x05ul << 16 |
@@ -1091,12 +1091,14 @@ public unsafe void CopyFromAscii(string data)
10911091
[MethodImpl(MethodImplOptions.NoInlining)]
10921092
private static byte[] CreateNumericBytesScratch()
10931093
{
1094-
return (_numericBytesScratch = new byte[_maxPositiveLongByteLength]);
1094+
var bytes = new byte[_maxULongByteLength];
1095+
_numericBytesScratch = bytes;
1096+
return bytes;
10951097
}
10961098

1097-
public void CopyFromNumeric(long value)
1099+
public void CopyFromNumeric(ulong value)
10981100
{
1099-
var position = _maxPositiveLongByteLength;
1101+
var position = _maxULongByteLength;
11001102
var byteBuffer = NumericBytesScratch;
11011103
do
11021104
{
@@ -1107,7 +1109,7 @@ public void CopyFromNumeric(long value)
11071109
}
11081110
while (value != 0);
11091111

1110-
CopyFrom(byteBuffer, position, _maxPositiveLongByteLength - position);
1112+
CopyFrom(byteBuffer, position, _maxULongByteLength - position);
11111113
}
11121114

11131115
public unsafe string GetAsciiString(ref MemoryPoolIterator end)

test/Microsoft.AspNetCore.Server.KestrelTests/FrameHeadersTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
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 System;
5+
using System.Collections.Generic;
46
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
57
using Microsoft.Extensions.Primitives;
8+
using Microsoft.Net.Http.Headers;
69
using Xunit;
710

811
namespace Microsoft.AspNetCore.Server.KestrelTests
@@ -223,5 +226,65 @@ public void TestParseTransferEncodingMultipleValues(string value1, string value2
223226
var transferEncodingOptions = FrameHeaders.GetFinalTransferCoding(transferEncoding);
224227
Assert.Equal(expectedTransferEncodingOptions, transferEncodingOptions);
225228
}
229+
230+
[Fact]
231+
public void ValidContentLengthsAccepted()
232+
{
233+
ValidContentLengthsAccepted(new FrameRequestHeaders());
234+
ValidContentLengthsAccepted(new FrameResponseHeaders());
235+
}
236+
237+
private static void ValidContentLengthsAccepted(FrameHeaders frameHeaders)
238+
{
239+
IDictionary<string, StringValues> headers = frameHeaders;
240+
241+
StringValues value;
242+
243+
Assert.False(headers.TryGetValue("Content-Length", out value));
244+
Assert.Equal(null, frameHeaders.ContentLength);
245+
Assert.False(frameHeaders.ContentLength.HasValue);
246+
247+
frameHeaders.ContentLength = 1;
248+
Assert.True(headers.TryGetValue("Content-Length", out value));
249+
Assert.Equal("1", value[0]);
250+
Assert.Equal(1, frameHeaders.ContentLength);
251+
Assert.True(frameHeaders.ContentLength.HasValue);
252+
253+
frameHeaders.ContentLength = long.MaxValue;
254+
Assert.True(headers.TryGetValue("Content-Length", out value));
255+
Assert.Equal(HeaderUtilities.FormatInt64(long.MaxValue), value[0]);
256+
Assert.Equal(long.MaxValue, frameHeaders.ContentLength);
257+
Assert.True(frameHeaders.ContentLength.HasValue);
258+
259+
frameHeaders.ContentLength = null;
260+
Assert.False(headers.TryGetValue("Content-Length", out value));
261+
Assert.Equal(null, frameHeaders.ContentLength);
262+
Assert.False(frameHeaders.ContentLength.HasValue);
263+
}
264+
265+
[Fact]
266+
public void InvalidContentLengthsRejected()
267+
{
268+
InvalidContentLengthsRejected(new FrameRequestHeaders());
269+
InvalidContentLengthsRejected(new FrameResponseHeaders());
270+
}
271+
272+
private static void InvalidContentLengthsRejected(FrameHeaders frameHeaders)
273+
{
274+
IDictionary<string, StringValues> headers = frameHeaders;
275+
276+
StringValues value;
277+
278+
Assert.False(headers.TryGetValue("Content-Length", out value));
279+
Assert.Equal(null, frameHeaders.ContentLength);
280+
Assert.False(frameHeaders.ContentLength.HasValue);
281+
282+
Assert.Throws<ArgumentOutOfRangeException>(() => frameHeaders.ContentLength = -1);
283+
Assert.Throws<ArgumentOutOfRangeException>(() => frameHeaders.ContentLength = long.MinValue);
284+
285+
Assert.False(headers.TryGetValue("Content-Length", out value));
286+
Assert.Equal(null, frameHeaders.ContentLength);
287+
Assert.False(frameHeaders.ContentLength.HasValue);
288+
}
226289
}
227290
}

0 commit comments

Comments
 (0)