OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
8 | 8 |
| 9 // Matches _WebSocketOpcode. |
9 class _WebSocketMessageType { | 10 class _WebSocketMessageType { |
10 static const int NONE = 0; | 11 static const int NONE = 0; |
11 static const int BINARY = 1; | 12 static const int TEXT = 1; |
12 static const int TEXT = 2; | 13 static const int BINARY = 2; |
13 } | 14 } |
14 | 15 |
15 | 16 |
16 class _WebSocketOpcode { | 17 class _WebSocketOpcode { |
17 static const int CONTINUATION = 0; | 18 static const int CONTINUATION = 0; |
18 static const int TEXT = 1; | 19 static const int TEXT = 1; |
19 static const int BINARY = 2; | 20 static const int BINARY = 2; |
20 static const int RESERVED_3 = 3; | 21 static const int RESERVED_3 = 3; |
21 static const int RESERVED_4 = 4; | 22 static const int RESERVED_4 = 4; |
22 static const int RESERVED_5 = 5; | 23 static const int RESERVED_5 = 5; |
(...skipping 21 matching lines...) Expand all Loading... |
44 // TODO(ajohnsen): make this transformer reusable? | 45 // TODO(ajohnsen): make this transformer reusable? |
45 class _WebSocketProtocolTransformer implements StreamTransformer, EventSink { | 46 class _WebSocketProtocolTransformer implements StreamTransformer, EventSink { |
46 static const int START = 0; | 47 static const int START = 0; |
47 static const int LEN_FIRST = 1; | 48 static const int LEN_FIRST = 1; |
48 static const int LEN_REST = 2; | 49 static const int LEN_REST = 2; |
49 static const int MASK = 3; | 50 static const int MASK = 3; |
50 static const int PAYLOAD = 4; | 51 static const int PAYLOAD = 4; |
51 static const int CLOSED = 5; | 52 static const int CLOSED = 5; |
52 static const int FAILURE = 6; | 53 static const int FAILURE = 6; |
53 | 54 |
54 int _state; | 55 int _state = START; |
55 bool _fin; | 56 bool _fin = false; |
56 int _opcode; | 57 int _opcode = -1; |
57 int _len; | 58 int _len = -1; |
58 bool _masked; | 59 bool _masked = false; |
59 int _maskingKey; | 60 int _remainingLenBytes = -1; |
60 int _remainingLenBytes; | 61 int _remainingMaskingKeyBytes = 4; |
61 int _remainingMaskingKeyBytes; | 62 int _remainingPayloadBytes = -1; |
62 int _remainingPayloadBytes; | 63 int _unmaskingIndex = 0; |
63 int _unmaskingIndex; | 64 int _currentMessageType = _WebSocketMessageType.NONE; |
64 | |
65 int _currentMessageType; | |
66 List<int> _controlPayload; | |
67 StreamController _controller; | |
68 | |
69 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED; | 65 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED; |
70 String closeReason = ""; | 66 String closeReason = ""; |
71 | 67 |
72 bool _serverSide; | |
73 EventSink _eventSink; | 68 EventSink _eventSink; |
74 | 69 |
75 _WebSocketProtocolTransformer([this._serverSide = false]) { | 70 final bool _serverSide; |
76 _prepareForNextFrame(); | 71 final List _maskingBytes = new List(4); |
77 _currentMessageType = _WebSocketMessageType.NONE; | 72 final BytesBuilder _payload = new BytesBuilder(); |
78 } | 73 |
| 74 _WebSocketProtocolTransformer([this._serverSide = false]); |
79 | 75 |
80 Stream bind(Stream stream) { | 76 Stream bind(Stream stream) { |
81 return new Stream.eventTransformed( | 77 return new Stream.eventTransformed( |
82 stream, | 78 stream, |
83 (EventSink eventSink) { | 79 (EventSink eventSink) { |
84 if (_eventSink != null) { | 80 if (_eventSink != null) { |
85 throw new StateError("WebSocket transformer already used."); | 81 throw new StateError("WebSocket transformer already used."); |
86 } | 82 } |
87 _eventSink = eventSink; | 83 _eventSink = eventSink; |
88 return this; | 84 return this; |
89 }); | 85 }); |
90 } | 86 } |
91 | 87 |
92 void addError(Object error, [StackTrace stackTrace]) => | 88 void addError(Object error, [StackTrace stackTrace]) => |
93 _eventSink.addError(error, stackTrace); | 89 _eventSink.addError(error, stackTrace); |
94 | 90 |
95 void close() => _eventSink.close(); | 91 void close() => _eventSink.close(); |
96 | 92 |
97 /** | 93 /** |
98 * Process data received from the underlying communication channel. | 94 * Process data received from the underlying communication channel. |
99 */ | 95 */ |
100 void add(Uint8List buffer) { | 96 void add(Uint8List buffer) { |
101 int count = buffer.length; | 97 int count = buffer.length; |
102 int index = 0; | 98 int index = 0; |
103 int lastIndex = count; | 99 int lastIndex = count; |
104 try { | 100 if (_state == CLOSED) { |
105 if (_state == CLOSED) { | 101 throw new WebSocketException("Data on closed connection"); |
106 throw new WebSocketException("Data on closed connection"); | 102 } |
107 } | 103 if (_state == FAILURE) { |
108 if (_state == FAILURE) { | 104 throw new WebSocketException("Data on failed connection"); |
109 throw new WebSocketException("Data on failed connection"); | 105 } |
110 } | 106 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { |
111 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { | 107 int byte = buffer[index]; |
112 int byte = buffer[index]; | 108 if (_state <= LEN_REST) { |
113 switch (_state) { | 109 if (_state == START) { |
114 case START: | 110 _fin = (byte & 0x80) != 0; |
115 _fin = (byte & 0x80) != 0; | 111 if ((byte & 0x70) != 0) { |
116 if ((byte & 0x70) != 0) { | 112 // The RSV1, RSV2 bits RSV3 must be all zero. |
117 // The RSV1, RSV2 bits RSV3 most be all zero. | 113 throw new WebSocketException("Protocol error"); |
118 throw new WebSocketException("Protocol error"); | 114 } |
119 } | 115 _opcode = (byte & 0xF); |
120 _opcode = (byte & 0xF); | 116 if (_opcode <= _WebSocketOpcode.BINARY) { |
121 switch (_opcode) { | 117 if (_opcode == _WebSocketOpcode.CONTINUATION) { |
122 case _WebSocketOpcode.CONTINUATION: | |
123 if (_currentMessageType == _WebSocketMessageType.NONE) { | 118 if (_currentMessageType == _WebSocketMessageType.NONE) { |
124 throw new WebSocketException("Protocol error"); | 119 throw new WebSocketException("Protocol error"); |
125 } | 120 } |
126 break; | 121 } else { |
127 | 122 assert(_opcode == _WebSocketOpcode.TEXT || |
128 case _WebSocketOpcode.TEXT: | 123 _opcode == _WebSocketOpcode.BINARY); |
129 if (_currentMessageType != _WebSocketMessageType.NONE) { | 124 if (_currentMessageType != _WebSocketMessageType.NONE) { |
130 throw new WebSocketException("Protocol error"); | 125 throw new WebSocketException("Protocol error"); |
131 } | 126 } |
132 _currentMessageType = _WebSocketMessageType.TEXT; | 127 _currentMessageType = _opcode; |
133 _controller = new StreamController(sync: true); | 128 } |
134 _controller.stream | 129 } else if (_opcode >= _WebSocketOpcode.CLOSE && |
135 .transform(UTF8.decoder) | 130 _opcode <= _WebSocketOpcode.PONG) { |
136 .fold(new StringBuffer(), (buffer, str) => buffer..write(str)) | 131 // Control frames cannot be fragmented. |
137 .then((buffer) { | 132 if (!_fin) throw new WebSocketException("Protocol error"); |
138 _eventSink.add(buffer.toString()); | 133 } else { |
139 }, onError: _eventSink.addError); | 134 throw new WebSocketException("Protocol error"); |
140 break; | 135 } |
| 136 _state = LEN_FIRST; |
| 137 } else if (_state == LEN_FIRST) { |
| 138 _masked = (byte & 0x80) != 0; |
| 139 _len = byte & 0x7F; |
| 140 if (_isControlFrame() && _len > 125) { |
| 141 throw new WebSocketException("Protocol error"); |
| 142 } |
| 143 if (_len == 126) { |
| 144 _len = 0; |
| 145 _remainingLenBytes = 2; |
| 146 _state = LEN_REST; |
| 147 } else if (_len == 127) { |
| 148 _len = 0; |
| 149 _remainingLenBytes = 8; |
| 150 _state = LEN_REST; |
| 151 } else { |
| 152 assert(_len < 126); |
| 153 _lengthDone(); |
| 154 } |
| 155 } else { |
| 156 assert(_state == LEN_REST); |
| 157 _len = _len << 8 | byte; |
| 158 _remainingLenBytes--; |
| 159 if (_remainingLenBytes == 0) { |
| 160 _lengthDone(); |
| 161 } |
| 162 } |
| 163 } else { |
| 164 if (_state == MASK) { |
| 165 _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte; |
| 166 if (_remainingMaskingKeyBytes == 0) { |
| 167 _maskDone(); |
| 168 } |
| 169 } else { |
| 170 assert(_state == PAYLOAD); |
| 171 // The payload is not handled one byte at a time but in blocks. |
| 172 int payload = min(lastIndex - index, _remainingPayloadBytes); |
| 173 _remainingPayloadBytes -= payload; |
| 174 // Unmask payload if masked. |
| 175 if (_masked) { |
| 176 for (int i = index; i < index + payload; i++) { |
| 177 buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3]; |
| 178 } |
| 179 } |
| 180 // Control frame and data frame share _payload builder. |
| 181 _payload.add(new Uint8List.view(buffer.buffer, index, payload)); |
| 182 index += payload; |
| 183 if (_isControlFrame()) { |
| 184 if (_remainingPayloadBytes == 0) _controlFrameEnd(); |
| 185 } else { |
| 186 if (_currentMessageType != _WebSocketMessageType.TEXT && |
| 187 _currentMessageType != _WebSocketMessageType.BINARY) { |
| 188 throw new WebSocketException("Protocol error"); |
| 189 } |
| 190 if (_remainingPayloadBytes == 0) _messageFrameEnd(); |
| 191 } |
141 | 192 |
142 case _WebSocketOpcode.BINARY: | 193 // Hack - as we always do index++ below. |
143 if (_currentMessageType != _WebSocketMessageType.NONE) { | 194 index--; |
144 throw new WebSocketException("Protocol error"); | 195 } |
145 } | 196 } |
146 _currentMessageType = _WebSocketMessageType.BINARY; | |
147 _controller = new StreamController(sync: true); | |
148 _controller.stream | |
149 .fold(new BytesBuilder(), (buffer, data) => buffer..add(data)) | |
150 .then((buffer) { | |
151 _eventSink.add(buffer.takeBytes()); | |
152 }, onError: _eventSink.addError); | |
153 break; | |
154 | 197 |
155 case _WebSocketOpcode.CLOSE: | 198 // Move to the next byte. |
156 case _WebSocketOpcode.PING: | 199 index++; |
157 case _WebSocketOpcode.PONG: | |
158 // Control frames cannot be fragmented. | |
159 if (!_fin) throw new WebSocketException("Protocol error"); | |
160 break; | |
161 | |
162 default: | |
163 throw new WebSocketException("Protocol error"); | |
164 } | |
165 _state = LEN_FIRST; | |
166 break; | |
167 | |
168 case LEN_FIRST: | |
169 _masked = (byte & 0x80) != 0; | |
170 _len = byte & 0x7F; | |
171 if (_isControlFrame() && _len > 125) { | |
172 throw new WebSocketException("Protocol error"); | |
173 } | |
174 if (_len < 126) { | |
175 _lengthDone(); | |
176 } else if (_len == 126) { | |
177 _len = 0; | |
178 _remainingLenBytes = 2; | |
179 _state = LEN_REST; | |
180 } else if (_len == 127) { | |
181 _len = 0; | |
182 _remainingLenBytes = 8; | |
183 _state = LEN_REST; | |
184 } | |
185 break; | |
186 | |
187 case LEN_REST: | |
188 _len = _len << 8 | byte; | |
189 _remainingLenBytes--; | |
190 if (_remainingLenBytes == 0) { | |
191 _lengthDone(); | |
192 } | |
193 break; | |
194 | |
195 case MASK: | |
196 _maskingKey = _maskingKey << 8 | byte; | |
197 _remainingMaskingKeyBytes--; | |
198 if (_remainingMaskingKeyBytes == 0) { | |
199 _maskDone(); | |
200 } | |
201 break; | |
202 | |
203 case PAYLOAD: | |
204 // The payload is not handled one byte at a time but in blocks. | |
205 int payload; | |
206 if (lastIndex - index <= _remainingPayloadBytes) { | |
207 payload = lastIndex - index; | |
208 } else { | |
209 payload = _remainingPayloadBytes; | |
210 } | |
211 _remainingPayloadBytes -= payload; | |
212 | |
213 // Unmask payload if masked. | |
214 if (_masked) { | |
215 for (int i = 0; i < payload; i++) { | |
216 int maskingByte = | |
217 ((_maskingKey >> ((3 - _unmaskingIndex) * 8)) & 0xFF); | |
218 buffer[index + i] = buffer[index + i] ^ maskingByte; | |
219 _unmaskingIndex = (_unmaskingIndex + 1) % 4; | |
220 } | |
221 } | |
222 | |
223 if (_isControlFrame()) { | |
224 if (payload > 0) { | |
225 // Allocate a buffer for collecting the control frame | |
226 // payload if any. | |
227 if (_controlPayload == null) { | |
228 _controlPayload = new List<int>(); | |
229 } | |
230 _controlPayload.addAll(buffer.sublist(index, index + payload)); | |
231 index += payload; | |
232 } | |
233 | |
234 if (_remainingPayloadBytes == 0) { | |
235 _controlFrameEnd(); | |
236 } | |
237 } else { | |
238 if (_currentMessageType != _WebSocketMessageType.TEXT && | |
239 _currentMessageType != _WebSocketMessageType.BINARY) { | |
240 throw new WebSocketException("Protocol error"); | |
241 } | |
242 _controller.add( | |
243 new Uint8List.view(buffer.buffer, index, payload)); | |
244 index += payload; | |
245 if (_remainingPayloadBytes == 0) { | |
246 _messageFrameEnd(); | |
247 } | |
248 } | |
249 | |
250 // Hack - as we always do index++ below. | |
251 index--; | |
252 break; | |
253 } | |
254 | |
255 // Move to the next byte. | |
256 index++; | |
257 } | |
258 } catch (e, stackTrace) { | |
259 _state = FAILURE; | |
260 _eventSink.addError(e, stackTrace); | |
261 } | 200 } |
262 } | 201 } |
263 | 202 |
264 void _lengthDone() { | 203 void _lengthDone() { |
265 if (_masked) { | 204 if (_masked) { |
266 if (!_serverSide) { | 205 if (!_serverSide) { |
267 throw new WebSocketException("Received masked frame from server"); | 206 throw new WebSocketException("Received masked frame from server"); |
268 } | 207 } |
269 _state = MASK; | 208 _state = MASK; |
270 _remainingMaskingKeyBytes = 4; | |
271 } else { | 209 } else { |
272 if (_serverSide) { | 210 if (_serverSide) { |
273 throw new WebSocketException("Received unmasked frame from client"); | 211 throw new WebSocketException("Received unmasked frame from client"); |
274 } | 212 } |
275 _remainingPayloadBytes = _len; | 213 _remainingPayloadBytes = _len; |
276 _startPayload(); | 214 _startPayload(); |
277 } | 215 } |
278 } | 216 } |
279 | 217 |
280 void _maskDone() { | 218 void _maskDone() { |
(...skipping 24 matching lines...) Expand all Loading... |
305 } | 243 } |
306 } else { | 244 } else { |
307 _state = PAYLOAD; | 245 _state = PAYLOAD; |
308 } | 246 } |
309 } | 247 } |
310 | 248 |
311 void _messageFrameEnd() { | 249 void _messageFrameEnd() { |
312 if (_fin) { | 250 if (_fin) { |
313 switch (_currentMessageType) { | 251 switch (_currentMessageType) { |
314 case _WebSocketMessageType.TEXT: | 252 case _WebSocketMessageType.TEXT: |
315 _controller.close(); | 253 _eventSink.add(UTF8.decode(_payload.takeBytes())); |
316 break; | 254 break; |
317 case _WebSocketMessageType.BINARY: | 255 case _WebSocketMessageType.BINARY: |
318 _controller.close(); | 256 _eventSink.add(_payload.takeBytes()); |
319 break; | 257 break; |
320 } | 258 } |
321 _controller = null; | |
322 _currentMessageType = _WebSocketMessageType.NONE; | 259 _currentMessageType = _WebSocketMessageType.NONE; |
323 } | 260 } |
324 _prepareForNextFrame(); | 261 _prepareForNextFrame(); |
325 } | 262 } |
326 | 263 |
327 void _controlFrameEnd() { | 264 void _controlFrameEnd() { |
328 switch (_opcode) { | 265 switch (_opcode) { |
329 case _WebSocketOpcode.CLOSE: | 266 case _WebSocketOpcode.CLOSE: |
330 closeCode = WebSocketStatus.NO_STATUS_RECEIVED; | 267 closeCode = WebSocketStatus.NO_STATUS_RECEIVED; |
331 if (_controlPayload.length > 0) { | 268 if (_payload.length > 0) { |
332 if (_controlPayload.length == 1) { | 269 var bytes = _payload.takeBytes(); |
| 270 if (bytes.length == 1) { |
333 throw new WebSocketException("Protocol error"); | 271 throw new WebSocketException("Protocol error"); |
334 } | 272 } |
335 closeCode = _controlPayload[0] << 8 | _controlPayload[1]; | 273 closeCode = bytes[0] << 8 | bytes[1]; |
336 if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) { | 274 if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) { |
337 throw new WebSocketException("Protocol error"); | 275 throw new WebSocketException("Protocol error"); |
338 } | 276 } |
339 if (_controlPayload.length > 2) { | 277 if (bytes.length > 2) { |
340 closeReason = UTF8.decode(_controlPayload.sublist(2)); | 278 closeReason = UTF8.decode(bytes.sublist(2)); |
341 } | 279 } |
342 } | 280 } |
343 _state = CLOSED; | 281 _state = CLOSED; |
344 _eventSink.close(); | 282 _eventSink.close(); |
345 break; | 283 break; |
346 | 284 |
347 case _WebSocketOpcode.PING: | 285 case _WebSocketOpcode.PING: |
348 _eventSink.add(new _WebSocketPing(_controlPayload)); | 286 _eventSink.add(new _WebSocketPing(_payload.takeBytes())); |
349 break; | 287 break; |
350 | 288 |
351 case _WebSocketOpcode.PONG: | 289 case _WebSocketOpcode.PONG: |
352 _eventSink.add(new _WebSocketPong(_controlPayload)); | 290 _eventSink.add(new _WebSocketPong(_payload.takeBytes())); |
353 break; | 291 break; |
354 } | 292 } |
355 _prepareForNextFrame(); | 293 _prepareForNextFrame(); |
356 } | 294 } |
357 | 295 |
358 bool _isControlFrame() { | 296 bool _isControlFrame() { |
359 return _opcode == _WebSocketOpcode.CLOSE || | 297 return _opcode == _WebSocketOpcode.CLOSE || |
360 _opcode == _WebSocketOpcode.PING || | 298 _opcode == _WebSocketOpcode.PING || |
361 _opcode == _WebSocketOpcode.PONG; | 299 _opcode == _WebSocketOpcode.PONG; |
362 } | 300 } |
363 | 301 |
364 void _prepareForNextFrame() { | 302 void _prepareForNextFrame() { |
365 if (_state != CLOSED && _state != FAILURE) _state = START; | 303 if (_state != CLOSED && _state != FAILURE) _state = START; |
366 _fin = null; | 304 _fin = false; |
367 _opcode = null; | 305 _opcode = -1; |
368 _len = null; | 306 _len = -1; |
369 _masked = null; | 307 _remainingLenBytes = -1; |
370 _maskingKey = 0; | 308 _remainingMaskingKeyBytes = 4; |
371 _remainingLenBytes = null; | 309 _remainingPayloadBytes = -1; |
372 _remainingMaskingKeyBytes = null; | |
373 _remainingPayloadBytes = null; | |
374 _unmaskingIndex = 0; | 310 _unmaskingIndex = 0; |
375 _controlPayload = null; | |
376 } | 311 } |
377 } | 312 } |
378 | 313 |
379 | 314 |
380 class _WebSocketPing { | 315 class _WebSocketPing { |
381 final List<int> payload; | 316 final List<int> payload; |
382 _WebSocketPing([this.payload = null]); | 317 _WebSocketPing([this.payload = null]); |
383 } | 318 } |
384 | 319 |
385 | 320 |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 static Iterable createFrame(int opcode, List<int> data, bool serverSide) { | 499 static Iterable createFrame(int opcode, List<int> data, bool serverSide) { |
565 bool mask = !serverSide; // Masking not implemented for server. | 500 bool mask = !serverSide; // Masking not implemented for server. |
566 int dataLength = data == null ? 0 : data.length; | 501 int dataLength = data == null ? 0 : data.length; |
567 // Determine the header size. | 502 // Determine the header size. |
568 int headerSize = (mask) ? 6 : 2; | 503 int headerSize = (mask) ? 6 : 2; |
569 if (dataLength > 65535) { | 504 if (dataLength > 65535) { |
570 headerSize += 8; | 505 headerSize += 8; |
571 } else if (dataLength > 125) { | 506 } else if (dataLength > 125) { |
572 headerSize += 2; | 507 headerSize += 2; |
573 } | 508 } |
574 List<int> header = new List<int>(headerSize); | 509 Uint8List header = new Uint8List(headerSize); |
575 int index = 0; | 510 int index = 0; |
576 // Set FIN and opcode. | 511 // Set FIN and opcode. |
577 header[index++] = 0x80 | opcode; | 512 header[index++] = 0x80 | opcode; |
578 // Determine size and position of length field. | 513 // Determine size and position of length field. |
579 int lengthBytes = 1; | 514 int lengthBytes = 1; |
580 int firstLengthByte = 1; | 515 int firstLengthByte = 1; |
581 if (dataLength > 65535) { | 516 if (dataLength > 65535) { |
582 header[index++] = 127; | 517 header[index++] = 127; |
583 lengthBytes = 8; | 518 lengthBytes = 8; |
584 } else if (dataLength > 125) { | 519 } else if (dataLength > 125) { |
(...skipping 13 matching lines...) Expand all Loading... |
598 var list; | 533 var list; |
599 // If this is a text message just do the masking inside the | 534 // If this is a text message just do the masking inside the |
600 // encoded data. | 535 // encoded data. |
601 if (opcode == _WebSocketOpcode.TEXT) { | 536 if (opcode == _WebSocketOpcode.TEXT) { |
602 list = data; | 537 list = data; |
603 } else { | 538 } else { |
604 list = new Uint8List(data.length); | 539 list = new Uint8List(data.length); |
605 } | 540 } |
606 if (data is Uint8List) { | 541 if (data is Uint8List) { |
607 for (int i = 0; i < data.length; i++) { | 542 for (int i = 0; i < data.length; i++) { |
608 list[i] = data[i] ^ maskBytes[i % 4]; | 543 list[i] = data[i] ^ maskBytes[i & 3]; |
609 } | 544 } |
610 } else { | 545 } else { |
611 for (int i = 0; i < data.length; i++) { | 546 for (int i = 0; i < data.length; i++) { |
612 if (data[i] < 0 || 255 < data[i]) { | 547 if (data[i] < 0 || 255 < data[i]) { |
613 throw new ArgumentError( | 548 throw new ArgumentError( |
614 "List element is not a byte value " | 549 "List element is not a byte value " |
615 "(value ${data[i]} at index $i)"); | 550 "(value ${data[i]} at index $i)"); |
616 } | 551 } |
617 list[i] = data[i] ^ maskBytes[i % 4]; | 552 list[i] = data[i] ^ maskBytes[i & 3]; |
618 } | 553 } |
619 } | 554 } |
620 data = list; | 555 data = list; |
621 } | 556 } |
622 } | 557 } |
623 assert(index == headerSize); | 558 assert(index == headerSize); |
624 if (data == null) { | 559 if (data == null) { |
625 return [header]; | 560 return [header]; |
626 } else { | 561 } else { |
627 return [header, data]; | 562 return [header, data]; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 Uri uri = Uri.parse(url); | 714 Uri uri = Uri.parse(url); |
780 if (uri.scheme != "ws" && uri.scheme != "wss") { | 715 if (uri.scheme != "ws" && uri.scheme != "wss") { |
781 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); | 716 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); |
782 } | 717 } |
783 if (uri.userInfo != "") { | 718 if (uri.userInfo != "") { |
784 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); | 719 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); |
785 } | 720 } |
786 | 721 |
787 Random random = new Random(); | 722 Random random = new Random(); |
788 // Generate 16 random bytes. | 723 // Generate 16 random bytes. |
789 List<int> nonceData = new List<int>(16); | 724 Uint8List nonceData = new Uint8List(16); |
790 for (int i = 0; i < 16; i++) { | 725 for (int i = 0; i < 16; i++) { |
791 nonceData[i] = random.nextInt(256); | 726 nonceData[i] = random.nextInt(256); |
792 } | 727 } |
793 String nonce = _CryptoUtils.bytesToBase64(nonceData); | 728 String nonce = _CryptoUtils.bytesToBase64(nonceData); |
794 | 729 |
795 uri = new Uri(scheme: uri.scheme == "wss" ? "https" : "http", | 730 uri = new Uri(scheme: uri.scheme == "wss" ? "https" : "http", |
796 userInfo: uri.userInfo, | 731 userInfo: uri.userInfo, |
797 host: uri.host, | 732 host: uri.host, |
798 port: uri.port, | 733 port: uri.port, |
799 path: uri.path, | 734 path: uri.path, |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 (code < WebSocketStatus.NORMAL_CLOSURE || | 900 (code < WebSocketStatus.NORMAL_CLOSURE || |
966 code == WebSocketStatus.RESERVED_1004 || | 901 code == WebSocketStatus.RESERVED_1004 || |
967 code == WebSocketStatus.NO_STATUS_RECEIVED || | 902 code == WebSocketStatus.NO_STATUS_RECEIVED || |
968 code == WebSocketStatus.ABNORMAL_CLOSURE || | 903 code == WebSocketStatus.ABNORMAL_CLOSURE || |
969 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && | 904 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && |
970 code < WebSocketStatus.RESERVED_1015) || | 905 code < WebSocketStatus.RESERVED_1015) || |
971 (code >= WebSocketStatus.RESERVED_1015 && | 906 (code >= WebSocketStatus.RESERVED_1015 && |
972 code < 3000)); | 907 code < 3000)); |
973 } | 908 } |
974 } | 909 } |
OLD | NEW |