Skip to content

Commit 88dd8c7

Browse files
authored
Use ArrayBuffer for write buffer management in HttpConnection (#79525)
1 parent a08cfcb commit 88dd8c7

File tree

4 files changed

+293
-406
lines changed

4 files changed

+293
-406
lines changed

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingWriteStream.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ internal sealed partial class HttpConnection : IDisposable
1111
{
1212
private sealed class ChunkedEncodingWriteStream : HttpContentWriteStream
1313
{
14+
private static readonly byte[] s_crlfBytes = "\r\n"u8.ToArray();
1415
private static readonly byte[] s_finalChunkBytes = "0\r\n\r\n"u8.ToArray();
1516

1617
public ChunkedEncodingWriteStream(HttpConnection connection) : base(connection)
@@ -31,12 +32,14 @@ public override void Write(ReadOnlySpan<byte> buffer)
3132
}
3233

3334
// Write chunk length in hex followed by \r\n
34-
connection.WriteHexInt32Async(buffer.Length, async: false).GetAwaiter().GetResult();
35-
connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: false).GetAwaiter().GetResult();
35+
ValueTask writeTask = connection.WriteHexInt32Async(buffer.Length, async: false);
36+
Debug.Assert(writeTask.IsCompleted);
37+
writeTask.GetAwaiter().GetResult();
38+
connection.Write(s_crlfBytes);
3639

3740
// Write chunk contents followed by \r\n
3841
connection.Write(buffer);
39-
connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: false).GetAwaiter().GetResult();
42+
connection.Write(s_crlfBytes);
4043
}
4144

4245
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken ignored)
@@ -62,11 +65,11 @@ static async ValueTask WriteChunkAsync(HttpConnection connection, ReadOnlyMemory
6265
{
6366
// Write chunk length in hex followed by \r\n
6467
await connection.WriteHexInt32Async(buffer.Length, async: true).ConfigureAwait(false);
65-
await connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: true).ConfigureAwait(false);
68+
await connection.WriteAsync(s_crlfBytes).ConfigureAwait(false);
6669

6770
// Write chunk contents followed by \r\n
68-
await connection.WriteAsync(buffer, async: true).ConfigureAwait(false);
69-
await connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: true).ConfigureAwait(false);
71+
await connection.WriteAsync(buffer).ConfigureAwait(false);
72+
await connection.WriteAsync(s_crlfBytes).ConfigureAwait(false);
7073
}
7174
}
7275

@@ -75,7 +78,16 @@ public override Task FinishAsync(bool async)
7578
// Send 0 byte chunk to indicate end, then final CrLf
7679
HttpConnection connection = GetConnectionOrThrow();
7780
_connection = null;
78-
return connection.WriteBytesAsync(s_finalChunkBytes, async);
81+
82+
if (async)
83+
{
84+
return connection.WriteAsync(s_finalChunkBytes).AsTask();
85+
}
86+
else
87+
{
88+
connection.Write(s_finalChunkBytes);
89+
return Task.CompletedTask;
90+
}
7991
}
8092
}
8193
}

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthWriteStream.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ public override void Write(ReadOnlySpan<byte> buffer)
2828
throw new HttpRequestException(SR.net_http_content_write_larger_than_content_length);
2929
}
3030

31-
// Have the connection write the data, skipping the buffer. Importantly, this will
32-
// force a flush of anything already in the buffer, i.e. any remaining request headers
33-
// that are still buffered.
3431
HttpConnection connection = GetConnectionOrThrow();
3532
Debug.Assert(connection._currentRequest != null);
3633
connection.Write(buffer);
@@ -45,12 +42,9 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
4542
return ValueTask.FromException(new HttpRequestException(SR.net_http_content_write_larger_than_content_length));
4643
}
4744

48-
// Have the connection write the data, skipping the buffer. Importantly, this will
49-
// force a flush of anything already in the buffer, i.e. any remaining request headers
50-
// that are still buffered.
5145
HttpConnection connection = GetConnectionOrThrow();
5246
Debug.Assert(connection._currentRequest != null);
53-
return connection.WriteAsync(buffer, async: true);
47+
return connection.WriteAsync(buffer);
5448
}
5549

5650
public override Task FinishAsync(bool async)

0 commit comments

Comments
 (0)