Skip to content

Commit

Permalink
Use ArrayBuffer for write buffer management in HttpConnection (#79525)
Browse files Browse the repository at this point in the history
  • Loading branch information
MihaZupan authored Jan 2, 2023
1 parent a08cfcb commit 88dd8c7
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 406 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal sealed partial class HttpConnection : IDisposable
{
private sealed class ChunkedEncodingWriteStream : HttpContentWriteStream
{
private static readonly byte[] s_crlfBytes = "\r\n"u8.ToArray();
private static readonly byte[] s_finalChunkBytes = "0\r\n\r\n"u8.ToArray();

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

// Write chunk length in hex followed by \r\n
connection.WriteHexInt32Async(buffer.Length, async: false).GetAwaiter().GetResult();
connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: false).GetAwaiter().GetResult();
ValueTask writeTask = connection.WriteHexInt32Async(buffer.Length, async: false);
Debug.Assert(writeTask.IsCompleted);
writeTask.GetAwaiter().GetResult();
connection.Write(s_crlfBytes);

// Write chunk contents followed by \r\n
connection.Write(buffer);
connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: false).GetAwaiter().GetResult();
connection.Write(s_crlfBytes);
}

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

// Write chunk contents followed by \r\n
await connection.WriteAsync(buffer, async: true).ConfigureAwait(false);
await connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', async: true).ConfigureAwait(false);
await connection.WriteAsync(buffer).ConfigureAwait(false);
await connection.WriteAsync(s_crlfBytes).ConfigureAwait(false);
}
}

Expand All @@ -75,7 +78,16 @@ public override Task FinishAsync(bool async)
// Send 0 byte chunk to indicate end, then final CrLf
HttpConnection connection = GetConnectionOrThrow();
_connection = null;
return connection.WriteBytesAsync(s_finalChunkBytes, async);

if (async)
{
return connection.WriteAsync(s_finalChunkBytes).AsTask();
}
else
{
connection.Write(s_finalChunkBytes);
return Task.CompletedTask;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ public override void Write(ReadOnlySpan<byte> buffer)
throw new HttpRequestException(SR.net_http_content_write_larger_than_content_length);
}

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

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

public override Task FinishAsync(bool async)
Expand Down
Loading

0 comments on commit 88dd8c7

Please sign in to comment.