| OLD | NEW |
| 1 // Copyright (c) 2012, 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; |
| 11 static const int BINARY = 1; | 11 static const int BINARY = 1; |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 } | 418 } |
| 419 String key = request.headers.value("Sec-WebSocket-Key"); | 419 String key = request.headers.value("Sec-WebSocket-Key"); |
| 420 if (key == null) { | 420 if (key == null) { |
| 421 return false; | 421 return false; |
| 422 } | 422 } |
| 423 return true; | 423 return true; |
| 424 } | 424 } |
| 425 } | 425 } |
| 426 | 426 |
| 427 | 427 |
| 428 class _WebSocketImpl extends Stream<Event> implements WebSocket { | 428 class _WebSocketImpl extends Stream implements WebSocket { |
| 429 final StreamController<Event> _controller = new StreamController<Event>(); | 429 final StreamController _controller = new StreamController(); |
| 430 | 430 |
| 431 final _WebSocketProtocolProcessor _processor = | 431 final _WebSocketProtocolProcessor _processor = |
| 432 new _WebSocketProtocolProcessor(); | 432 new _WebSocketProtocolProcessor(); |
| 433 | 433 |
| 434 final Socket _socket; | 434 final Socket _socket; |
| 435 int _readyState = WebSocket.CONNECTING; | 435 int _readyState = WebSocket.CONNECTING; |
| 436 bool _writeClosed = false; | 436 bool _writeClosed = false; |
| 437 int _closeCode; |
| 438 String _closeReason; |
| 437 | 439 |
| 438 static final HttpClient _httpClient = new HttpClient(); | 440 static final HttpClient _httpClient = new HttpClient(); |
| 439 | 441 |
| 440 static Future<WebSocket> connect(String url, [protocols]) { | 442 static Future<WebSocket> connect(String url, [protocols]) { |
| 441 Uri uri = Uri.parse(url); | 443 Uri uri = Uri.parse(url); |
| 442 if (uri.scheme != "ws" && uri.scheme != "wss") { | 444 if (uri.scheme != "ws" && uri.scheme != "wss") { |
| 443 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); | 445 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); |
| 444 } | 446 } |
| 445 if (uri.userInfo != "") { | 447 if (uri.userInfo != "") { |
| 446 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); | 448 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 }; | 524 }; |
| 523 _processor.onMessageData = (buffer, offset, count) { | 525 _processor.onMessageData = (buffer, offset, count) { |
| 524 if (type == _WebSocketMessageType.TEXT) { | 526 if (type == _WebSocketMessageType.TEXT) { |
| 525 data.add(_decodeString(buffer.getRange(offset, count))); | 527 data.add(_decodeString(buffer.getRange(offset, count))); |
| 526 } else { | 528 } else { |
| 527 data.addAll(buffer.getRange(offset, count)); | 529 data.addAll(buffer.getRange(offset, count)); |
| 528 } | 530 } |
| 529 }; | 531 }; |
| 530 _processor.onMessageEnd = () { | 532 _processor.onMessageEnd = () { |
| 531 if (type == _WebSocketMessageType.TEXT) { | 533 if (type == _WebSocketMessageType.TEXT) { |
| 532 _controller.add(new _WebSocketMessageEvent(data.toString())); | 534 _controller.add(data.toString()); |
| 533 } else { | 535 } else { |
| 534 _controller.add(new _WebSocketMessageEvent(data)); | 536 _controller.add(data); |
| 535 } | 537 } |
| 536 }; | 538 }; |
| 537 _processor.onClosed = (code, reason) { | 539 _processor.onClosed = (code, reason) { |
| 538 bool clean = true; | 540 bool clean = true; |
| 539 if (_readyState == WebSocket.OPEN) { | 541 if (_readyState == WebSocket.OPEN) { |
| 540 _readyState = WebSocket.CLOSING; | 542 _readyState = WebSocket.CLOSING; |
| 541 if (code != WebSocketStatus.NO_STATUS_RECEIVED) { | 543 if (code != WebSocketStatus.NO_STATUS_RECEIVED) { |
| 542 _close(code); | 544 _close(code); |
| 543 } else { | 545 } else { |
| 544 _close(); | 546 _close(); |
| 545 clean = false; | 547 clean = false; |
| 546 } | 548 } |
| 547 _readyState = WebSocket.CLOSED; | 549 _readyState = WebSocket.CLOSED; |
| 548 } | 550 } |
| 549 if (_readyState == WebSocket.CLOSED) return; | 551 if (_readyState == WebSocket.CLOSED) return; |
| 550 _controller.add(new _WebSocketCloseEvent(clean, code, reason)); | 552 _closeCode = code; |
| 553 _closeReason = reason; |
| 551 _controller.close(); | 554 _controller.close(); |
| 552 }; | 555 }; |
| 553 | 556 |
| 554 _socket.listen( | 557 _socket.listen( |
| 555 (data) => _processor.update(data, 0, data.length), | 558 (data) => _processor.update(data, 0, data.length), |
| 556 onDone: () => _processor.closed(), | 559 onDone: () => _processor.closed(), |
| 557 onError: (error) => _controller.signalError(error)); | 560 onError: (error) => _controller.signalError(error)); |
| 558 | 561 |
| 559 _socket.done | 562 _socket.done |
| 560 .catchError((error) { | 563 .catchError((error) { |
| 561 if (_readyState == WebSocket.CLOSED) return; | 564 if (_readyState == WebSocket.CLOSED) return; |
| 562 _readyState = WebSocket.CLOSED; | 565 _readyState = WebSocket.CLOSED; |
| 566 _closeCode = ABNORMAL_CLOSURE; |
| 563 _controller.signalError(error); | 567 _controller.signalError(error); |
| 564 _controller.close(); | 568 _controller.close(); |
| 565 _socket.destroy(); | 569 _socket.destroy(); |
| 566 }) | 570 }) |
| 567 .whenComplete(() { | 571 .whenComplete(() { |
| 568 _writeClosed = true; | 572 _writeClosed = true; |
| 569 }); | 573 }); |
| 570 } | 574 } |
| 571 | 575 |
| 572 StreamSubscription<Event> listen(void onData(Event event), | 576 StreamSubscription listen(void onData(message), |
| 573 {void onError(AsyncError error), | 577 {void onError(AsyncError error), |
| 574 void onDone(), | 578 void onDone(), |
| 575 bool unsubscribeOnError}) { | 579 bool unsubscribeOnError}) { |
| 576 return _controller.stream.listen(onData, | 580 return _controller.stream.listen(onData, |
| 577 onError: onError, | 581 onError: onError, |
| 578 onDone: onDone, | 582 onDone: onDone, |
| 579 unsubscribeOnError: unsubscribeOnError); | 583 unsubscribeOnError: unsubscribeOnError); |
| 580 } | 584 } |
| 581 | 585 |
| 582 int get readyState => _readyState; | 586 int get readyState => _readyState; |
| 583 int get bufferedAmount => 0; | |
| 584 | 587 |
| 585 String get extensions => null; | 588 String get extensions => null; |
| 586 String get protocol => null; | 589 String get protocol => null; |
| 590 int get closeCode => _closeCode; |
| 591 String get closeReason => _closeReason; |
| 587 | 592 |
| 588 void close([int code, String reason]) { | 593 void close([int code, String reason]) { |
| 589 if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING; | 594 if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING; |
| 590 if (code == WebSocketStatus.RESERVED_1004 || | 595 if (code == WebSocketStatus.RESERVED_1004 || |
| 591 code == WebSocketStatus.NO_STATUS_RECEIVED || | 596 code == WebSocketStatus.NO_STATUS_RECEIVED || |
| 592 code == WebSocketStatus.RESERVED_1015) { | 597 code == WebSocketStatus.RESERVED_1015) { |
| 593 throw new WebSocketException("Reserved status code $code"); | 598 throw new WebSocketException("Reserved status code $code"); |
| 594 } | 599 } |
| 595 _close(code, reason); | 600 _close(code, reason); |
| 596 } | 601 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 for (int i = 0; i < lengthBytes; i++) { | 683 for (int i = 0; i < lengthBytes; i++) { |
| 679 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; | 684 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; |
| 680 } | 685 } |
| 681 assert(index == headerSize); | 686 assert(index == headerSize); |
| 682 _socket.add(header); | 687 _socket.add(header); |
| 683 if (data != null) { | 688 if (data != null) { |
| 684 _socket.add(data); | 689 _socket.add(data); |
| 685 } | 690 } |
| 686 } | 691 } |
| 687 } | 692 } |
| 688 | |
| 689 | |
| 690 class _WebSocketMessageEvent implements MessageEvent { | |
| 691 _WebSocketMessageEvent(this._data); | |
| 692 get data => _data; | |
| 693 var _data; | |
| 694 } | |
| 695 | |
| 696 | |
| 697 class _WebSocketCloseEvent implements CloseEvent { | |
| 698 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); | |
| 699 bool get wasClean => _wasClean; | |
| 700 int get code => _code; | |
| 701 String get reason => _reason; | |
| 702 bool _wasClean; | |
| 703 int _code; | |
| 704 String _reason; | |
| 705 } | |
| OLD | NEW |