Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 153de68

Browse files
Geoff Kizerstephentoub
authored andcommitted
fix HttpListener chunked encoding handling
1 parent d0c1b6a commit 153de68

File tree

4 files changed

+70
-27
lines changed

4 files changed

+70
-27
lines changed

src/System.Net.HttpListener/src/System/Net/Managed/ChunkStream.cs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
//
3232

3333
using System.Collections;
34+
using System.Diagnostics;
3435
using System.Collections.Generic;
3536
using System.Globalization;
3637
using System.IO;
@@ -79,12 +80,6 @@ public int Read(byte[] buffer, int offset, int size)
7980
private int _trailerState;
8081
private List<Chunk> _chunks;
8182

82-
public ChunkStream(byte[] buffer, int offset, int size, WebHeaderCollection headers)
83-
: this(headers)
84-
{
85-
Write(buffer, offset, size);
86-
}
87-
8883
public ChunkStream(WebHeaderCollection headers)
8984
{
9085
_headers = headers;
@@ -102,13 +97,6 @@ public void ResetBuffer()
10297
_chunks.Clear();
10398
}
10499

105-
public void WriteAndReadBack(byte[] buffer, int offset, int size, ref int read)
106-
{
107-
if (offset + read > 0)
108-
Write(buffer, offset, offset + read);
109-
read = Read(buffer, offset, size);
110-
}
111-
112100
public int Read(byte[] buffer, int offset, int size)
113101
{
114102
return ReadFromChunks(buffer, offset, size);
@@ -143,6 +131,10 @@ private int ReadFromChunks(byte[] buffer, int offset, int size)
143131

144132
public void Write(byte[] buffer, int offset, int size)
145133
{
134+
// Note, the logic here only works when offset is 0 here.
135+
// Otherwise, it would treat "size" as the end offset instead of an actual byte count from offset.
136+
Debug.Assert(offset == 0);
137+
146138
if (offset < size)
147139
InternalWrite(buffer, ref offset, size);
148140
}

src/System.Net.HttpListener/src/System/Net/Managed/ChunkedInputStream.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,19 @@ private void OnRead(IAsyncResult base_ares)
118118
try
119119
{
120120
int nread = base.EndRead(base_ares);
121+
if (nread == 0)
122+
{
123+
_no_more_data = true;
124+
ares._count = rb.InitialCount - rb.Count;
125+
ares.Complete();
126+
return;
127+
}
128+
121129
_decoder.Write(ares._buffer, ares._offset, nread);
122130
nread = _decoder.Read(rb.Buffer, rb.Offset, rb.Count);
123131
rb.Offset += nread;
124132
rb.Count -= nread;
125-
if (rb.Count == 0 || !_decoder.WantMore || nread == 0)
133+
if (rb.Count == 0 || !_decoder.WantMore)
126134
{
127135
_no_more_data = !_decoder.WantMore && nread == 0;
128136
ares._count = rb.InitialCount - rb.Count;

src/System.Net.HttpListener/src/System/Net/Managed/HttpStreamAsyncResult.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ public WaitHandle AsyncWaitHandle
9595
}
9696
}
9797

98-
public bool CompletedSynchronously
99-
{
100-
get { return (_synchRead == _count); }
101-
}
98+
public bool CompletedSynchronously => false;
10299

103100
public bool IsCompleted
104101
{

src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public void Dispose()
3333
}
3434

3535
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
36-
//[InlineData(true, "")] // [ActiveIssue(20246)] // CI hanging frequently
36+
[InlineData(true, "")]
3737
[InlineData(false, "")]
38-
//[InlineData(true, "Non-Empty")] // [ActiveIssue(20246)] // CI hanging frequently
38+
[InlineData(true, "Non-Empty")]
3939
[InlineData(false, "Non-Empty")]
4040
public async Task Read_FullLengthAsynchronous_Success(bool transferEncodingChunked, string text)
4141
{
@@ -77,9 +77,55 @@ public async Task Read_FullLengthAsynchronous_Success(bool transferEncodingChunk
7777
}
7878

7979
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
80-
// [InlineData(true, "")] // [ActiveIssue(20246)] // CI hanging frequently
80+
[InlineData(true, "")]
8181
[InlineData(false, "")]
82-
// [InlineData(true, "Non-Empty")] // [ActiveIssue(20246)] // CI hanging frequently
82+
[InlineData(true, "Non-Empty")]
83+
[InlineData(false, "Non-Empty")]
84+
public async Task Read_FullLengthAsynchronous_PadBuffer_Success(bool transferEncodingChunked, string text)
85+
{
86+
byte[] expected = Encoding.UTF8.GetBytes(text);
87+
Task<HttpListenerContext> contextTask = _listener.GetContextAsync();
88+
89+
using (HttpClient client = new HttpClient())
90+
{
91+
client.DefaultRequestHeaders.TransferEncodingChunked = transferEncodingChunked;
92+
Task<HttpResponseMessage> clientTask = client.PostAsync(_factory.ListeningUrl, new StringContent(text));
93+
94+
HttpListenerContext context = await contextTask;
95+
if (transferEncodingChunked)
96+
{
97+
Assert.Equal(-1, context.Request.ContentLength64);
98+
Assert.Equal("chunked", context.Request.Headers["Transfer-Encoding"]);
99+
}
100+
else
101+
{
102+
Assert.Equal(expected.Length, context.Request.ContentLength64);
103+
Assert.Null(context.Request.Headers["Transfer-Encoding"]);
104+
}
105+
106+
const int pad = 128;
107+
108+
// Add padding at beginning and end to test for correct offset/size handling
109+
byte[] buffer = new byte[pad + expected.Length + pad];
110+
int bytesRead = await context.Request.InputStream.ReadAsync(buffer, pad, expected.Length);
111+
Assert.Equal(expected.Length, bytesRead);
112+
Assert.Equal(expected, buffer.Skip(pad).Take(bytesRead));
113+
114+
// Subsequent reads don't do anything.
115+
Assert.Equal(0, await context.Request.InputStream.ReadAsync(buffer, pad, 1));
116+
117+
context.Response.Close();
118+
using (HttpResponseMessage response = await clientTask)
119+
{
120+
Assert.Equal(200, (int)response.StatusCode);
121+
}
122+
}
123+
}
124+
125+
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
126+
[InlineData(true, "")]
127+
[InlineData(false, "")]
128+
[InlineData(true, "Non-Empty")]
83129
[InlineData(false, "Non-Empty")]
84130
public async Task Read_FullLengthSynchronous_Success(bool transferEncodingChunked, string text)
85131
{
@@ -121,7 +167,7 @@ public async Task Read_FullLengthSynchronous_Success(bool transferEncodingChunke
121167
}
122168

123169
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
124-
// [InlineData(true)] // [ActiveIssue(20246)] // CI hanging frequently
170+
[InlineData(true)]
125171
[InlineData(false)]
126172
public async Task Read_LargeLengthAsynchronous_Success(bool transferEncodingChunked)
127173
{
@@ -160,7 +206,7 @@ public async Task Read_LargeLengthAsynchronous_Success(bool transferEncodingChun
160206
}
161207

162208
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
163-
// [InlineData(true)] // [ActiveIssue(20246)] // CI hanging frequently
209+
[InlineData(true)]
164210
[InlineData(false)]
165211
public async Task Read_LargeLengthSynchronous_Success(bool transferEncodingChunked)
166212
{
@@ -199,7 +245,7 @@ public async Task Read_LargeLengthSynchronous_Success(bool transferEncodingChunk
199245
}
200246

201247
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
202-
// [InlineData(true)] // [ActiveIssue(20246)] // CI hanging frequently
248+
[InlineData(true)]
203249
[InlineData(false)]
204250
public async Task Read_TooMuchAsynchronous_Success(bool transferEncodingChunked)
205251
{
@@ -224,7 +270,7 @@ public async Task Read_TooMuchAsynchronous_Success(bool transferEncodingChunked)
224270
}
225271

226272
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
227-
// [InlineData(true)] // [ActiveIssue(20246)] // CI hanging frequently
273+
[InlineData(true)]
228274
[InlineData(false)]
229275
public async Task Read_TooMuchSynchronous_Success(bool transferEncodingChunked)
230276
{
@@ -249,7 +295,7 @@ public async Task Read_TooMuchSynchronous_Success(bool transferEncodingChunked)
249295
}
250296

251297
[ConditionalTheory(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotOneCoreUAP))]
252-
// [InlineData(true)] // [ActiveIssue(20246)] // CI hanging frequently
298+
[InlineData(true)]
253299
[InlineData(false)]
254300
public async Task Read_NotEnoughThenCloseAsynchronous_Success(bool transferEncodingChunked)
255301
{

0 commit comments

Comments
 (0)