Skip to content

Commit 9fd32e9

Browse files
optimizations
1 parent 1b843c6 commit 9fd32e9

File tree

2 files changed

+66
-45
lines changed

2 files changed

+66
-45
lines changed

Infinity.WebSockets/WebSocketClientConnection.cs

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -107,29 +107,39 @@ public override async Task Connect(MessageWriter _writer, int _timeout = 5000)
107107
_ = Task.Run(ReceiveLoop);
108108
}
109109

110-
public override async Task<SendErrors> Send(MessageWriter _writer)
110+
public override async Task<SendErrors> Send(MessageWriter message)
111111
{
112+
// Check if the connection is ready
112113
if (state != ConnectionState.Connected || stream == null || closeSent)
113-
{
114114
return SendErrors.Disconnected;
115-
}
116115

117-
InvokeBeforeSend(_writer);
118-
MessageWriter frame = WebSocketFrame.CreateFrame(_writer.Buffer.AsSpan(0, _writer.Length), _writer.Length, WebSocketOpcode.Binary, true, _mask: true);
116+
// Allow any pre-send processing
117+
InvokeBeforeSend(message);
118+
119+
// Create a WebSocket frame from the message
120+
var frame = WebSocketFrame.CreateFrame(
121+
message.Buffer.AsSpan(0, message.Length),
122+
message.Length,
123+
WebSocketOpcode.Binary,
124+
true, // fin
125+
true // mask
126+
);
127+
119128
try
120129
{
130+
// Write the frame to the network stream
121131
await stream.WriteAsync(frame.Buffer, 0, frame.Length);
122132
await stream.FlushAsync();
123133
}
124134
catch (Exception ex)
125135
{
126136
logger?.WriteError("WebSocket send failed: " + ex.Message);
127-
frame.Recycle();
128137
DisconnectInternal(InfinityInternalErrors.ConnectionDisconnected, "Send failed");
129138
return SendErrors.Disconnected;
130139
}
131140
finally
132141
{
142+
// Always recycle the frame to avoid memory leaks
133143
frame.Recycle();
134144
}
135145

@@ -422,49 +432,74 @@ protected override void Dispose(bool _disposing)
422432
base.Dispose(_disposing);
423433
}
424434

425-
private static async Task<string> ReadHeaders(NetworkStream _stream)
435+
private static async Task<string> ReadHeaders(NetworkStream stream)
426436
{
427-
var sb = new StringBuilder();
437+
var builder = new StringBuilder();
428438
byte[] buffer = new byte[1024];
429-
int matched = 0;
439+
int consecutiveMatch = 0; // Tracks \r\n\r\n sequence
440+
430441
while (true)
431442
{
432-
int read = await _stream.ReadAsync(buffer, 0, buffer.Length);
433-
if (read <= 0) break;
434-
sb.Append(Encoding.ASCII.GetString(buffer, 0, read));
435-
for (int i = 0; i < read; i++)
443+
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
444+
if (bytesRead <= 0) break; // End of stream
445+
446+
// Append the chunk to the string builder
447+
builder.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead));
448+
449+
// Check for end-of-headers sequence (\r\n\r\n)
450+
for (int i = 0; i < bytesRead; i++)
436451
{
437452
char c = (char)buffer[i];
438-
if ((matched == 0 || matched == 2) && c == '\r') matched++;
439-
else if ((matched == 1 || matched == 3) && c == '\n') matched++;
440-
else matched = 0;
441-
if (matched == 4) return sb.ToString();
453+
454+
if ((consecutiveMatch == 0 || consecutiveMatch == 2) && c == '\r')
455+
consecutiveMatch++;
456+
else if ((consecutiveMatch == 1 || consecutiveMatch == 3) && c == '\n')
457+
consecutiveMatch++;
458+
else
459+
consecutiveMatch = 0;
460+
461+
// End of headers found
462+
if (consecutiveMatch == 4)
463+
return builder.ToString();
442464
}
443465
}
444-
return sb.ToString();
466+
467+
return builder.ToString();
445468
}
446469

447-
private static Dictionary<string, string> ParseHeaders(string raw)
470+
private static Dictionary<string, string> ParseHeaders(string rawHeaders)
448471
{
449-
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
450-
var lines = raw.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
472+
// Use case-insensitive dictionary for HTTP headers
473+
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
474+
475+
// Split the raw header string into lines, ignoring empty lines
476+
var lines = rawHeaders.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
477+
478+
// Start from index 1 assuming the first line is the request/status line
451479
for (int i = 1; i < lines.Length; i++)
452480
{
453481
var line = lines[i];
454-
int idx = line.IndexOf(':');
455-
if (idx <= 0) continue;
456-
var k = line[..idx].Trim();
457-
var v = line[(idx + 1)..].Trim();
458-
dict[k] = v;
482+
483+
// Find the first colon, which separates key and value
484+
int colonIndex = line.IndexOf(':');
485+
if (colonIndex <= 0) continue; // Skip malformed lines
486+
487+
// Extract key and value, trimming whitespace
488+
var key = line[..colonIndex].Trim();
489+
var value = line[(colonIndex + 1)..].Trim();
490+
491+
headers[key] = value;
459492
}
460-
return dict;
493+
494+
return headers;
461495
}
462496

463-
private static string ComputeWebSocketAccept(string _clientKey)
497+
private static string ComputeWebSocketAccept(string clientKey)
464498
{
465-
string concat = _clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
466-
byte[] sha1 = System.Security.Cryptography.SHA1.HashData(Encoding.ASCII.GetBytes(concat));
467-
return Convert.ToBase64String(sha1);
499+
const string WebSocketGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
500+
var concatenated = clientKey + WebSocketGuid;
501+
var hash = SHA1.HashData(Encoding.ASCII.GetBytes(concatenated));
502+
return Convert.ToBase64String(hash);
468503
}
469504
}
470505
}

Infinity.WebSockets/WebSocketFrame.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,6 @@ public static class WebSocketFrame
99
{
1010
public static MessageWriter CreateFrame(ReadOnlySpan<byte> _payload, int _length, WebSocketOpcode _opcode, bool _fin, bool _mask)
1111
{
12-
int headerLen = 2;
13-
int extendedLen = 0;
14-
if (_length >= 126 && _length <= ushort.MaxValue)
15-
{
16-
extendedLen = 2;
17-
}
18-
else if (_length > ushort.MaxValue)
19-
{
20-
extendedLen = 8;
21-
}
22-
23-
int maskLen = _mask ? 4 : 0;
24-
int totalLen = headerLen + extendedLen + maskLen + _length;
25-
2612
MessageWriter writer = MessageWriter.Get();
2713
writer.Position = 0; // Use from start
2814

0 commit comments

Comments
 (0)