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

Commit

Permalink
Validate IAsyncResult used with managed HttpListener BeginRead/Write
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed May 29, 2017
1 parent 8e0a589 commit 4f81ce7
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 14 deletions.
Expand Up @@ -77,7 +77,7 @@ protected override int ReadCore(byte[] buffer, int offset, int count)

protected override IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state)
{
HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
ares._callback = cback;
ares._state = state;
if (_no_more_data || size == 0 || _closed)
Expand Down Expand Up @@ -146,8 +146,15 @@ public override int EndRead(IAsyncResult asyncResult)
throw new ArgumentNullException(nameof(asyncResult));

HttpStreamAsyncResult ares = asyncResult as HttpStreamAsyncResult;
if (asyncResult == null)
if (ares == null || !ReferenceEquals(this, ares._parent))
{
throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
}
if (ares._endCalled)
{
throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndRead)));
}
ares._endCalled = true;

if (!asyncResult.IsCompleted)
asyncResult.AsyncWaitHandle.WaitOne();
Expand Down
Expand Up @@ -30,6 +30,7 @@

using System.IO;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -112,7 +113,7 @@ protected virtual IAsyncResult BeginReadCore(byte[] buffer, int offset, int size
{
if (size == 0 || _closed)
{
HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
ares._callback = cback;
ares._state = state;
ares.Complete();
Expand All @@ -122,7 +123,7 @@ protected virtual IAsyncResult BeginReadCore(byte[] buffer, int offset, int size
int nread = FillFromBuffer(buffer, offset, size);
if (nread > 0 || nread == -1)
{
HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
ares._buffer = buffer;
ares._offset = offset;
ares._count = size;
Expand All @@ -148,18 +149,39 @@ public override int EndRead(IAsyncResult asyncResult)
if (asyncResult == null)
throw new ArgumentNullException(nameof(asyncResult));

if (asyncResult is HttpStreamAsyncResult)
if (asyncResult is HttpStreamAsyncResult r)
{
HttpStreamAsyncResult r = (HttpStreamAsyncResult)asyncResult;
if (!ReferenceEquals(this, r._parent))
{
throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
}
if (r._endCalled)
{
throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndRead)));
}
r._endCalled = true;

if (!asyncResult.IsCompleted)
{
asyncResult.AsyncWaitHandle.WaitOne();
}

return r._synchRead;
}

if (_closed)
return 0;

int nread = _stream.EndRead(asyncResult);
int nread = 0;
try
{
nread = _stream.EndRead(asyncResult);
}
catch (IOException e) when (e.InnerException is ArgumentException || e.InnerException is InvalidOperationException)
{
ExceptionDispatchInfo.Throw(e.InnerException);
}

if (_remainingBody > 0 && nread > 0)
{
_remainingBody -= nread;
Expand Down
Expand Up @@ -31,6 +31,7 @@
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -207,7 +208,7 @@ private IAsyncResult BeginWriteCore(byte[] buffer, int offset, int size, AsyncCa
{
if (_closed)
{
HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
ares._callback = cback;
ares._state = state;
ares.Complete();
Expand Down Expand Up @@ -245,7 +246,7 @@ private IAsyncResult BeginWriteCore(byte[] buffer, int offset, int size, AsyncCa
{
if (_ignore_errors)
{
HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
ares._callback = cback;
ares._state = state;
ares.Complete();
Expand Down Expand Up @@ -283,10 +284,17 @@ private void EndWriteCore(IAsyncResult asyncResult)
}
catch (IOException ex)
{
// NetworkStream wraps exceptions in IOExceptions; if the underlying socket operation
// failed because of invalid arguments or usage, propagate that error. Otherwise
// wrap the whole thing in an HttpListenerException. This is all to match Windows behavior.
if (ex.InnerException is ArgumentException || ex.InnerException is InvalidOperationException)
{
ExceptionDispatchInfo.Throw(ex.InnerException);
}

throw new HttpListenerException(ex.HResult, ex.Message);
}
}
}
}
}

Expand Up @@ -39,13 +39,20 @@ internal class HttpStreamAsyncResult : IAsyncResult
private ManualResetEvent _handle;
private bool _completed;

internal readonly object _parent;
internal byte[] _buffer;
internal int _offset;
internal int _count;
internal AsyncCallback _callback;
internal object _state;
internal int _synchRead;
internal Exception _error;
internal bool _endCalled;

internal HttpStreamAsyncResult(object parent)
{
_parent = parent;
}

public void Complete(Exception e)
{
Expand Down
2 changes: 0 additions & 2 deletions src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs
Expand Up @@ -416,7 +416,6 @@ public async Task EndRead_NullAsyncResult_ThrowsArgumentNullException(bool chunk
[Theory]
[InlineData(true)]
[InlineData(false)]
[ActiveIssue(18128, platforms: TestPlatforms.AnyUnix)] // No validation performed
public async Task EndRead_InvalidAsyncResult_ThrowsArgumentException(bool chunked)
{
HttpListenerRequest request1 = await _helper.GetRequest(chunked);
Expand All @@ -435,7 +434,6 @@ public async Task EndRead_InvalidAsyncResult_ThrowsArgumentException(bool chunke
[Theory]
[InlineData(true)]
[InlineData(false)]
[ActiveIssue(18128, platforms: TestPlatforms.AnyUnix)] // No validation performed
public async Task EndRead_CalledTwice_ThrowsInvalidOperationException(bool chunked)
{
HttpListenerRequest request = await _helper.GetRequest(chunked);
Expand Down
2 changes: 0 additions & 2 deletions src/System.Net.HttpListener/tests/HttpResponseStreamTests.cs
Expand Up @@ -550,7 +550,6 @@ public async Task EndWrite_NullAsyncResult_ThrowsArgumentNullException(bool igno
}

[Fact]
[ActiveIssue(18128, platforms: TestPlatforms.AnyUnix)]
public async Task EndWrite_InvalidAsyncResult_ThrowsArgumentException()
{
using (HttpListenerResponse response1 = await _helper.GetResponse())
Expand All @@ -566,7 +565,6 @@ public async Task EndWrite_InvalidAsyncResult_ThrowsArgumentException()
}

[Fact]
[ActiveIssue(18128, platforms: TestPlatforms.AnyUnix)]
public async Task EndWrite_CalledTwice_ThrowsInvalidOperationException()
{
using (HttpListenerResponse response1 = await _helper.GetResponse())
Expand Down

0 comments on commit 4f81ce7

Please sign in to comment.