Skip to content
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
4 changes: 2 additions & 2 deletions src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ private async Task<List<byte[]>> ReadRequestHeaderBytesAsync()
public async Task WriteStringAsync(string s)
{
byte[] bytes = Encoding.ASCII.GetBytes(s);
await _stream.WriteAsync(bytes);
await _stream.WriteAsync(bytes, 0, bytes.Length);
}

public async Task SendResponseAsync(string response)
Expand All @@ -736,7 +736,7 @@ public async Task SendResponseAsync(string response)

public async Task SendResponseAsync(byte[] response)
{
await _stream.WriteAsync(response);
await _stream.WriteAsync(response, 0, response.Length);
}

public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
<IsPackable>true</IsPackable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<ServicingVersion>1</ServicingVersion>
<PackageDescription>Provides extension methods for System.Net.Http.HttpClient and System.Net.Http.HttpContent that perform automatic serialization and deserialization using System.Text.Json.

Commonly Used Types:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore(taskResponse, type, options, cancellationToken);
}

Expand All @@ -37,7 +37,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore(taskResponse, type, options, cancellationToken);
}

Expand All @@ -50,7 +50,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore<TValue>(taskResponse, options, cancellationToken);
}

Expand All @@ -63,7 +63,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore<TValue>(taskResponse, options, cancellationToken);
}

Expand All @@ -74,7 +74,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore(taskResponse, type, context, cancellationToken);
}

Expand All @@ -85,7 +85,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore(taskResponse, type, context, cancellationToken);
}

Expand All @@ -96,7 +96,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore(taskResponse, jsonTypeInfo, cancellationToken);
}

Expand All @@ -107,7 +107,7 @@ public static partial class HttpClientJsonExtensions
throw new ArgumentNullException(nameof(client));
}

Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Task<HttpResponseMessage> taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
return GetFromJsonAsyncCore<TValue>(taskResponse, jsonTypeInfo, cancellationToken);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,5 +354,92 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync(
await server.HandleRequestAsync(content: json, headers: headers);
});
}

public static IEnumerable<object[]> GetFromJsonAsync_EnforcesMaxResponseContentBufferSize_MemberData() =>
from useDeleteAsync in new[] { true, false }
from limit in new[] { 2, 100, 100000 }
from contentLength in new[] { limit, limit + 1 }
from chunked in new[] { true, false }
select new object[] { useDeleteAsync, limit, contentLength, chunked };

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // No Socket support
[MemberData(nameof(GetFromJsonAsync_EnforcesMaxResponseContentBufferSize_MemberData))]
public async Task GetFromJsonAsync_EnforcesMaxResponseContentBufferSize(bool useDeleteAsync, int limit, int contentLength, bool chunked)
{
await LoopbackServer.CreateClientAndServerAsync(async uri =>
{
using var client = new HttpClient { MaxResponseContentBufferSize = limit };

Func<Task> testMethod = () => useDeleteAsync ? client.DeleteFromJsonAsync<string>(uri) : client.GetFromJsonAsync<string>(uri);

if (contentLength > limit)
{
Exception ex = await Assert.ThrowsAsync<HttpRequestException>(testMethod);
Assert.Contains(limit.ToString(), ex.Message);
}
else
{
await testMethod();
}
},
async server =>
{
List<HttpHeaderData> headers = new();
string content = $"\"{new string('a', contentLength - 2)}\"";

if (chunked)
{
headers.Add(new HttpHeaderData("Transfer-Encoding", "chunked"));
content = $"{Convert.ToString(contentLength, 16)}\r\n{content}\r\n0\r\n\r\n";
}

await server.HandleRequestAsync(headers: headers, content: content);
});
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // No Socket support
[InlineData(true, true)]
[InlineData(true, false)]
[InlineData(false, true)]
[InlineData(false, false)]
public async Task GetFromJsonAsync_EnforcesTimeout(bool useDeleteAsync, bool slowHeaders)
{
TaskCompletionSource<byte> exceptionThrown = new(TaskCreationOptions.RunContinuationsAsynchronously);

await LoopbackServer.CreateClientAndServerAsync(async uri =>
{
using var client = new HttpClient { Timeout = TimeSpan.FromMilliseconds(100) };

Exception ex = await Assert.ThrowsAsync<TaskCanceledException>(() =>
useDeleteAsync ? client.DeleteFromJsonAsync<string>(uri) : client.GetFromJsonAsync<string>(uri));

#if NETCORE
Assert.Contains("HttpClient.Timeout", ex.Message);
Assert.IsType<TimeoutException>(ex.InnerException);
#endif

exceptionThrown.SetResult(0);
},
async server =>
{
// The client may timeout before even connecting the server
await Task.WhenAny(exceptionThrown.Task, Task.Run(async () =>
{
try
{
await server.AcceptConnectionAsync(async connection =>
{
if (!slowHeaders)
{
await connection.SendPartialResponseHeadersAsync(headers: new[] { new HttpHeaderData("Content-Length", "42") });
}

await exceptionThrown.Task;
});
}
catch { }
}));
});
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);net48</TargetFrameworks>
</PropertyGroup>
Expand All @@ -13,11 +13,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)System\Net\Capability.Security.cs" Link="Common\System\Net\Capability.Security.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.Certificates.cs" Link="Common\System\Net\Configuration.Certificates.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.cs" Link="Common\System\Net\Configuration.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.Http.cs" Link="Common\System\Net\Configuration.Http.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.Security.cs" Link="Common\System\Net\Configuration.Security.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\HttpMessageHandlerLoopbackServer.cs" Link="Common\System\Net\Http\HttpMessageHandlerLoopbackServer.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\GenericLoopbackServer.cs" Link="Common\System\Net\Http\GenericLoopbackServer.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\LoopbackServer.cs" Link="Common\System\Net\Http\LoopbackServer.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\PlatformSupport.cs" Link="CommonTest\System\Security\Cryptography\PlatformSupport.cs" />
<Compile Include="$(CommonTestPath)System\Threading\Tasks\TaskTimeoutExtensions.cs" Link="Common\System\Threading\Tasks\TaskTimeoutExtensions.cs" />
</ItemGroup>
Expand Down