Skip to content

Commit 28110f4

Browse files
github-actions[bot]Katya SokolovaMihaZupanCarnaViire
authored
[release/6.0] Fix compression (#79549)
* Fix compression * Apply suggestions from code review Co-authored-by: Miha Zupan <[email protected]> * Adding SendAsync to ref * fix ws deflate tests * Check bytes on server side * Fix u8 Co-authored-by: Miha Zupan <[email protected]> * Fix build on net6.0 * Remove ref assembly change, pr feedback Co-authored-by: Katya Sokolova <[email protected]> Co-authored-by: Miha Zupan <[email protected]> Co-authored-by: Natalia Kondratyeva <[email protected]>
1 parent 8b70363 commit 28110f4

File tree

3 files changed

+99
-2
lines changed

3 files changed

+99
-2
lines changed

src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ public override Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType m
109109
public override ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
110110
ConnectedWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
111111

112+
public override ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, WebSocketMessageFlags messageFlags, CancellationToken cancellationToken) =>
113+
ConnectedWebSocket.SendAsync(buffer, messageType, messageFlags, cancellationToken);
114+
112115
public override Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken) =>
113116
ConnectedWebSocket.ReceiveAsync(buffer, cancellationToken);
114117

src/libraries/System.Net.WebSockets.Client/tests/DeflateTests.cs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,100 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
7272
}), new LoopbackServer.Options { WebSocketEndpoint = true });
7373
}
7474

75+
[ConditionalFact(nameof(WebSocketsSupported))]
76+
public async Task ThrowsWhenContinuationHasDifferentCompressionFlags()
77+
{
78+
var deflateOpt = new WebSocketDeflateOptions
79+
{
80+
ClientMaxWindowBits = 14,
81+
ClientContextTakeover = true,
82+
ServerMaxWindowBits = 14,
83+
ServerContextTakeover = true
84+
};
85+
await LoopbackServer.CreateClientAndServerAsync(async uri =>
86+
{
87+
using var cws = new ClientWebSocket();
88+
using var cts = new CancellationTokenSource(TimeOutMilliseconds);
89+
90+
cws.Options.DangerousDeflateOptions = deflateOpt;
91+
await cws.ConnectAsync(uri, cts.Token);
92+
93+
await cws.SendAsync(Memory<byte>.Empty, WebSocketMessageType.Text, WebSocketMessageFlags.DisableCompression, default);
94+
Assert.Throws<ArgumentException>("messageFlags", () =>
95+
cws.SendAsync(Memory<byte>.Empty, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, default));
96+
}, server => server.AcceptConnectionAsync(async connection =>
97+
{
98+
string extensionsReply = CreateDeflateOptionsHeader(deflateOpt);
99+
await LoopbackHelper.WebSocketHandshakeAsync(connection, extensionsReply);
100+
}), new LoopbackServer.Options { WebSocketEndpoint = true });
101+
}
102+
103+
[ConditionalFact(nameof(WebSocketsSupported))]
104+
public async Task SendHelloWithDisableCompression()
105+
{
106+
byte[] bytes = Encoding.ASCII.GetBytes("Hello");
107+
108+
int prefixLength = 2;
109+
byte[] rawPrefix = new byte[] { 0x81, 0x85 }; // fin=1, rsv=0, opcode=text; mask=1, len=5
110+
int rawRemainingBytes = 9; // mask bytes (4) + payload bytes (5)
111+
byte[] compressedPrefix = new byte[] { 0xc1, 0x87 }; // fin=1, rsv=compressed, opcode=text; mask=1, len=7
112+
int compressedRemainingBytes = 11; // mask bytes (4) + payload bytes (7)
113+
114+
var deflateOpt = new WebSocketDeflateOptions
115+
{
116+
ClientMaxWindowBits = 14,
117+
ClientContextTakeover = true,
118+
ServerMaxWindowBits = 14,
119+
ServerContextTakeover = true
120+
};
121+
122+
await LoopbackServer.CreateClientAndServerAsync(async uri =>
123+
{
124+
using var cws = new ClientWebSocket();
125+
using var cts = new CancellationTokenSource(TimeOutMilliseconds);
126+
127+
cws.Options.DangerousDeflateOptions = deflateOpt;
128+
await cws.ConnectAsync(uri, cts.Token);
129+
130+
await cws.SendAsync(bytes, WebSocketMessageType.Text, true, cts.Token);
131+
132+
WebSocketMessageFlags flags = WebSocketMessageFlags.DisableCompression | WebSocketMessageFlags.EndOfMessage;
133+
await cws.SendAsync(bytes, WebSocketMessageType.Text, flags, cts.Token);
134+
}, server => server.AcceptConnectionAsync(async connection =>
135+
{
136+
var buffer = new byte[compressedRemainingBytes];
137+
string extensionsReply = CreateDeflateOptionsHeader(deflateOpt);
138+
await LoopbackHelper.WebSocketHandshakeAsync(connection, extensionsReply);
139+
140+
// first message is compressed
141+
await ReadExactAsync(buffer, prefixLength);
142+
Assert.Equal(compressedPrefix, buffer[..prefixLength]);
143+
// read rest of the frame
144+
await ReadExactAsync(buffer, compressedRemainingBytes);
145+
146+
// second message is not compressed
147+
await ReadExactAsync(buffer, prefixLength);
148+
Assert.Equal(rawPrefix, buffer[..prefixLength]);
149+
// read rest of the frame
150+
await ReadExactAsync(buffer, rawRemainingBytes);
151+
152+
async Task ReadExactAsync(byte[] buf, int n)
153+
{
154+
var mem = buf.AsMemory(0, n);
155+
int totalRead = 0;
156+
while (totalRead < n)
157+
{
158+
int read = await connection.Stream.ReadAsync(mem.Slice(totalRead)).ConfigureAwait(false);
159+
if (read == 0)
160+
{
161+
throw new Exception("Unexpected end of stream");
162+
}
163+
totalRead += read;
164+
}
165+
}
166+
}), new LoopbackServer.Options { WebSocketEndpoint = true });
167+
}
168+
75169
private static string CreateDeflateOptionsHeader(WebSocketDeflateOptions options)
76170
{
77171
var builder = new StringBuilder();

src/libraries/System.Net.WebSockets.Client/tests/wasm/BrowserTimerThrottlingTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,12 @@ private async static Task SendAndReceive(ClientWebSocket cws, string message)
158158
catch (OperationCanceledException)
159159
{
160160
}
161+
#if DEBUG
161162
catch (Exception ex)
162163
{
163-
#if DEBUG
164164
Console.WriteLine("SendAndReceive fail:" + ex);
165-
#endif
166165
}
166+
#endif
167167
}
168168
}
169169

0 commit comments

Comments
 (0)