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

Commit e376494

Browse files
committed
Fix MemoryPoolIterator2.CopyTo's block traversal
- This fix prevents large request streams from being corrupted #234
1 parent 7e386ab commit e376494

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ public MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int a
442442
else
443443
{
444444
Buffer.BlockCopy(block.Array, index, array, offset, following);
445+
offset += following;
445446
remaining -= following;
446447
block = block.Next;
447448
index = block.Start;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Globalization;
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNet.Builder;
9+
using Microsoft.AspNet.Hosting;
10+
using Microsoft.AspNet.Http;
11+
using Microsoft.Dnx.Runtime.Infrastructure;
12+
using Microsoft.Extensions.Configuration;
13+
using Xunit;
14+
15+
namespace Microsoft.AspNet.Server.Kestrel.FunctionalTests
16+
{
17+
public class RequestTests
18+
{
19+
[Fact]
20+
public async Task LargeUpload()
21+
{
22+
var config = new ConfigurationBuilder()
23+
.AddInMemoryCollection(new Dictionary<string, string>
24+
{
25+
{ "server.urls", "http://localhost:8791/" }
26+
})
27+
.Build();
28+
29+
var hostBuilder = new WebHostBuilder(CallContextServiceLocator.Locator.ServiceProvider, config);
30+
hostBuilder.UseServer("Microsoft.AspNet.Server.Kestrel");
31+
hostBuilder.UseStartup(app =>
32+
{
33+
app.Run(async context =>
34+
{
35+
// Read the full request body
36+
var total = 0;
37+
var bytes = new byte[1024];
38+
var count = await context.Request.Body.ReadAsync(bytes, 0, bytes.Length);
39+
while (count > 0)
40+
{
41+
for (int i = 0; i < count; i++)
42+
{
43+
Assert.Equal(total % 256, bytes[i]);
44+
total++;
45+
}
46+
count = await context.Request.Body.ReadAsync(bytes, 0, bytes.Length);
47+
}
48+
49+
await context.Response.WriteAsync(total.ToString(CultureInfo.InvariantCulture));
50+
});
51+
});
52+
53+
using (var app = hostBuilder.Build().Start())
54+
{
55+
using (var client = new HttpClient())
56+
{
57+
var bytes = new byte[1024 * 1024];
58+
for (int i = 0; i < bytes.Length; i++)
59+
{
60+
bytes[i] = (byte)i;
61+
}
62+
63+
var response = await client.PostAsync("http://localhost:8791/", new ByteArrayContent(bytes));
64+
response.EnsureSuccessStatusCode();
65+
var sizeString = await response.Content.ReadAsStringAsync();
66+
Assert.Equal(sizeString, bytes.Length.ToString(CultureInfo.InvariantCulture));
67+
}
68+
}
69+
}
70+
}
71+
}

test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,41 @@ public void AddDoesNotAdvanceAtEndOfCurrentBlock()
117117
}
118118
}
119119

120+
[Fact]
121+
public void CopyToCorrectlyTraversesBlocks()
122+
{
123+
using (var pool = new MemoryPool2())
124+
{
125+
var block1 = pool.Lease(128);
126+
var block2 = block1.Next = pool.Lease(128);
127+
128+
for (int i = 0; i < 128; i++)
129+
{
130+
block1.Array[block1.End++] = (byte)i;
131+
}
132+
for (int i = 128; i < 256; i++)
133+
{
134+
block2.Array[block2.End++] = (byte)i;
135+
}
136+
137+
var beginIterator = block1.GetIterator();
138+
139+
var array = new byte[256];
140+
int actual;
141+
var endIterator = beginIterator.CopyTo(array, 0, 256, out actual);
142+
143+
Assert.Equal(256, actual);
144+
145+
for (int i = 0; i < 256; i++)
146+
{
147+
Assert.Equal(i, array[i]);
148+
}
149+
150+
endIterator.CopyTo(array, 0, 256, out actual);
151+
Assert.Equal(0, actual);
152+
}
153+
}
154+
120155
private void AssertIterator(MemoryPoolIterator2 iter, MemoryPoolBlock2 block, int index)
121156
{
122157
Assert.Same(block, iter.Block);

0 commit comments

Comments
 (0)