@@ -72,6 +72,100 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
72
72
} ) , new LoopbackServer . Options { WebSocketEndpoint = true } ) ;
73
73
}
74
74
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
+
75
169
private static string CreateDeflateOptionsHeader ( WebSocketDeflateOptions options )
76
170
{
77
171
var builder = new StringBuilder ( ) ;
0 commit comments