Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, Cancel
OperationCanceledException oce = _completed as OperationCanceledException;
return (oce != null && oce.CancellationToken.IsCancellationRequested) ?
Task.FromCanceled<int>(oce.CancellationToken) :
Task.FromException<int>(_completed);
Task.FromException<int>(MapToReadWriteIOException(_completed, isRead: true));
}

// Quick check for if no data was actually requested. We do this after the check
Expand Down Expand Up @@ -380,7 +380,7 @@ internal void SignalComplete(Exception error = null)
}
else
{
_pendingReadRequest.TrySetException(_completed);
_pendingReadRequest.TrySetException(MapToReadWriteIOException(_completed, isRead: true));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
// If we've been disposed, throw an exception so as to end the CopyToAsync operation.
if (_disposed)
{
throw CreateHttpRequestException();
throw new ObjectDisposedException(GetType().FullName);
}

if (_buffer == null)
Expand Down Expand Up @@ -349,7 +349,7 @@ private void EndCopyToAsync(Task completedCopy)
Debug.Assert(_waiterIsReader, "We're done writing, so a waiter must be a reader");
if (completedCopy.IsFaulted)
{
_asyncOp.TrySetException(completedCopy.Exception.InnerException);
_asyncOp.TrySetException(MapToReadWriteIOException(completedCopy.Exception.InnerException, isRead: _waiterIsReader));
_copyTask = completedCopy;
}
else if (completedCopy.IsCanceled)
Expand Down
12 changes: 10 additions & 2 deletions src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;

using CURLAUTH = Interop.Http.CURLAUTH;
using CURLcode = Interop.Http.CURLcode;
Expand Down Expand Up @@ -625,11 +626,18 @@ private static void EventSourceTraceCore(string message, MultiAgent agent, EasyR
message);
}

private static Exception CreateHttpRequestException(Exception inner = null)
private static HttpRequestException CreateHttpRequestException(Exception inner = null)
{
return new HttpRequestException(SR.net_http_client_execution_error, inner);
}

private static IOException MapToReadWriteIOException(Exception error, bool isRead)
{
return new IOException(
isRead ? SR.net_http_io_read : SR.net_http_io_write,
error is HttpRequestException && error.InnerException != null ? error.InnerException : error);
}

private static bool TryParseStatusLine(HttpResponseMessage response, string responseHeader, EasyRequest state)
{
if (!responseHeader.StartsWith(CurlResponseParseUtils.HttpPrefix, StringComparison.OrdinalIgnoreCase))
Expand Down
51 changes: 50 additions & 1 deletion src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.IO;
using System.Net.Sockets;
using System.Net.Test.Common;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -90,6 +91,54 @@ await client.GetAsync(HttpTestServers.RemoteEchoServer, HttpCompletionOption.Res
}
}

[ActiveIssue(6231, PlatformID.Windows)]
[Fact]
public async Task ReadAsStreamAsync_IncompleteContentLengthResponse_ThrowsIOException()
{
var server = new TcpListener(IPAddress.Loopback, 0);
Task serverTask = ((Func<Task>)async delegate {
server.Start();
using (var client = await server.AcceptSocketAsync())
using (var stream = new NetworkStream(client))
using (var reader = new StreamReader(stream, Encoding.ASCII))
{
// Read request
string line;
while (!string.IsNullOrEmpty(line = reader.ReadLine())) ;

// Write response, with a potentially invalid content length
using (var writer = new StreamWriter(stream, Encoding.ASCII))
{
string content = "This is some response content.";
writer.Write("HTTP/1.1 200 OK\r\n");
writer.Write($"Date: {DateTimeOffset.UtcNow:R}\r\n");
writer.Write("Content-Type: text/plain\r\n");
writer.Write($"Content-Length: {content.Length + 42}\r\n"); // incorrect length
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think we were able to use this construct yet? The TFS mirrored builds are still C# 5, I think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with #6181. Hence the very large #6209 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good to know.

writer.Write("\r\n");
writer.Write(content);
writer.Flush();
}

client.Shutdown(SocketShutdown.Both);
}
})();

using (var client = new HttpClient())
{
var local = (IPEndPoint)server.LocalEndpoint;
using (var response = await client.GetAsync(new Uri($"http://localhost:{((IPEndPoint)server.LocalEndpoint).Port}/"), HttpCompletionOption.ResponseHeadersRead))
using (var stream = await response.Content.ReadAsStreamAsync())
{
await Assert.ThrowsAsync<IOException>(async () => {
var buffer = new byte[1];
while (await stream.ReadAsync(buffer, 0, 1) > 0) ;
});
}
}

await serverTask;
}

// These methods help to validate the response body since the endpoint will echo
// all request headers.
//
Expand Down
1 change: 1 addition & 0 deletions src/System.Net.Http/tests/FunctionalTests/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"System.IO": "4.0.10",
"System.IO.FileSystem": "4.0.0",
"System.Net.Primitives": "4.0.11-rc3-23818",
"System.Net.Sockets": "4.1.0-rc3-23818",
"System.Runtime.Extensions": "4.0.10",
"System.Security.Cryptography.Algorithms": "4.0.0-rc3-23818",
"System.Text.Encoding": "4.0.10",
Expand Down