Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: sdk/lib/io/websocket_impl.dart

Issue 12387085: Improve web-socket implementation by using making _WebSocketProtocolProcessor a StreamTransformer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/io/http_impl.dart ('k') | tests/standalone/io/web_socket_protocol_processor_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 class _WebSocketMessageType { 9 class _WebSocketMessageType {
10 static const int NONE = 0; 10 static const int NONE = 0;
(...skipping 15 matching lines...) Expand all
26 static const int PING = 9; 26 static const int PING = 9;
27 static const int PONG = 10; 27 static const int PONG = 10;
28 static const int RESERVED_B = 11; 28 static const int RESERVED_B = 11;
29 static const int RESERVED_C = 12; 29 static const int RESERVED_C = 12;
30 static const int RESERVED_D = 13; 30 static const int RESERVED_D = 13;
31 static const int RESERVED_E = 14; 31 static const int RESERVED_E = 14;
32 static const int RESERVED_F = 15; 32 static const int RESERVED_F = 15;
33 } 33 }
34 34
35 /** 35 /**
36 * The web socket protocol processor handles the protocol byte stream 36 * The web socket protocol transformer handles the protocol byte stream
37 * which is supplied through the [:update:] and [:closed:] 37 * which is supplied through the [:handleData:]. As the protocol is processed,
38 * methods. As the protocol is processed the following callbacks are 38 * it'll output frame data as either a List<int> or String.
39 * called:
40 * 39 *
41 * [:onMessageStart:] 40 * Important infomation about usage: Be sure you use unsubscribeOnError, so the
42 * [:onMessageData:] 41 * socket will be closed when the processer encounter an error. Not using it
43 * [:onMessageEnd:] 42 * will lead to undefined behaviour.
44 * [:onClosed:]
45 *
46 */ 43 */
47 class _WebSocketProtocolProcessor { 44 class _WebSocketProtocolTransformer extends StreamEventTransformer {
48 static const int START = 0; 45 static const int START = 0;
49 static const int LEN_FIRST = 1; 46 static const int LEN_FIRST = 1;
50 static const int LEN_REST = 2; 47 static const int LEN_REST = 2;
51 static const int MASK = 3; 48 static const int MASK = 3;
52 static const int PAYLOAD = 4; 49 static const int PAYLOAD = 4;
53 static const int CLOSED = 5; 50 static const int CLOSED = 5;
54 static const int FAILURE = 6; 51 static const int FAILURE = 6;
55 52
56 _WebSocketProtocolProcessor() { 53 _WebSocketProtocolTransformer() {
57 _prepareForNextFrame(); 54 _prepareForNextFrame();
58 _currentMessageType = _WebSocketMessageType.NONE; 55 _currentMessageType = _WebSocketMessageType.NONE;
59 } 56 }
60 57
61 /** 58 /**
62 * Process data received from the underlying communication channel. 59 * Process data received from the underlying communication channel.
63 */ 60 */
64 void update(List<int> buffer, int offset, int count) { 61 void handleData(List<int> buffer, StreamSink sink) {
65 int index = offset; 62 int count = buffer.length;
66 int lastIndex = offset + count; 63 int index = 0;
64 int lastIndex = count;
67 try { 65 try {
68 if (_state == CLOSED) { 66 if (_state == CLOSED) {
69 throw new WebSocketException("Data on closed connection"); 67 throw new WebSocketException("Data on closed connection");
70 } 68 }
71 if (_state == FAILURE) { 69 if (_state == FAILURE) {
72 throw new WebSocketException("Data on failed connection"); 70 throw new WebSocketException("Data on failed connection");
73 } 71 }
74 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { 72 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
75 int byte = buffer[index]; 73 int byte = buffer[index];
76 switch (_state) { 74 switch (_state) {
77 case START: 75 case START:
78 _fin = (byte & 0x80) != 0; 76 _fin = (byte & 0x80) != 0;
79 _opcode = (byte & 0xF); 77 _opcode = (byte & 0xF);
80 switch (_opcode) { 78 switch (_opcode) {
81 case _WebSocketOpcode.CONTINUATION: 79 case _WebSocketOpcode.CONTINUATION:
82 if (_currentMessageType == _WebSocketMessageType.NONE) { 80 if (_currentMessageType == _WebSocketMessageType.NONE) {
83 throw new WebSocketException("Protocol error"); 81 throw new WebSocketException("Protocol error");
84 } 82 }
85 break; 83 break;
86 84
87 case _WebSocketOpcode.TEXT: 85 case _WebSocketOpcode.TEXT:
88 if (_currentMessageType != _WebSocketMessageType.NONE) { 86 if (_currentMessageType != _WebSocketMessageType.NONE) {
89 throw new WebSocketException("Protocol error"); 87 throw new WebSocketException("Protocol error");
90 } 88 }
91 _currentMessageType = _WebSocketMessageType.TEXT; 89 _currentMessageType = _WebSocketMessageType.TEXT;
92 if (onMessageStart != null) { 90 _buffer = new StringBuffer();
93 onMessageStart(_WebSocketMessageType.TEXT);
94 }
95 break; 91 break;
96 92
97 case _WebSocketOpcode.BINARY: 93 case _WebSocketOpcode.BINARY:
98 if (_currentMessageType != _WebSocketMessageType.NONE) { 94 if (_currentMessageType != _WebSocketMessageType.NONE) {
99 throw new WebSocketException("Protocol error"); 95 throw new WebSocketException("Protocol error");
100 } 96 }
101 _currentMessageType = _WebSocketMessageType.BINARY; 97 _currentMessageType = _WebSocketMessageType.BINARY;
102 if (onMessageStart != null) { 98 _buffer = new _BufferList();
103 onMessageStart(_WebSocketMessageType.BINARY);
104 }
105 break; 99 break;
106 100
107 case _WebSocketOpcode.CLOSE: 101 case _WebSocketOpcode.CLOSE:
108 case _WebSocketOpcode.PING: 102 case _WebSocketOpcode.PING:
109 case _WebSocketOpcode.PONG: 103 case _WebSocketOpcode.PONG:
110 // Control frames cannot be fragmented. 104 // Control frames cannot be fragmented.
111 if (!_fin) throw new WebSocketException("Protocol error"); 105 if (!_fin) throw new WebSocketException("Protocol error");
112 break; 106 break;
113 107
114 default: 108 default:
115 throw new WebSocketException("Protocol error"); 109 throw new WebSocketException("Protocol error");
116 } 110 }
117 _state = LEN_FIRST; 111 _state = LEN_FIRST;
118 break; 112 break;
119 113
120 case LEN_FIRST: 114 case LEN_FIRST:
121 _masked = (byte & 0x80) != 0; 115 _masked = (byte & 0x80) != 0;
122 _len = byte & 0x7F; 116 _len = byte & 0x7F;
123 if (_isControlFrame() && _len > 126) { 117 if (_isControlFrame() && _len > 126) {
124 throw new WebSocketException("Protocol error"); 118 throw new WebSocketException("Protocol error");
125 } 119 }
126 if (_len < 126) { 120 if (_len < 126) {
127 _lengthDone(); 121 _lengthDone(sink);
128 } else if (_len == 126) { 122 } else if (_len == 126) {
129 _len = 0; 123 _len = 0;
130 _remainingLenBytes = 2; 124 _remainingLenBytes = 2;
131 _state = LEN_REST; 125 _state = LEN_REST;
132 } else if (_len == 127) { 126 } else if (_len == 127) {
133 _len = 0; 127 _len = 0;
134 _remainingLenBytes = 8; 128 _remainingLenBytes = 8;
135 _state = LEN_REST; 129 _state = LEN_REST;
136 } 130 }
137 break; 131 break;
138 132
139 case LEN_REST: 133 case LEN_REST:
140 _len = _len << 8 | byte; 134 _len = _len << 8 | byte;
141 _remainingLenBytes--; 135 _remainingLenBytes--;
142 if (_remainingLenBytes == 0) { 136 if (_remainingLenBytes == 0) {
143 _lengthDone(); 137 _lengthDone(sink);
144 } 138 }
145 break; 139 break;
146 140
147 case MASK: 141 case MASK:
148 _maskingKey = _maskingKey << 8 | byte; 142 _maskingKey = _maskingKey << 8 | byte;
149 _remainingMaskingKeyBytes--; 143 _remainingMaskingKeyBytes--;
150 if (_remainingMaskingKeyBytes == 0) { 144 if (_remainingMaskingKeyBytes == 0) {
151 _maskDone(); 145 _maskDone(sink);
152 } 146 }
153 break; 147 break;
154 148
155 case PAYLOAD: 149 case PAYLOAD:
156 // The payload is not handled one byte at a time but in blocks. 150 // The payload is not handled one byte at a time but in blocks.
157 int payload; 151 int payload;
158 if (lastIndex - index <= _remainingPayloadBytes) { 152 if (lastIndex - index <= _remainingPayloadBytes) {
159 payload = lastIndex - index; 153 payload = lastIndex - index;
160 } else { 154 } else {
161 payload = _remainingPayloadBytes; 155 payload = _remainingPayloadBytes;
(...skipping 15 matching lines...) Expand all
177 // Allocate a buffer for collecting the control frame 171 // Allocate a buffer for collecting the control frame
178 // payload if any. 172 // payload if any.
179 if (_controlPayload == null) { 173 if (_controlPayload == null) {
180 _controlPayload = new List<int>(); 174 _controlPayload = new List<int>();
181 } 175 }
182 _controlPayload.addAll(buffer.getRange(index, payload)); 176 _controlPayload.addAll(buffer.getRange(index, payload));
183 index += payload; 177 index += payload;
184 } 178 }
185 179
186 if (_remainingPayloadBytes == 0) { 180 if (_remainingPayloadBytes == 0) {
187 _controlFrameEnd(); 181 _controlFrameEnd(sink);
188 } 182 }
189 } else { 183 } else {
190 switch (_currentMessageType) { 184 switch (_currentMessageType) {
191 case _WebSocketMessageType.NONE: 185 case _WebSocketMessageType.NONE:
192 throw new WebSocketException("Protocol error"); 186 throw new WebSocketException("Protocol error");
193 187
194 case _WebSocketMessageType.TEXT: 188 case _WebSocketMessageType.TEXT:
195 case _WebSocketMessageType.BINARY: 189 _buffer.add(_decodeString(buffer.getRange(index, payload)));
196 if (onMessageData != null) {
197 onMessageData(buffer, index, payload);
198 }
199 index += payload; 190 index += payload;
200 if (_remainingPayloadBytes == 0) { 191 if (_remainingPayloadBytes == 0) {
201 _messageFrameEnd(); 192 _messageFrameEnd(sink);
202 } 193 }
203 break; 194 break;
204 195
196 case _WebSocketMessageType.BINARY:
197 _buffer.add(buffer.getRange(index, payload));
198 index += payload;
199 if (_remainingPayloadBytes == 0) {
200 _messageFrameEnd(sink);
201 }
202 break;
203
205 default: 204 default:
206 throw new WebSocketException("Protocol error"); 205 throw new WebSocketException("Protocol error");
207 } 206 }
208 } 207 }
209 208
210 // Hack - as we always do index++ below. 209 // Hack - as we always do index++ below.
211 index--; 210 index--;
212 break; 211 break;
213 } 212 }
214 213
215 // Move to the next byte. 214 // Move to the next byte.
216 index++; 215 index++;
217 } 216 }
218 } catch (e) { 217 } catch (e) {
219 if (onClosed != null) onClosed(WebSocketStatus.PROTOCOL_ERROR,
220 "Protocol error");
221 _state = FAILURE; 218 _state = FAILURE;
219 sink.signalError(e);
222 } 220 }
223 } 221 }
224 222
225 /** 223 void _lengthDone(StreamSink sink) {
226 * Indicate that the underlying communication channel has been closed.
227 */
228 void closed() {
229 if (_state == START || _state == CLOSED || _state == FAILURE) return;
230 if (onClosed != null) onClosed(WebSocketStatus.ABNORMAL_CLOSURE,
231 "Connection closed unexpectedly");
232 _state = CLOSED;
233 }
234
235 void _lengthDone() {
236 if (_masked) { 224 if (_masked) {
237 _state = MASK; 225 _state = MASK;
238 _remainingMaskingKeyBytes = 4; 226 _remainingMaskingKeyBytes = 4;
239 } else { 227 } else {
240 _remainingPayloadBytes = _len; 228 _remainingPayloadBytes = _len;
241 _startPayload(); 229 _startPayload(sink);
242 } 230 }
243 } 231 }
244 232
245 void _maskDone() { 233 void _maskDone(StreamSink sink) {
246 _remainingPayloadBytes = _len; 234 _remainingPayloadBytes = _len;
247 _startPayload(); 235 _startPayload(sink);
248 } 236 }
249 237
250 void _startPayload() { 238 void _startPayload(StreamSink sink) {
251 // If there is no actual payload perform perform callbacks without 239 // If there is no actual payload perform perform callbacks without
252 // going through the PAYLOAD state. 240 // going through the PAYLOAD state.
253 if (_remainingPayloadBytes == 0) { 241 if (_remainingPayloadBytes == 0) {
254 if (_isControlFrame()) { 242 if (_isControlFrame()) {
255 switch (_opcode) { 243 switch (_opcode) {
256 case _WebSocketOpcode.CLOSE: 244 case _WebSocketOpcode.CLOSE:
257 if (onClosed != null) onClosed(1005, "");
258 _state = CLOSED; 245 _state = CLOSED;
246 sink.close();
259 break; 247 break;
260 case _WebSocketOpcode.PING: 248 case _WebSocketOpcode.PING:
261 if (onPing != null) onPing(null); 249 // TODO(ajohnsen): Handle ping.
262 break; 250 break;
263 case _WebSocketOpcode.PONG: 251 case _WebSocketOpcode.PONG:
264 if (onPong != null) onPong(null); 252 // TODO(ajohnsen): Handle pong.
265 break; 253 break;
266 } 254 }
267 _prepareForNextFrame(); 255 _prepareForNextFrame();
268 } else { 256 } else {
269 _messageFrameEnd(); 257 _messageFrameEnd(sink);
270 } 258 }
271 } else { 259 } else {
272 _state = PAYLOAD; 260 _state = PAYLOAD;
273 } 261 }
274 } 262 }
275 263
276 void _messageFrameEnd() { 264 void _messageFrameEnd(StreamSink sink) {
277 if (_fin) { 265 if (_fin) {
278 if (onMessageEnd != null) onMessageEnd(); 266 switch (_currentMessageType) {
267 case _WebSocketMessageType.TEXT:
268 sink.add(_buffer.toString());
269 break;
270 case _WebSocketMessageType.BINARY:
271 if (_buffer.length == 0) {
272 sink.add(const []);
273 } else {
274 sink.add(_buffer.readBytes(_buffer.length));
275 }
276 break;
277 }
278 _buffer = null;
279 _currentMessageType = _WebSocketMessageType.NONE; 279 _currentMessageType = _WebSocketMessageType.NONE;
280 } 280 }
281 _prepareForNextFrame(); 281 _prepareForNextFrame();
282 } 282 }
283 283
284 void _controlFrameEnd() { 284 void _controlFrameEnd(StreamSink sink) {
285 switch (_opcode) { 285 switch (_opcode) {
286 case _WebSocketOpcode.CLOSE: 286 case _WebSocketOpcode.CLOSE:
287 int status = WebSocketStatus.NO_STATUS_RECEIVED; 287 closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
288 String reason = "";
289 if (_controlPayload.length > 0) { 288 if (_controlPayload.length > 0) {
290 if (_controlPayload.length == 1) { 289 if (_controlPayload.length == 1) {
291 throw new WebSocketException("Protocol error"); 290 throw new WebSocketException("Protocol error");
292 } 291 }
293 status = _controlPayload[0] << 8 | _controlPayload[1]; 292 closeCode = _controlPayload[0] << 8 | _controlPayload[1];
294 if (status == WebSocketStatus.NO_STATUS_RECEIVED) { 293 if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
295 throw new WebSocketException("Protocol error"); 294 throw new WebSocketException("Protocol error");
296 } 295 }
297 if (_controlPayload.length > 2) { 296 if (_controlPayload.length > 2) {
298 reason = _decodeString( 297 closeReason = _decodeString(
299 _controlPayload.getRange(2, _controlPayload.length - 2)); 298 _controlPayload.getRange(2, _controlPayload.length - 2));
300 } 299 }
301 } 300 }
302 if (onClosed != null) onClosed(status, reason);
303 _state = CLOSED; 301 _state = CLOSED;
302 sink.close();
304 break; 303 break;
305 304
306 case _WebSocketOpcode.PING: 305 case _WebSocketOpcode.PING:
307 if (onPing != null) onPing(_controlPayload); 306 // TODO(ajohnsen): Handle ping.
308 break; 307 break;
309 308
310 case _WebSocketOpcode.PONG: 309 case _WebSocketOpcode.PONG:
311 if (onPong != null) onPong(_controlPayload); 310 // TODO(ajohnsen): Handle pong.
312 break; 311 break;
313 } 312 }
314 _prepareForNextFrame(); 313 _prepareForNextFrame();
315 } 314 }
316 315
317 bool _isControlFrame() { 316 bool _isControlFrame() {
318 return _opcode == _WebSocketOpcode.CLOSE || 317 return _opcode == _WebSocketOpcode.CLOSE ||
319 _opcode == _WebSocketOpcode.PING || 318 _opcode == _WebSocketOpcode.PING ||
320 _opcode == _WebSocketOpcode.PONG; 319 _opcode == _WebSocketOpcode.PONG;
321 } 320 }
(...skipping 18 matching lines...) Expand all
340 int _len; 339 int _len;
341 bool _masked; 340 bool _masked;
342 int _maskingKey; 341 int _maskingKey;
343 int _remainingLenBytes; 342 int _remainingLenBytes;
344 int _remainingMaskingKeyBytes; 343 int _remainingMaskingKeyBytes;
345 int _remainingPayloadBytes; 344 int _remainingPayloadBytes;
346 int _unmaskingIndex; 345 int _unmaskingIndex;
347 346
348 int _currentMessageType; 347 int _currentMessageType;
349 List<int> _controlPayload; 348 List<int> _controlPayload;
349 var _buffer; // Either StringBuffer or _BufferList.
350 350
351 Function onMessageStart; 351 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
352 Function onMessageData; 352 String closeReason = "";
353 Function onMessageEnd;
354 Function onPing;
355 Function onPong;
356 Function onClosed;
357 } 353 }
358 354
359 355
360 class _WebSocketTransformerImpl implements WebSocketTransformer { 356 class _WebSocketTransformerImpl implements WebSocketTransformer {
361 final StreamController<WebSocket> _controller = 357 final StreamController<WebSocket> _controller =
362 new StreamController<WebSocket>(); 358 new StreamController<WebSocket>();
363 359
364 Stream<WebSocket> bind(Stream<HttpRequest> stream) { 360 Stream<WebSocket> bind(Stream<HttpRequest> stream) {
365 stream.listen((request) { 361 stream.listen((request) {
366 _upgrade(request) 362 _upgrade(request)
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 return false; 419 return false;
424 } 420 }
425 return true; 421 return true;
426 } 422 }
427 } 423 }
428 424
429 425
430 class _WebSocketImpl extends Stream implements WebSocket { 426 class _WebSocketImpl extends Stream implements WebSocket {
431 final StreamController _controller = new StreamController(); 427 final StreamController _controller = new StreamController();
432 428
433 final _WebSocketProtocolProcessor _processor =
434 new _WebSocketProtocolProcessor();
435
436 final Socket _socket; 429 final Socket _socket;
437 int _readyState = WebSocket.CONNECTING; 430 int _readyState = WebSocket.CONNECTING;
438 bool _writeClosed = false; 431 bool _writeClosed = false;
439 int _closeCode; 432 int _closeCode;
440 String _closeReason; 433 String _closeReason;
441 434
442 static final HttpClient _httpClient = new HttpClient(); 435 static final HttpClient _httpClient = new HttpClient();
443 436
444 static Future<WebSocket> connect(String url, [protocols]) { 437 static Future<WebSocket> connect(String url, [protocols]) {
445 Uri uri = Uri.parse(url); 438 Uri uri = Uri.parse(url);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 } 500 }
508 } 501 }
509 return response.detachSocket() 502 return response.detachSocket()
510 .then((socket) => new _WebSocketImpl._fromSocket(socket)); 503 .then((socket) => new _WebSocketImpl._fromSocket(socket));
511 }); 504 });
512 } 505 }
513 506
514 _WebSocketImpl._fromSocket(Socket this._socket) { 507 _WebSocketImpl._fromSocket(Socket this._socket) {
515 _readyState = WebSocket.OPEN; 508 _readyState = WebSocket.OPEN;
516 509
517 int type; 510 bool closed = false;
518 var data; 511 var transformer = new _WebSocketProtocolTransformer();
519 _processor.onMessageStart = (int t) { 512 _socket.transform(transformer).listen(
520 type = t; 513 (data) {
521 if (type == _WebSocketMessageType.TEXT) { 514 _controller.add(data);
522 data = new StringBuffer(); 515 },
523 } else { 516 onError: (error) {
524 data = []; 517 if (closed) return;
525 } 518 closed = true;
526 }; 519 _controller.signalError(error);
527 _processor.onMessageData = (buffer, offset, count) { 520 _controller.close();
528 if (type == _WebSocketMessageType.TEXT) { 521 },
529 data.add(_decodeString(buffer.getRange(offset, count))); 522 onDone: () {
530 } else { 523 if (closed) return;
531 data.addAll(buffer.getRange(offset, count)); 524 closed = true;
532 } 525 if (_readyState == WebSocket.OPEN) {
533 }; 526 _readyState = WebSocket.CLOSING;
534 _processor.onMessageEnd = () { 527 if (transformer.closeCode != WebSocketStatus.NO_STATUS_RECEIVED) {
535 if (type == _WebSocketMessageType.TEXT) { 528 _close(transformer.closeCode);
536 _controller.add(data.toString()); 529 } else {
537 } else { 530 _close();
538 _controller.add(data); 531 }
539 } 532 _readyState = WebSocket.CLOSED;
540 }; 533 }
541 _processor.onClosed = (code, reason) { 534 _closeCode = transformer.closeCode;
542 bool clean = true; 535 _closeReason = transformer.closeReason;
543 if (_readyState == WebSocket.OPEN) { 536 _controller.close();
544 _readyState = WebSocket.CLOSING; 537 if (_writeClosed) _socket.destroy();
545 if (code != WebSocketStatus.NO_STATUS_RECEIVED) { 538 },
546 _close(code); 539 unsubscribeOnError: true);
547 } else {
548 _close();
549 clean = false;
550 }
551 _readyState = WebSocket.CLOSED;
552 }
553 if (_readyState == WebSocket.CLOSED) return;
554 _closeCode = code;
555 _closeReason = reason;
556 _controller.close();
557 };
558
559 _socket.listen(
560 (data) => _processor.update(data, 0, data.length),
561 onDone: () => _processor.closed(),
562 onError: (error) => _controller.signalError(error));
563 540
564 _socket.done 541 _socket.done
565 .catchError((error) { 542 .catchError((error) {
566 if (_readyState == WebSocket.CLOSED) return; 543 if (closed) return;
544 closed = true;
567 _readyState = WebSocket.CLOSED; 545 _readyState = WebSocket.CLOSED;
568 _closeCode = ABNORMAL_CLOSURE; 546 _closeCode = WebSocketStatus.ABNORMAL_CLOSURE;
569 _controller.signalError(error); 547 _controller.signalError(error);
570 _controller.close(); 548 _controller.close();
571 _socket.destroy();
572 }) 549 })
573 .whenComplete(() { 550 .whenComplete(() {
574 _writeClosed = true; 551 _writeClosed = true;
575 }); 552 });
576 } 553 }
577 554
578 StreamSubscription listen(void onData(message), 555 StreamSubscription listen(void onData(message),
579 {void onError(AsyncError error), 556 {void onError(AsyncError error),
580 void onDone(), 557 void onDone(),
581 bool unsubscribeOnError}) { 558 bool unsubscribeOnError}) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 } else { 618 } else {
642 if (message is !List<int>) { 619 if (message is !List<int>) {
643 throw new ArgumentError(message); 620 throw new ArgumentError(message);
644 } 621 }
645 opcode = _WebSocketOpcode.BINARY; 622 opcode = _WebSocketOpcode.BINARY;
646 data = message; 623 data = message;
647 } 624 }
648 } else { 625 } else {
649 opcode = _WebSocketOpcode.TEXT; 626 opcode = _WebSocketOpcode.TEXT;
650 } 627 }
651 try { 628 _sendFrame(opcode, data);
652 _sendFrame(opcode, data);
653 } catch (_) {
654 // The socket can be closed before _socket.done have a chance
655 // to complete.
656 }
657 } 629 }
658 630
659 void _sendFrame(int opcode, [List<int> data]) { 631 void _sendFrame(int opcode, [List<int> data]) {
660 if (_writeClosed) return; 632 if (_writeClosed) return;
661 bool mask = false; // Masking not implemented for server. 633 bool mask = false; // Masking not implemented for server.
662 int dataLength = data == null ? 0 : data.length; 634 int dataLength = data == null ? 0 : data.length;
663 // Determine the header size. 635 // Determine the header size.
664 int headerSize = (mask) ? 6 : 2; 636 int headerSize = (mask) ? 6 : 2;
665 if (dataLength > 65535) { 637 if (dataLength > 65535) {
666 headerSize += 8; 638 headerSize += 8;
(...skipping 12 matching lines...) Expand all
679 lengthBytes = 8; 651 lengthBytes = 8;
680 } else if (dataLength > 125) { 652 } else if (dataLength > 125) {
681 header[index++] = 126; 653 header[index++] = 126;
682 lengthBytes = 2; 654 lengthBytes = 2;
683 } 655 }
684 // Write the length in network byte order into the header. 656 // Write the length in network byte order into the header.
685 for (int i = 0; i < lengthBytes; i++) { 657 for (int i = 0; i < lengthBytes; i++) {
686 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; 658 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
687 } 659 }
688 assert(index == headerSize); 660 assert(index == headerSize);
689 _socket.add(header); 661 try {
690 if (data != null) { 662 _socket.add(header);
691 _socket.add(data); 663 if (data != null) {
664 _socket.add(data);
665 }
666 } catch (_) {
667 // The socket can be closed before _socket.done have a chance
668 // to complete.
669 _writeClosed = true;
692 } 670 }
693 } 671 }
694 } 672 }
OLDNEW
« no previous file with comments | « sdk/lib/io/http_impl.dart ('k') | tests/standalone/io/web_socket_protocol_processor_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698