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

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

Issue 14696012: Make web-socket pass AutobanhTestSuite. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes Created 7 years, 7 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/websocket.dart ('k') | sdk/lib/utf/utf_stream.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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 throw new WebSocketException("Data on closed connection"); 69 throw new WebSocketException("Data on closed connection");
70 } 70 }
71 if (_state == FAILURE) { 71 if (_state == FAILURE) {
72 throw new WebSocketException("Data on failed connection"); 72 throw new WebSocketException("Data on failed connection");
73 } 73 }
74 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { 74 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
75 int byte = buffer[index]; 75 int byte = buffer[index];
76 switch (_state) { 76 switch (_state) {
77 case START: 77 case START:
78 _fin = (byte & 0x80) != 0; 78 _fin = (byte & 0x80) != 0;
79 if ((byte & 0x70) != 0) {
80 // The RSV1, RSV2 bits RSV3 most be all zero.
81 throw new WebSocketException("Protocol error");
82 }
79 _opcode = (byte & 0xF); 83 _opcode = (byte & 0xF);
80 switch (_opcode) { 84 switch (_opcode) {
81 case _WebSocketOpcode.CONTINUATION: 85 case _WebSocketOpcode.CONTINUATION:
82 if (_currentMessageType == _WebSocketMessageType.NONE) { 86 if (_currentMessageType == _WebSocketMessageType.NONE) {
83 throw new WebSocketException("Protocol error"); 87 throw new WebSocketException("Protocol error");
84 } 88 }
85 break; 89 break;
86 90
87 case _WebSocketOpcode.TEXT: 91 case _WebSocketOpcode.TEXT:
88 if (_currentMessageType != _WebSocketMessageType.NONE) { 92 if (_currentMessageType != _WebSocketMessageType.NONE) {
89 throw new WebSocketException("Protocol error"); 93 throw new WebSocketException("Protocol error");
90 } 94 }
91 _currentMessageType = _WebSocketMessageType.TEXT; 95 _currentMessageType = _WebSocketMessageType.TEXT;
92 _buffer = new StringBuffer(); 96 _controller = new StreamController();
97 _controller.stream
98 .transform(new Utf8DecoderTransformer(null))
99 .fold(new StringBuffer(), (buffer, str) => buffer..write(str))
100 .then((buffer) {
101 sink.add(buffer.toString());
102 }, onError: (error) {
103 sink.addError(error);
104 });
93 break; 105 break;
94 106
95 case _WebSocketOpcode.BINARY: 107 case _WebSocketOpcode.BINARY:
96 if (_currentMessageType != _WebSocketMessageType.NONE) { 108 if (_currentMessageType != _WebSocketMessageType.NONE) {
97 throw new WebSocketException("Protocol error"); 109 throw new WebSocketException("Protocol error");
98 } 110 }
99 _currentMessageType = _WebSocketMessageType.BINARY; 111 _currentMessageType = _WebSocketMessageType.BINARY;
100 _buffer = new _BufferList(); 112 _controller = new StreamController();
113 _controller.stream
114 .fold(new _BufferList(), (buffer, data) => buffer..add(data))
115 .then((buffer) {
116 sink.add(buffer.readBytes());
117 }, onError: (error) {
118 sink.addError(error);
119 });
101 break; 120 break;
102 121
103 case _WebSocketOpcode.CLOSE: 122 case _WebSocketOpcode.CLOSE:
104 case _WebSocketOpcode.PING: 123 case _WebSocketOpcode.PING:
105 case _WebSocketOpcode.PONG: 124 case _WebSocketOpcode.PONG:
106 // Control frames cannot be fragmented. 125 // Control frames cannot be fragmented.
107 if (!_fin) throw new WebSocketException("Protocol error"); 126 if (!_fin) throw new WebSocketException("Protocol error");
108 break; 127 break;
109 128
110 default: 129 default:
111 throw new WebSocketException("Protocol error"); 130 throw new WebSocketException("Protocol error");
112 } 131 }
113 _state = LEN_FIRST; 132 _state = LEN_FIRST;
114 break; 133 break;
115 134
116 case LEN_FIRST: 135 case LEN_FIRST:
117 _masked = (byte & 0x80) != 0; 136 _masked = (byte & 0x80) != 0;
118 _len = byte & 0x7F; 137 _len = byte & 0x7F;
119 if (_isControlFrame() && _len > 126) { 138 if (_isControlFrame() && _len > 125) {
120 throw new WebSocketException("Protocol error"); 139 throw new WebSocketException("Protocol error");
121 } 140 }
122 if (_len < 126) { 141 if (_len < 126) {
123 _lengthDone(sink); 142 _lengthDone(sink);
124 } else if (_len == 126) { 143 } else if (_len == 126) {
125 _len = 0; 144 _len = 0;
126 _remainingLenBytes = 2; 145 _remainingLenBytes = 2;
127 _state = LEN_REST; 146 _state = LEN_REST;
128 } else if (_len == 127) { 147 } else if (_len == 127) {
129 _len = 0; 148 _len = 0;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 _controlPayload = new List<int>(); 195 _controlPayload = new List<int>();
177 } 196 }
178 _controlPayload.addAll(buffer.sublist(index, index + payload)); 197 _controlPayload.addAll(buffer.sublist(index, index + payload));
179 index += payload; 198 index += payload;
180 } 199 }
181 200
182 if (_remainingPayloadBytes == 0) { 201 if (_remainingPayloadBytes == 0) {
183 _controlFrameEnd(sink); 202 _controlFrameEnd(sink);
184 } 203 }
185 } else { 204 } else {
186 switch (_currentMessageType) { 205 if (_currentMessageType != _WebSocketMessageType.TEXT &&
187 case _WebSocketMessageType.NONE: 206 _currentMessageType != _WebSocketMessageType.BINARY) {
188 throw new WebSocketException("Protocol error"); 207 throw new WebSocketException("Protocol error");
189 208 }
190 case _WebSocketMessageType.TEXT: 209 _controller.add(new Uint8List.view(buffer.buffer, index, payload)) ;
191 _buffer.write(_decodeString( 210 index += payload;
192 buffer.sublist(index, index + payload))); 211 if (_remainingPayloadBytes == 0) {
193 index += payload; 212 _messageFrameEnd(sink);
194 if (_remainingPayloadBytes == 0) {
195 _messageFrameEnd(sink);
196 }
197 break;
198
199 case _WebSocketMessageType.BINARY:
200 _buffer.write(buffer.sublist(index, index + payload));
201 index += payload;
202 if (_remainingPayloadBytes == 0) {
203 _messageFrameEnd(sink);
204 }
205 break;
206
207 default:
208 throw new WebSocketException("Protocol error");
209 } 213 }
210 } 214 }
211 215
212 // Hack - as we always do index++ below. 216 // Hack - as we always do index++ below.
213 index--; 217 index--;
214 break; 218 break;
215 } 219 }
216 220
217 // Move to the next byte. 221 // Move to the next byte.
218 index++; 222 index++;
(...skipping 29 matching lines...) Expand all
248 // If there is no actual payload perform perform callbacks without 252 // If there is no actual payload perform perform callbacks without
249 // going through the PAYLOAD state. 253 // going through the PAYLOAD state.
250 if (_remainingPayloadBytes == 0) { 254 if (_remainingPayloadBytes == 0) {
251 if (_isControlFrame()) { 255 if (_isControlFrame()) {
252 switch (_opcode) { 256 switch (_opcode) {
253 case _WebSocketOpcode.CLOSE: 257 case _WebSocketOpcode.CLOSE:
254 _state = CLOSED; 258 _state = CLOSED;
255 sink.close(); 259 sink.close();
256 break; 260 break;
257 case _WebSocketOpcode.PING: 261 case _WebSocketOpcode.PING:
258 // TODO(ajohnsen): Handle ping. 262 sink.add(new _WebSocketPing());
259 break; 263 break;
260 case _WebSocketOpcode.PONG: 264 case _WebSocketOpcode.PONG:
261 // TODO(ajohnsen): Handle pong. 265 sink.add(new _WebSocketPong());
262 break; 266 break;
263 } 267 }
264 _prepareForNextFrame(); 268 _prepareForNextFrame();
265 } else { 269 } else {
266 _messageFrameEnd(sink); 270 _messageFrameEnd(sink);
267 } 271 }
268 } else { 272 } else {
269 _state = PAYLOAD; 273 _state = PAYLOAD;
270 } 274 }
271 } 275 }
272 276
273 void _messageFrameEnd(EventSink sink) { 277 void _messageFrameEnd(EventSink sink) {
274 if (_fin) { 278 if (_fin) {
275 switch (_currentMessageType) { 279 switch (_currentMessageType) {
276 case _WebSocketMessageType.TEXT: 280 case _WebSocketMessageType.TEXT:
277 sink.add(_buffer.toString()); 281 _controller.close();
278 break; 282 break;
279 case _WebSocketMessageType.BINARY: 283 case _WebSocketMessageType.BINARY:
280 sink.add(_buffer.readBytes()); 284 _controller.close();
281 break; 285 break;
282 } 286 }
283 _buffer = null; 287 _controller = null;
284 _currentMessageType = _WebSocketMessageType.NONE; 288 _currentMessageType = _WebSocketMessageType.NONE;
285 } 289 }
286 _prepareForNextFrame(); 290 _prepareForNextFrame();
287 } 291 }
288 292
289 void _controlFrameEnd(EventSink sink) { 293 void _controlFrameEnd(EventSink sink) {
290 switch (_opcode) { 294 switch (_opcode) {
291 case _WebSocketOpcode.CLOSE: 295 case _WebSocketOpcode.CLOSE:
292 closeCode = WebSocketStatus.NO_STATUS_RECEIVED; 296 closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
293 if (_controlPayload.length > 0) { 297 if (_controlPayload.length > 0) {
294 if (_controlPayload.length == 1) { 298 if (_controlPayload.length == 1) {
295 throw new WebSocketException("Protocol error"); 299 throw new WebSocketException("Protocol error");
296 } 300 }
297 closeCode = _controlPayload[0] << 8 | _controlPayload[1]; 301 closeCode = _controlPayload[0] << 8 | _controlPayload[1];
298 if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) { 302 if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
299 throw new WebSocketException("Protocol error"); 303 throw new WebSocketException("Protocol error");
300 } 304 }
301 if (_controlPayload.length > 2) { 305 if (_controlPayload.length > 2) {
302 closeReason = _decodeString( 306 closeReason = _decodeUtf8Strict(_controlPayload.sublist(2));
303 _controlPayload.sublist(2));
304 } 307 }
305 } 308 }
306 _state = CLOSED; 309 _state = CLOSED;
307 sink.close(); 310 sink.close();
308 break; 311 break;
309 312
310 case _WebSocketOpcode.PING: 313 case _WebSocketOpcode.PING:
311 // TODO(ajohnsen): Handle ping. 314 sink.add(new _WebSocketPing(_controlPayload));
312 break; 315 break;
313 316
314 case _WebSocketOpcode.PONG: 317 case _WebSocketOpcode.PONG:
315 // TODO(ajohnsen): Handle pong. 318 sink.add(new _WebSocketPong(_controlPayload));
316 break; 319 break;
317 } 320 }
318 _prepareForNextFrame(); 321 _prepareForNextFrame();
319 } 322 }
320 323
321 bool _isControlFrame() { 324 bool _isControlFrame() {
322 return _opcode == _WebSocketOpcode.CLOSE || 325 return _opcode == _WebSocketOpcode.CLOSE ||
323 _opcode == _WebSocketOpcode.PING || 326 _opcode == _WebSocketOpcode.PING ||
324 _opcode == _WebSocketOpcode.PONG; 327 _opcode == _WebSocketOpcode.PONG;
325 } 328 }
(...skipping 18 matching lines...) Expand all
344 int _len; 347 int _len;
345 bool _masked; 348 bool _masked;
346 int _maskingKey; 349 int _maskingKey;
347 int _remainingLenBytes; 350 int _remainingLenBytes;
348 int _remainingMaskingKeyBytes; 351 int _remainingMaskingKeyBytes;
349 int _remainingPayloadBytes; 352 int _remainingPayloadBytes;
350 int _unmaskingIndex; 353 int _unmaskingIndex;
351 354
352 int _currentMessageType; 355 int _currentMessageType;
353 List<int> _controlPayload; 356 List<int> _controlPayload;
354 var _buffer; // Either StringBuffer or _BufferList. 357 StreamController _controller;
355 358
356 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED; 359 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
357 String closeReason = ""; 360 String closeReason = "";
358 } 361 }
359 362
360 363
364 class _WebSocketPing {
365 final List<int> payload;
366 _WebSocketPing([this.payload = null]);
367 }
368
369
370 class _WebSocketPong {
371 final List<int> payload;
372 _WebSocketPong([this.payload = null]);
373 }
374
375
361 class _WebSocketTransformerImpl implements WebSocketTransformer { 376 class _WebSocketTransformerImpl implements WebSocketTransformer {
362 final StreamController<WebSocket> _controller = 377 final StreamController<WebSocket> _controller =
363 new StreamController<WebSocket>(); 378 new StreamController<WebSocket>();
364 379
365 Stream<WebSocket> bind(Stream<HttpRequest> stream) { 380 Stream<WebSocket> bind(Stream<HttpRequest> stream) {
366 stream.listen((request) { 381 stream.listen((request) {
367 _upgrade(request) 382 _upgrade(request)
368 .then((WebSocket webSocket) => _controller.add(webSocket)) 383 .then((WebSocket webSocket) => _controller.add(webSocket))
369 .catchError((error) => _controller.addError(error)); 384 .catchError((error) => _controller.addError(error));
370 }); 385 });
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 442 }
428 } 443 }
429 444
430 445
431 class _WebSocketOutgoingTransformer extends StreamEventTransformer { 446 class _WebSocketOutgoingTransformer extends StreamEventTransformer {
432 final _WebSocketImpl webSocket; 447 final _WebSocketImpl webSocket;
433 448
434 _WebSocketOutgoingTransformer(_WebSocketImpl this.webSocket); 449 _WebSocketOutgoingTransformer(_WebSocketImpl this.webSocket);
435 450
436 void handleData(message, EventSink<List<int>> sink) { 451 void handleData(message, EventSink<List<int>> sink) {
452 if (message is _WebSocketPong) {
453 addFrame(_WebSocketOpcode.PONG, message.payload, sink);
454 return;
455 }
456 if (message is _WebSocketPing) {
457 addFrame(_WebSocketOpcode.PONG, message.payload, sink);
458 return;
459 }
437 List<int> data; 460 List<int> data;
438 int opcode; 461 int opcode;
439 if (message != null) { 462 if (message != null) {
440 if (message is String) { 463 if (message is String) {
441 opcode = _WebSocketOpcode.TEXT; 464 opcode = _WebSocketOpcode.TEXT;
442 data = _encodeString(message); 465 data = _encodeString(message);
443 } else { 466 } else {
444 if (message is !List<int>) { 467 if (message is !List<int>) {
445 throw new ArgumentError(message); 468 throw new ArgumentError(message);
446 } 469 }
(...skipping 16 matching lines...) Expand all
463 data.add(code & 0xFF); 486 data.add(code & 0xFF);
464 if (reason != null) { 487 if (reason != null) {
465 data.addAll(_encodeString(reason)); 488 data.addAll(_encodeString(reason));
466 } 489 }
467 } 490 }
468 addFrame(_WebSocketOpcode.CLOSE, data, sink); 491 addFrame(_WebSocketOpcode.CLOSE, data, sink);
469 sink.close(); 492 sink.close();
470 } 493 }
471 494
472 void addFrame(int opcode, List<int> data, EventSink<List<int>> sink) { 495 void addFrame(int opcode, List<int> data, EventSink<List<int>> sink) {
473 bool mask = !webSocket._serverSide; // Masking not implemented for server. 496 createFrame(opcode, data, webSocket._serverSide).forEach(sink.add);
497 }
498
499 static Iterator createFrame(int opcode, List<int> data, bool serverSide) {
500 bool mask = !serverSide; // Masking not implemented for server.
474 int dataLength = data == null ? 0 : data.length; 501 int dataLength = data == null ? 0 : data.length;
475 // Determine the header size. 502 // Determine the header size.
476 int headerSize = (mask) ? 6 : 2; 503 int headerSize = (mask) ? 6 : 2;
477 if (dataLength > 65535) { 504 if (dataLength > 65535) {
478 headerSize += 8; 505 headerSize += 8;
479 } else if (dataLength > 125) { 506 } else if (dataLength > 125) {
480 headerSize += 2; 507 headerSize += 2;
481 } 508 }
482 List<int> header = new List<int>(headerSize); 509 List<int> header = new List<int>(headerSize);
483 int index = 0; 510 int index = 0;
(...skipping 20 matching lines...) Expand all
504 index += 4; 531 index += 4;
505 if (data != null) { 532 if (data != null) {
506 var list = new Uint8List(data.length); 533 var list = new Uint8List(data.length);
507 for (int i = 0; i < data.length; i++) { 534 for (int i = 0; i < data.length; i++) {
508 list[i] = data[i] ^ maskBytes[i % 4]; 535 list[i] = data[i] ^ maskBytes[i % 4];
509 } 536 }
510 data = list; 537 data = list;
511 } 538 }
512 } 539 }
513 assert(index == headerSize); 540 assert(index == headerSize);
514 sink.add(header); 541 if (data == null) {
515 if (data != null) { 542 return [header];
516 sink.add(data); 543 } else {
544 return [header, data];
517 } 545 }
518 } 546 }
519 } 547 }
520 548
521 549
522 class _WebSocketConsumer implements StreamConsumer { 550 class _WebSocketConsumer implements StreamConsumer {
523 final _WebSocketImpl webSocket; 551 final _WebSocketImpl webSocket;
524 final Socket socket; 552 final Socket socket;
525 StreamController _controller; 553 StreamController _controller;
526 StreamSubscription _subscription; 554 StreamSubscription _subscription;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 _done(); 605 _done();
578 }, 606 },
579 onError: (error) { 607 onError: (error) {
580 _done(error); 608 _done(error);
581 }, 609 },
582 cancelOnError: true); 610 cancelOnError: true);
583 return _completer.future; 611 return _completer.future;
584 } 612 }
585 613
586 Future close() { 614 Future close() {
615 _ensureController();
587 Future closeSocket() { 616 Future closeSocket() {
588 return socket.close().then((_) => webSocket); 617 return socket.close().then((_) => webSocket);
589 } 618 }
590 if (_controller == null) return closeSocket();
591 _controller.close(); 619 _controller.close();
592 return _closeCompleter.future.then((_) => closeSocket()); 620 return _closeCompleter.future.then((_) => closeSocket());
593 } 621 }
622
623 void add(data) {
624 _ensureController();
625 _controller.add(data);
626 }
594 } 627 }
595 628
596 629
597 class _WebSocketImpl extends Stream implements WebSocket { 630 class _WebSocketImpl extends Stream implements WebSocket {
598 final StreamController _controller = new StreamController(); 631 final StreamController _controller = new StreamController();
599 StreamSink _sink; 632 StreamSink _sink;
600 633
601 final Socket _socket; 634 final Socket _socket;
602 final bool _serverSide; 635 final bool _serverSide;
603 int _readyState = WebSocket.CONNECTING; 636 int _readyState = WebSocket.CONNECTING;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 error("Bad response 'Sec-WebSocket-Accept' header"); 708 error("Bad response 'Sec-WebSocket-Accept' header");
676 } 709 }
677 } 710 }
678 return response.detachSocket() 711 return response.detachSocket()
679 .then((socket) => new _WebSocketImpl._fromSocket(socket)); 712 .then((socket) => new _WebSocketImpl._fromSocket(socket));
680 }); 713 });
681 } 714 }
682 715
683 _WebSocketImpl._fromSocket(Socket this._socket, 716 _WebSocketImpl._fromSocket(Socket this._socket,
684 [bool this._serverSide = false]) { 717 [bool this._serverSide = false]) {
685 _sink = new _StreamSinkImpl(new _WebSocketConsumer(this, _socket)); 718 var consumer = new _WebSocketConsumer(this, _socket);
719 _sink = new _StreamSinkImpl(consumer);
686 _readyState = WebSocket.OPEN; 720 _readyState = WebSocket.OPEN;
687 721
688 var transformer = new _WebSocketProtocolTransformer(_serverSide); 722 var transformer = new _WebSocketProtocolTransformer(_serverSide);
689 _socket.transform(transformer).listen( 723 _socket.transform(transformer).listen(
690 (data) { 724 (data) {
691 _controller.add(data); 725 if (data is _WebSocketPing) {
726 consumer.add(new _WebSocketPong(data.payload));
727 } else if (data is _WebSocketPong) {
728 // TODO(ajohnsen): Notify pong?
729 } else {
730 _controller.add(data);
731 }
692 }, 732 },
693 onError: (error) { 733 onError: (error) {
734 if (error is ArgumentError) {
735 close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
736 } else {
737 close(WebSocketStatus.PROTOCOL_ERROR);
738 }
694 _controller.addError(error); 739 _controller.addError(error);
695 _controller.close(); 740 _controller.close();
696 }, 741 },
697 onDone: () { 742 onDone: () {
698 if (_readyState == WebSocket.OPEN) { 743 if (_readyState == WebSocket.OPEN) {
699 _readyState = WebSocket.CLOSING; 744 _readyState = WebSocket.CLOSING;
700 if (transformer.closeCode != WebSocketStatus.NO_STATUS_RECEIVED) { 745 if (!_isReservedStatusCode(transformer.closeCode)) {
701 close(transformer.closeCode); 746 close(transformer.closeCode);
702 } else { 747 } else {
703 close(); 748 close();
704 } 749 }
705 _readyState = WebSocket.CLOSED; 750 _readyState = WebSocket.CLOSED;
706 } 751 }
707 _closeCode = transformer.closeCode; 752 _closeCode = transformer.closeCode;
708 _closeReason = transformer.closeReason; 753 _closeReason = transformer.closeReason;
709 _controller.close(); 754 _controller.close();
710 }, 755 },
(...skipping 17 matching lines...) Expand all
728 int get closeCode => _closeCode; 773 int get closeCode => _closeCode;
729 String get closeReason => _closeReason; 774 String get closeReason => _closeReason;
730 775
731 void add(data) => _sink.add(data); 776 void add(data) => _sink.add(data);
732 void addError(error) => _sink.addError(error); 777 void addError(error) => _sink.addError(error);
733 Future addStream(Stream stream) => _sink.addStream(stream); 778 Future addStream(Stream stream) => _sink.addStream(stream);
734 Future get done => _sink.done; 779 Future get done => _sink.done;
735 780
736 Future close([int code, String reason]) { 781 Future close([int code, String reason]) {
737 if (!_writeClosed) { 782 if (!_writeClosed) {
738 if (code == WebSocketStatus.RESERVED_1004 || 783 if (_isReservedStatusCode(code)) {
739 code == WebSocketStatus.NO_STATUS_RECEIVED ||
740 code == WebSocketStatus.RESERVED_1015) {
741 throw new WebSocketException("Reserved status code $code"); 784 throw new WebSocketException("Reserved status code $code");
742 } 785 }
743 _outCloseCode = code; 786 _outCloseCode = code;
744 _outCloseReason = reason; 787 _outCloseReason = reason;
745 _writeClosed = true; 788 _writeClosed = true;
746 } 789 }
747 return _sink.close(); 790 return _sink.close();
748 } 791 }
792
793 static bool _isReservedStatusCode(int code) {
794 return code != null &&
795 (code < WebSocketStatus.NORMAL_CLOSURE ||
796 code == WebSocketStatus.RESERVED_1004 ||
797 code == WebSocketStatus.NO_STATUS_RECEIVED ||
798 code == WebSocketStatus.ABNORMAL_CLOSURE ||
799 (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
800 code < WebSocketStatus.RESERVED_1015) ||
801 (code >= WebSocketStatus.RESERVED_1015 &&
802 code < 3000));
803 }
749 } 804 }
OLDNEW
« no previous file with comments | « sdk/lib/io/websocket.dart ('k') | sdk/lib/utf/utf_stream.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698