| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 final String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 5 final String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
| 6 | 6 |
| 7 class _WebSocketMessageType { | 7 class _WebSocketMessageType { |
| 8 static final int NONE = 0; | 8 static final int NONE = 0; |
| 9 static final int BINARY = 1; | 9 static final int BINARY = 1; |
| 10 static final int TEXT = 2; | 10 static final int TEXT = 2; |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 | 339 |
| 340 Function onMessageStart; | 340 Function onMessageStart; |
| 341 Function onMessageData; | 341 Function onMessageData; |
| 342 Function onMessageEnd; | 342 Function onMessageEnd; |
| 343 Function onClosed; | 343 Function onClosed; |
| 344 Function onError; | 344 Function onError; |
| 345 } | 345 } |
| 346 | 346 |
| 347 | 347 |
| 348 class _WebSocketConnectionBase { | 348 class _WebSocketConnectionBase { |
| 349 void _socketReady(DetachedSocket detached) { | 349 void _socketConnected(Socket socket) { |
| 350 assert(detached.socket != null); | 350 _socket = socket; |
| 351 _socket = detached.socket; | 351 _socket.onError = (e) { |
| 352 _reportError(e); |
| 353 _socket.close(); |
| 354 }; |
| 355 } |
| 356 |
| 357 void _startProcessing(List<int> unparsedData) { |
| 352 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); | 358 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); |
| 353 processor.onMessageStart = _onWebSocketMessageStart; | 359 processor.onMessageStart = _onWebSocketMessageStart; |
| 354 processor.onMessageData = _onWebSocketMessageData; | 360 processor.onMessageData = _onWebSocketMessageData; |
| 355 processor.onMessageEnd = _onWebSocketMessageEnd; | 361 processor.onMessageEnd = _onWebSocketMessageEnd; |
| 356 processor.onClosed = _onWebSocketClosed; | 362 processor.onClosed = _onWebSocketClosed; |
| 357 processor.onError = _onWebSocketError; | 363 processor.onError = _onWebSocketError; |
| 358 if (detached.unparsedData != null) { | 364 if (unparsedData != null) { |
| 359 processor.update(detached.unparsedData, 0, detached.unparsedData.length); | 365 processor.update(unparsedData, 0, unparsedData.length); |
| 360 } | 366 } |
| 361 _socket.onData = () { | 367 _socket.onData = () { |
| 362 int available = _socket.available(); | 368 int available = _socket.available(); |
| 363 List<int> data = new List<int>(available); | 369 List<int> data = new List<int>(available); |
| 364 int read = _socket.readList(data, 0, available); | 370 int read = _socket.readList(data, 0, available); |
| 365 processor.update(data, 0, read); | 371 processor.update(data, 0, read); |
| 366 }; | 372 }; |
| 367 _socket.onClosed = () { | 373 _socket.onClosed = () { |
| 368 processor.closed(); | 374 processor.closed(); |
| 369 if (_closeSent) { | 375 if (_closeSent) { |
| 370 // Got socket close in response to close frame. Don't treat | 376 // Got socket close in response to close frame. Don't treat |
| 371 // that as an error. | 377 // that as an error. |
| 372 if (_closeTimer != null) _closeTimer.cancel(); | 378 if (_closeTimer != null) _closeTimer.cancel(); |
| 373 } else { | 379 } else { |
| 374 _reportError(new WebSocketException("Unexpected close")); | 380 _reportError(new WebSocketException("Unexpected close")); |
| 375 } | 381 } |
| 376 _socket.close(); | 382 _socket.close(); |
| 377 }; | 383 }; |
| 378 _socket.onError = (e) { | |
| 379 _reportError(e); | |
| 380 _socket.close(); | |
| 381 }; | |
| 382 } | 384 } |
| 383 | 385 |
| 384 void set onMessage(void callback(Object message)) { | 386 void set onMessage(void callback(Object message)) { |
| 385 _onMessage = callback; | 387 _onMessage = callback; |
| 386 } | 388 } |
| 387 | 389 |
| 388 void set onClosed(void callback(int status, String reason)) { | 390 void set onClosed(void callback(int status, String reason)) { |
| 389 _onClosed = callback; | 391 _onClosed = callback; |
| 390 } | 392 } |
| 391 | 393 |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 _StringDecoder _decoder; | 555 _StringDecoder _decoder; |
| 554 ListOutputStream _outputStream; | 556 ListOutputStream _outputStream; |
| 555 bool _closeReceived = false; | 557 bool _closeReceived = false; |
| 556 bool _closeSent = false; | 558 bool _closeSent = false; |
| 557 } | 559 } |
| 558 | 560 |
| 559 | 561 |
| 560 class _WebSocketConnection | 562 class _WebSocketConnection |
| 561 extends _WebSocketConnectionBase implements WebSocketConnection { | 563 extends _WebSocketConnectionBase implements WebSocketConnection { |
| 562 _WebSocketConnection(DetachedSocket detached) { | 564 _WebSocketConnection(DetachedSocket detached) { |
| 563 _socketReady(detached); | 565 _socketConnected(detached.socket); |
| 566 _startProcessing(detached.unparsedData); |
| 564 } | 567 } |
| 565 } | 568 } |
| 566 | 569 |
| 567 | 570 |
| 568 class _WebSocketHandler implements WebSocketHandler { | 571 class _WebSocketHandler implements WebSocketHandler { |
| 569 void onRequest(HttpRequest request, HttpResponse response) { | 572 void onRequest(HttpRequest request, HttpResponse response) { |
| 570 // Check that this is a web socket upgrade. | 573 // Check that this is a web socket upgrade. |
| 571 if (!_isWebSocketUpgrade(request)) { | 574 if (!_isWebSocketUpgrade(request)) { |
| 572 response.statusCode = HttpStatus.BAD_REQUEST; | 575 response.statusCode = HttpStatus.BAD_REQUEST; |
| 573 response.outputStream.close(); | 576 response.outputStream.close(); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 return; | 674 return; |
| 672 } | 675 } |
| 673 | 676 |
| 674 if (!_isWebSocketUpgrade(response)) { | 677 if (!_isWebSocketUpgrade(response)) { |
| 675 _conn.detachSocket().socket.close(); | 678 _conn.detachSocket().socket.close(); |
| 676 throw new WebSocketException("Protocol upgrade failed"); | 679 throw new WebSocketException("Protocol upgrade failed"); |
| 677 return; | 680 return; |
| 678 } | 681 } |
| 679 | 682 |
| 680 // Connection upgrade successful. | 683 // Connection upgrade successful. |
| 681 _socketReady(_conn.detachSocket()); | 684 DetachedSocket detached = _conn.detachSocket(); |
| 685 _socketConnected(detached.socket); |
| 682 if (_onOpen != null) _onOpen(); | 686 if (_onOpen != null) _onOpen(); |
| 687 _startProcessing(detached.unparsedData); |
| 683 } | 688 } |
| 684 | 689 |
| 685 void _generateNonce() { | 690 void _generateNonce() { |
| 686 assert(_nonce == null); | 691 assert(_nonce == null); |
| 687 void intToBigEndianBytes(int value, List<int> bytes, int offset) { | 692 void intToBigEndianBytes(int value, List<int> bytes, int offset) { |
| 688 bytes[offset] = (value >> 24) & 0xFF; | 693 bytes[offset] = (value >> 24) & 0xFF; |
| 689 bytes[offset + 1] = (value >> 16) & 0xFF; | 694 bytes[offset + 1] = (value >> 16) & 0xFF; |
| 690 bytes[offset + 2] = (value >> 8) & 0xFF; | 695 bytes[offset + 2] = (value >> 8) & 0xFF; |
| 691 bytes[offset + 3] = value & 0xFF; | 696 bytes[offset + 3] = value & 0xFF; |
| 692 } | 697 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 } | 731 } |
| 727 return true; | 732 return true; |
| 728 } | 733 } |
| 729 | 734 |
| 730 Function _onRequest; | 735 Function _onRequest; |
| 731 Function _onOpen; | 736 Function _onOpen; |
| 732 Function _onNoUpgrade; | 737 Function _onNoUpgrade; |
| 733 HttpClientConnection _conn; | 738 HttpClientConnection _conn; |
| 734 String _nonce; | 739 String _nonce; |
| 735 } | 740 } |
| 741 |
| 742 |
| 743 class _WebSocket implements WebSocket { |
| 744 _WebSocket(String url, [protocols]) { |
| 745 Uri uri = new Uri.fromString(url); |
| 746 if (uri.scheme != "ws") { |
| 747 throw new WebSocketException("Unsupported URL scheme ${uri.scheme}"); |
| 748 } |
| 749 if (uri.userInfo != "") { |
| 750 throw new WebSocketException("Unsupported user info ${uri.userInfo}"); |
| 751 } |
| 752 int port = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port; |
| 753 String path; |
| 754 if (uri.query != "") { |
| 755 if (uri.fragment != "") { |
| 756 path = "${uri.path}?${uri.query}#${uri.fragment}"; |
| 757 } else { |
| 758 path = "${uri.path}?${uri.query}"; |
| 759 } |
| 760 } else { |
| 761 path = uri.path; |
| 762 } |
| 763 |
| 764 HttpClient client = new HttpClient(); |
| 765 HttpClientConnection conn = client.open("GET", uri.domain, port, path); |
| 766 if (protocols is String) protocols = [protocols]; |
| 767 _wsconn = new WebSocketClientConnection(conn, protocols); |
| 768 _wsconn.onOpen = () { |
| 769 // HTTP client not needed after socket have been detached. |
| 770 client.shutdown(); |
| 771 client = null; |
| 772 _readyState = WebSocket.OPEN; |
| 773 if (_onopen != null) _onopen(); |
| 774 }; |
| 775 _wsconn.onMessage = (message) { |
| 776 if (_onmessage != null) { |
| 777 _onmessage(new _WebSocketMessageEvent(message)); |
| 778 } |
| 779 }; |
| 780 _wsconn.onClosed = (status, reason) { |
| 781 _readyState = WebSocket.CLOSED; |
| 782 if (_onclose != null) { |
| 783 _onclose(new _WebSocketCloseEvent(true, status, reason)); |
| 784 } |
| 785 }; |
| 786 _wsconn.onNoUpgrade = (response) { |
| 787 if (_onerror != null) _onerror("Failed web socket connection"); |
| 788 }; |
| 789 _wsconn.onError = (e) { |
| 790 if (_onerror != null) _onerror(e); |
| 791 }; |
| 792 } |
| 793 |
| 794 int get readyState() => _readyState; |
| 795 int get bufferedAmount() => 0; |
| 796 |
| 797 void set onopen(Function callback) { |
| 798 _onopen = callback; |
| 799 } |
| 800 |
| 801 void set onerror(Function callback) { |
| 802 _onerror = callback; |
| 803 } |
| 804 |
| 805 void set onclose(Function callback) { |
| 806 _onclose = callback; |
| 807 } |
| 808 |
| 809 String get extensions() => null; |
| 810 String get protocol() => null; |
| 811 |
| 812 void close(int code, String reason) { |
| 813 if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING; |
| 814 _wsconn.close(code, reason); |
| 815 } |
| 816 |
| 817 void set onmessage(Function callback) { |
| 818 _onmessage = callback; |
| 819 } |
| 820 |
| 821 void send(data) { |
| 822 _wsconn.send(data); |
| 823 } |
| 824 |
| 825 WebSocketClientConnection _wsconn; |
| 826 int _readyState = WebSocket.CONNECTING; |
| 827 Function _onopen; |
| 828 Function _onerror; |
| 829 Function _onclose; |
| 830 Function _onmessage; |
| 831 } |
| 832 |
| 833 |
| 834 class _WebSocketMessageEvent implements MessageEvent { |
| 835 _WebSocketMessageEvent(this._data); |
| 836 get data() => _data; |
| 837 var _data; |
| 838 } |
| 839 |
| 840 |
| 841 class _WebSocketCloseEvent implements CloseEvent { |
| 842 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); |
| 843 bool get wasClean() => _wasClean; |
| 844 int get code() => _code; |
| 845 String get reason() => _reason; |
| 846 bool _wasClean; |
| 847 int _code; |
| 848 String _reason; |
| 849 } |
| OLD | NEW |