Skip to content

Commit 27fac58

Browse files
Synchronously write HTTP responses (#713)
1 parent 4c795d1 commit 27fac58

File tree

9 files changed

+204
-216
lines changed

9 files changed

+204
-216
lines changed

Engine/Internal/Infrastructure/Endpoints/EndPoint.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using GenHTTP.Api.Infrastructure;
66

77
using GenHTTP.Engine.Internal.Protocol;
8+
using GenHTTP.Engine.Internal.Utilities;
89
using GenHTTP.Engine.Shared.Infrastructure;
910

1011
namespace GenHTTP.Engine.Internal.Infrastructure.Endpoints;
@@ -98,7 +99,7 @@ private void Handle(Socket client)
9899

99100
protected abstract ValueTask Accept(Socket client);
100101

101-
protected ValueTask Handle(Socket client, Stream inputStream, X509Certificate? clientCertificate = null)
102+
protected ValueTask Handle(Socket client, PoolBufferedStream inputStream, X509Certificate? clientCertificate = null)
102103
{
103104
client.NoDelay = true;
104105

Engine/Internal/Protocol/ChunkedStream.cs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using GenHTTP.Modules.IO.Streaming;
1+
using GenHTTP.Engine.Internal.Utilities;
22

33
namespace GenHTTP.Engine.Internal.Protocol;
44

@@ -11,18 +11,8 @@ namespace GenHTTP.Engine.Internal.Protocol;
1111
/// soon as there is no known content length. To avoid this overhead,
1212
/// specify the length of your content whenever possible.
1313
/// </remarks>
14-
public sealed class ChunkedStream : Stream
14+
public sealed class ChunkedStream(PoolBufferedStream target) : Stream
1515
{
16-
private static readonly string NL = "\r\n";
17-
18-
#region Initialization
19-
20-
public ChunkedStream(Stream target)
21-
{
22-
Target = target;
23-
}
24-
25-
#endregion
2616

2717
#region Get-/Setters
2818

@@ -36,7 +26,7 @@ public ChunkedStream(Stream target)
3626

3727
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
3828

39-
private Stream Target { get; }
29+
private Stream Target { get; } = target;
4030

4131
#endregion
4232

@@ -59,37 +49,37 @@ public override void Write(byte[] buffer, int offset, int count)
5949

6050
Target.Write(buffer, offset, count);
6151

62-
NL.Write(Target);
52+
Target.Write("\r\n"u8);
6353
}
6454
}
6555

6656
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
6757
{
6858
if (count > 0)
6959
{
70-
await WriteAsync(count);
60+
Write(count);
7161

7262
await Target.WriteAsync(buffer.AsMemory(offset, count), cancellationToken);
7363

74-
await WriteAsync(NL);
64+
Target.Write("\r\n"u8);
7565
}
7666
}
7767

7868
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
7969
{
8070
if (!buffer.IsEmpty)
8171
{
82-
await WriteAsync(buffer.Length);
72+
Write(buffer.Length);
8373

8474
await Target.WriteAsync(buffer, cancellationToken);
8575

86-
await WriteAsync(NL);
76+
Target.Write("\r\n"u8);
8777
}
8878
}
8979

90-
public async ValueTask FinishAsync()
80+
public void Finish()
9181
{
92-
await WriteAsync("0\r\n\r\n");
82+
Target.Write("0\r\n\r\n"u8);
9383
}
9484

9585
public override void Flush()
@@ -99,11 +89,22 @@ public override void Flush()
9989

10090
public override Task FlushAsync(CancellationToken cancellationToken) => Target.FlushAsync(cancellationToken);
10191

102-
private void Write(int value) => $"{value:X}\r\n".Write(Target);
92+
private void Write(int value)
93+
{
94+
Span<byte> buffer = stackalloc byte[8 + 2];
10395

104-
private ValueTask WriteAsync(string text) => text.WriteAsync(Target);
96+
if (value.TryFormat(buffer, out var written, "X"))
97+
{
98+
buffer[written++] = (byte)'\r';
99+
buffer[written++] = (byte)'\n';
105100

106-
private ValueTask WriteAsync(int value) => $"{value:X}\r\n".WriteAsync(Target);
101+
Target.Write(buffer[..written]);
102+
}
103+
else
104+
{
105+
throw new InvalidOperationException("Failed to format chunk size");
106+
}
107+
}
107108

108109
#endregion
109110

Engine/Internal/Protocol/ClientHandler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using GenHTTP.Api.Protocol;
88

99
using GenHTTP.Engine.Internal.Protocol.Parser;
10+
using GenHTTP.Engine.Internal.Utilities;
1011
using GenHTTP.Engine.Shared.Infrastructure;
1112
using GenHTTP.Engine.Shared.Types;
1213

@@ -38,7 +39,7 @@ internal sealed class ClientHandler
3839

3940
internal X509Certificate? ClientCertificate { get; set; }
4041

41-
internal Stream Stream { get; }
42+
internal PoolBufferedStream Stream { get; }
4243

4344
private bool? KeepAlive { get; set; }
4445

@@ -48,7 +49,7 @@ internal sealed class ClientHandler
4849

4950
#region Initialization
5051

51-
internal ClientHandler(Socket socket, Stream stream, X509Certificate? clientCertificate, IServer server, IEndPoint endPoint, NetworkConfiguration config)
52+
internal ClientHandler(Socket socket, PoolBufferedStream stream, X509Certificate? clientCertificate, IServer server, IEndPoint endPoint, NetworkConfiguration config)
5253
{
5354
Server = server;
5455
EndPoint = endPoint;

0 commit comments

Comments
 (0)