Skip to content

Commit d0cca51

Browse files
authored
Set ContentLength for TestHost (#24107)
1 parent e3501dd commit d0cca51

File tree

2 files changed

+68
-6
lines changed

2 files changed

+68
-6
lines changed

src/Hosting/TestHost/src/ClientHandler.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ protected override async Task<HttpResponseMessage> SendAsync(
100100
if (request.Version == HttpVersion.Version20)
101101
{
102102
// https://tools.ietf.org/html/rfc7540
103-
req.Protocol = HttpProtocol.Http2;
103+
req.Protocol = HttpProtocol.Http2;
104104
}
105105
else
106106
{
@@ -142,12 +142,13 @@ protected override async Task<HttpResponseMessage> SendAsync(
142142
}
143143
req.QueryString = QueryString.FromUriComponent(request.RequestUri);
144144

145-
if (requestContent != null)
145+
// Reading the ContentLength will add it to the Headers‼
146+
// https://github.com/dotnet/runtime/blob/874399ab15e47c2b4b7c6533cc37d27d47cb5242/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpContentHeaders.cs#L68-L87
147+
_ = requestContent.Headers.ContentLength;
148+
149+
foreach (var header in requestContent.Headers)
146150
{
147-
foreach (var header in requestContent.Headers)
148-
{
149-
req.Headers.Append(header.Key, header.Value.ToArray());
150-
}
151+
req.Headers.Append(header.Key, header.Value.ToArray());
151152
}
152153

153154
req.Body = new AsyncStreamWrapper(reader.AsStream(), () => contextBuilder.AllowSynchronousIO);

src/Hosting/TestHost/test/ClientHandlerTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
using System;
55
using System.IO;
66
using System.Linq;
7+
using System.Net;
78
using System.Net.Http;
9+
using System.Text;
810
using System.Threading;
911
using System.Threading.Tasks;
1012
using Microsoft.AspNetCore.Builder;
@@ -103,6 +105,51 @@ public Task UserAgentHeaderWorks()
103105
return httpClient.GetAsync("http://example.com");
104106
}
105107

108+
[Fact]
109+
public Task ContentLengthWithBodyWorks()
110+
{
111+
var contentBytes = Encoding.UTF8.GetBytes("This is a content!");
112+
var handler = new ClientHandler(new PathString(""), new DummyApplication(context =>
113+
{
114+
Assert.Equal(contentBytes.LongLength, context.Request.ContentLength);
115+
116+
return Task.CompletedTask;
117+
}));
118+
var httpClient = new HttpClient(handler);
119+
var content = new ByteArrayContent(contentBytes);
120+
121+
return httpClient.PostAsync("http://example.com", content);
122+
}
123+
124+
[Fact]
125+
public Task ContentLengthWithNoBodyWorks()
126+
{
127+
var handler = new ClientHandler(new PathString(""), new DummyApplication(context =>
128+
{
129+
Assert.Equal(0, context.Request.ContentLength);
130+
131+
return Task.CompletedTask;
132+
}));
133+
var httpClient = new HttpClient(handler);
134+
135+
return httpClient.GetAsync("http://example.com");
136+
}
137+
138+
[Fact]
139+
public Task ContentLengthWithChunkedTransferEncodingWorks()
140+
{
141+
var handler = new ClientHandler(new PathString(""), new DummyApplication(context =>
142+
{
143+
Assert.Null(context.Request.ContentLength);
144+
145+
return Task.CompletedTask;
146+
}));
147+
148+
var httpClient = new HttpClient(handler);
149+
150+
return httpClient.PostAsync("http://example.com", new UnlimitedContent());
151+
}
152+
106153
[Fact]
107154
public async Task ServerTrailersSetOnResponseAfterContentRead()
108155
{
@@ -566,5 +613,19 @@ public void Dispose()
566613
}
567614
}
568615
}
616+
617+
private class UnlimitedContent : HttpContent
618+
{
619+
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
620+
{
621+
return Task.CompletedTask;
622+
}
623+
624+
protected override bool TryComputeLength(out long length)
625+
{
626+
length = -1;
627+
return false;
628+
}
629+
}
569630
}
570631
}

0 commit comments

Comments
 (0)