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