Skip to content

Commit 59417ef

Browse files
geoffkizerGeoffrey Kizer
andauthored
Get rid of StreamWriter usage in HTTP loopback server and fix HTTP/1.1 loopback implementation of SendResponseBodyAsync (#47364)
Get rid of StreamWriter usage in HTTP loopback server and fix HTTP/1.1 loopback implementation of SendResponseBodyAsync Co-authored-by: Geoffrey Kizer <geoffrek@windows.microsoft.com>
1 parent fdc8148 commit 59417ef

15 files changed

+54
-45
lines changed

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Asynchrony.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ await LoopbackServer.CreateClientAndServerAsync(uri =>
5959
await server.AcceptConnectionAsync(async connection =>
6060
{
6161
await connection.ReadRequestHeaderAsync();
62-
await connection.Writer.WriteAsync(
62+
await connection.WriteStringAsync(
6363
LoopbackServer.GetContentModeResponse(
6464
contentMode,
6565
string.Concat(Enumerable.Repeat('s', 10_000)),

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,10 @@ await LoopbackServer.CreateServerAsync(async (server, url) =>
351351
Task serverTask1 = server.AcceptConnectionAsync(async connection1 =>
352352
{
353353
await connection1.ReadRequestHeaderAsync();
354-
await connection1.Writer.WriteAsync($"HTTP/1.1 200 OK\r\nConnection: close\r\nDate: {DateTimeOffset.UtcNow:R}\r\n");
354+
await connection1.WriteStringAsync($"HTTP/1.1 200 OK\r\nConnection: close\r\nDate: {DateTimeOffset.UtcNow:R}\r\n");
355355
serverAboutToBlock.SetResult(true);
356356
await blockServerResponse.Task;
357-
await connection1.Writer.WriteAsync("Content-Length: 5\r\n\r\nhello");
357+
await connection1.WriteStringAsync("Content-Length: 5\r\n\r\nhello");
358358
});
359359

360360
Task get1 = client.GetAsync(url);

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
101101
await server.AcceptConnectionAsync(async connection =>
102102
{
103103
await connection.ReadRequestHeaderAsync();
104-
await connection.Writer.WriteAsync($"HTTP/1.1 200 OK\r\nContent-Encoding: {encodingName}\r\n\r\n");
104+
await connection.WriteStringAsync($"HTTP/1.1 200 OK\r\nContent-Encoding: {encodingName}\r\n\r\n");
105105
using (Stream compressedStream = compress(connection.Stream))
106106
{
107107
await compressedStream.WriteAsync(expectedContent);
@@ -163,7 +163,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
163163
await server.AcceptConnectionAsync(async connection =>
164164
{
165165
await connection.ReadRequestHeaderAsync();
166-
await connection.Writer.WriteAsync($"HTTP/1.1 200 OK\r\nContent-Encoding: {encodingName}\r\n\r\n");
166+
await connection.WriteStringAsync($"HTTP/1.1 200 OK\r\nContent-Encoding: {encodingName}\r\n\r\n");
167167
await connection.Stream.WriteAsync(compressedContent);
168168
});
169169
});

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.MaxResponseHeadersLength.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ await server.AcceptConnectionAsync(async connection =>
8686
{
8787
while (!cts.IsCancellationRequested)
8888
{
89-
await connection.Writer.WriteAsync(new string('s', 16000));
89+
await connection.WriteStringAsync(new string('s', 16000));
9090
await Task.Delay(1);
9191
}
9292
}

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -969,12 +969,11 @@ await LoopbackServer.CreateServerAsync(async (server, url) =>
969969
Task serverTask = server.AcceptConnectionAsync(async connection =>
970970
{
971971
await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
972-
TextWriter writer = connection.Writer;
973972
try
974973
{
975974
while (!cts.IsCancellationRequested) // infinite to make sure implementation doesn't OOM
976975
{
977-
await writer.WriteAsync(new string(' ', 10000));
976+
await connection.WriteStringAsync(new string(' ', 10000));
978977
await Task.Delay(1);
979978
}
980979
}

src/libraries/Common/tests/System/Net/Http/HttpProtocolTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,18 +442,18 @@ await server.AcceptConnectionAsync(async connection =>
442442
{
443443
await connection.ReadRequestHeaderAsync();
444444

445-
await connection.Writer.WriteAsync($"HTTP/1.1 200 OK{lineEnding}Transfer-Encoding: chunked{lineEnding}{lineEnding}");
445+
await connection.WriteStringAsync($"HTTP/1.1 200 OK{lineEnding}Transfer-Encoding: chunked{lineEnding}{lineEnding}");
446446
for (int bytesSent = 0; bytesSent < expectedData.Length;)
447447
{
448448
int bytesRemaining = expectedData.Length - bytesSent;
449449
int bytesToSend = rand.Next(1, Math.Min(bytesRemaining, maxChunkSize + 1));
450-
await connection.Writer.WriteAsync(bytesToSend.ToString("X") + lineEnding);
450+
await connection.WriteStringAsync(bytesToSend.ToString("X") + lineEnding);
451451
await connection.Stream.WriteAsync(new Memory<byte>(expectedData, bytesSent, bytesToSend));
452-
await connection.Writer.WriteAsync(lineEnding);
452+
await connection.WriteStringAsync(lineEnding);
453453
bytesSent += bytesToSend;
454454
}
455-
await connection.Writer.WriteAsync($"0{lineEnding}");
456-
await connection.Writer.WriteAsync(lineEnding);
455+
await connection.WriteStringAsync($"0{lineEnding}");
456+
await connection.WriteStringAsync(lineEnding);
457457
});
458458
});
459459
}

src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ public sealed class Connection : GenericLoopbackConnection
397397
private const int BufferSize = 4000;
398398
private Socket _socket;
399399
private Stream _stream;
400-
private StreamWriter _writer;
401400
private byte[] _readBuffer;
402401
private int _readStart;
403402
private int _readEnd;
@@ -409,16 +408,13 @@ public Connection(Socket socket, Stream stream)
409408
_socket = socket;
410409
_stream = stream;
411410

412-
_writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true };
413-
414411
_readBuffer = new byte[BufferSize];
415412
_readStart = 0;
416413
_readEnd = 0;
417414
}
418415

419416
public Socket Socket => _socket;
420417
public Stream Stream => _stream;
421-
public StreamWriter Writer => _writer;
422418

423419
public static async Task<Connection> CreateAsync(Socket socket, Stream stream, Options httpOptions)
424420
{
@@ -620,7 +616,6 @@ public override void Dispose()
620616
}
621617
catch (Exception) { }
622618

623-
_writer.Dispose();
624619
_stream.Dispose();
625620
_socket?.Dispose();
626621
}
@@ -673,9 +668,20 @@ private async Task<List<byte[]>> ReadRequestHeaderBytesAsync()
673668
return lines;
674669
}
675670

671+
public async Task WriteStringAsync(string s)
672+
{
673+
byte[] bytes = Encoding.ASCII.GetBytes(s);
674+
await _stream.WriteAsync(bytes);
675+
}
676+
676677
public async Task SendResponseAsync(string response)
677678
{
678-
await _writer.WriteAsync(response).ConfigureAwait(false);
679+
await WriteStringAsync(response);
680+
}
681+
682+
public async Task SendResponseAsync(byte[] response)
683+
{
684+
await _stream.WriteAsync(response);
679685
}
680686

681687
public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
@@ -686,7 +692,7 @@ public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.O
686692
public async Task<List<string>> ReadRequestHeaderAndSendCustomResponseAsync(string response)
687693
{
688694
List<string> lines = await ReadRequestHeaderAsync().ConfigureAwait(false);
689-
await _writer.WriteAsync(response).ConfigureAwait(false);
695+
await WriteStringAsync(response);
690696
return lines;
691697
}
692698

@@ -892,7 +898,7 @@ public override async Task SendResponseHeadersAsync(HttpStatusCode statusCode =
892898

893899
public override async Task SendResponseBodyAsync(byte[] body, bool isFinal = true, int requestId = 0)
894900
{
895-
await SendResponseAsync(Encoding.UTF8.GetString(body)).ConfigureAwait(false);
901+
await SendResponseAsync(body).ConfigureAwait(false);
896902
}
897903

898904
public override async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")

src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -321,32 +321,31 @@ public static Task StartTransferTypeAndErrorServer(
321321
}
322322

323323
// Write response header
324-
TextWriter writer = connection.Writer;
325-
await writer.WriteAsync("HTTP/1.1 200 OK\r\n").ConfigureAwait(false);
326-
await writer.WriteAsync($"Date: {DateTimeOffset.UtcNow:R}\r\n").ConfigureAwait(false);
327-
await writer.WriteAsync("Content-Type: text/plain\r\n").ConfigureAwait(false);
324+
await connection.WriteStringAsync("HTTP/1.1 200 OK\r\n").ConfigureAwait(false);
325+
await connection.WriteStringAsync($"Date: {DateTimeOffset.UtcNow:R}\r\n").ConfigureAwait(false);
326+
await connection.WriteStringAsync("Content-Type: text/plain\r\n").ConfigureAwait(false);
328327
if (!string.IsNullOrEmpty(transferHeader))
329328
{
330-
await writer.WriteAsync(transferHeader).ConfigureAwait(false);
329+
await connection.WriteStringAsync(transferHeader).ConfigureAwait(false);
331330
}
332-
await writer.WriteAsync("\r\n").ConfigureAwait(false);
331+
await connection.WriteStringAsync("\r\n").ConfigureAwait(false);
333332

334333
// Write response body
335334
if (transferType == TransferType.Chunked)
336335
{
337336
string chunkSizeInHex = string.Format(
338337
"{0:x}\r\n",
339338
content.Length + (transferError == TransferError.ChunkSizeTooLarge ? 42 : 0));
340-
await writer.WriteAsync(chunkSizeInHex).ConfigureAwait(false);
341-
await writer.WriteAsync($"{content}\r\n").ConfigureAwait(false);
339+
await connection.WriteStringAsync(chunkSizeInHex).ConfigureAwait(false);
340+
await connection.WriteStringAsync($"{content}\r\n").ConfigureAwait(false);
342341
if (transferError != TransferError.MissingChunkTerminator)
343342
{
344-
await writer.WriteAsync("0\r\n\r\n").ConfigureAwait(false);
343+
await connection.WriteStringAsync("0\r\n\r\n").ConfigureAwait(false);
345344
}
346345
}
347346
else
348347
{
349-
await writer.WriteAsync($"{content}").ConfigureAwait(false);
348+
await connection.WriteStringAsync($"{content}").ConfigureAwait(false);
350349
}
351350
}));
352351
}

src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Connect.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ await server.AcceptConnectionAsync(async connection =>
5252

5353
TextReader clientReader = new StreamReader(clientStream);
5454
TextWriter clientWriter = new StreamWriter(clientStream) { AutoFlush = true };
55-
TextWriter serverWriter = connection.Writer;
55+
TextWriter serverWriter = new StreamWriter(connection.Stream, leaveOpen: true) { AutoFlush = true };
5656

5757
const string helloServer = "hello server";
5858
const string helloClient = "hello client";

src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,16 @@ await LoopbackServerFactory.CreateClientAndServerAsync(
391391
},
392392
async server =>
393393
{
394-
await server.HandleRequestAsync(headers: new[]
394+
// The client may detect the bad header and close the connection before we are done sending the response.
395+
// So, eat any IOException that occurs here.
396+
try
395397
{
396-
new HttpHeaderData("", "foo")
397-
});
398+
await server.HandleRequestAsync(headers: new[]
399+
{
400+
new HttpHeaderData("", "foo")
401+
});
402+
}
403+
catch (IOException) { }
398404
});
399405
}
400406

0 commit comments

Comments
 (0)