| 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 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 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 processor.onMessageData = _onWebSocketMessageData; | 372 processor.onMessageData = _onWebSocketMessageData; |
| 373 processor.onMessageEnd = _onWebSocketMessageEnd; | 373 processor.onMessageEnd = _onWebSocketMessageEnd; |
| 374 processor.onPing = _onWebSocketPing; | 374 processor.onPing = _onWebSocketPing; |
| 375 processor.onPong = _onWebSocketPong; | 375 processor.onPong = _onWebSocketPong; |
| 376 processor.onClosed = _onWebSocketClosed; | 376 processor.onClosed = _onWebSocketClosed; |
| 377 if (unparsedData != null) { | 377 if (unparsedData != null) { |
| 378 processor.update(unparsedData, 0, unparsedData.length); | 378 processor.update(unparsedData, 0, unparsedData.length); |
| 379 } | 379 } |
| 380 _socket.onData = () { | 380 _socket.onData = () { |
| 381 int available = _socket.available(); | 381 int available = _socket.available(); |
| 382 List<int> data = new List<int>(available); | 382 List<int> data = new List<int>.fixedLength(available); |
| 383 int read = _socket.readList(data, 0, available); | 383 int read = _socket.readList(data, 0, available); |
| 384 processor.update(data, 0, read); | 384 processor.update(data, 0, read); |
| 385 }; | 385 }; |
| 386 _socket.onClosed = () { | 386 _socket.onClosed = () { |
| 387 processor.closed(); | 387 processor.closed(); |
| 388 if (_closeSent) { | 388 if (_closeSent) { |
| 389 // Got socket close in response to close frame. Don't treat | 389 // Got socket close in response to close frame. Don't treat |
| 390 // that as an error. | 390 // that as an error. |
| 391 if (_closeTimer != null) _closeTimer.cancel(); | 391 if (_closeTimer != null) _closeTimer.cancel(); |
| 392 } else { | 392 } else { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 _sendFrame(int opcode, [List<int> data]) { | 529 _sendFrame(int opcode, [List<int> data]) { |
| 530 bool mask = false; // Masking not implemented for server. | 530 bool mask = false; // Masking not implemented for server. |
| 531 int dataLength = data == null ? 0 : data.length; | 531 int dataLength = data == null ? 0 : data.length; |
| 532 // Determine the header size. | 532 // Determine the header size. |
| 533 int headerSize = (mask) ? 6 : 2; | 533 int headerSize = (mask) ? 6 : 2; |
| 534 if (dataLength > 65535) { | 534 if (dataLength > 65535) { |
| 535 headerSize += 8; | 535 headerSize += 8; |
| 536 } else if (dataLength > 125) { | 536 } else if (dataLength > 125) { |
| 537 headerSize += 2; | 537 headerSize += 2; |
| 538 } | 538 } |
| 539 List<int> header = new List<int>(headerSize); | 539 List<int> header = new List<int>.fixedLength(headerSize); |
| 540 int index = 0; | 540 int index = 0; |
| 541 // Set FIN and opcode. | 541 // Set FIN and opcode. |
| 542 header[index++] = 0x80 | opcode; | 542 header[index++] = 0x80 | opcode; |
| 543 // Determine size and position of length field. | 543 // Determine size and position of length field. |
| 544 int lengthBytes = 1; | 544 int lengthBytes = 1; |
| 545 int firstLengthByte = 1; | 545 int firstLengthByte = 1; |
| 546 if (dataLength > 65535) { | 546 if (dataLength > 65535) { |
| 547 header[index++] = 127; | 547 header[index++] = 127; |
| 548 lengthBytes = 8; | 548 lengthBytes = 8; |
| 549 } else if (dataLength > 125) { | 549 } else if (dataLength > 125) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 response.outputStream.close(); | 594 response.outputStream.close(); |
| 595 return; | 595 return; |
| 596 } | 596 } |
| 597 | 597 |
| 598 // Send the upgrade response. | 598 // Send the upgrade response. |
| 599 response.statusCode = HttpStatus.SWITCHING_PROTOCOLS; | 599 response.statusCode = HttpStatus.SWITCHING_PROTOCOLS; |
| 600 response.headers.add(HttpHeaders.CONNECTION, "Upgrade"); | 600 response.headers.add(HttpHeaders.CONNECTION, "Upgrade"); |
| 601 response.headers.add(HttpHeaders.UPGRADE, "websocket"); | 601 response.headers.add(HttpHeaders.UPGRADE, "websocket"); |
| 602 String key = request.headers.value("Sec-WebSocket-Key"); | 602 String key = request.headers.value("Sec-WebSocket-Key"); |
| 603 SHA1 sha1 = new SHA1(); | 603 SHA1 sha1 = new SHA1(); |
| 604 sha1.update("$key$_webSocketGUID".charCodes); | 604 sha1.add("$key$_webSocketGUID".charCodes); |
| 605 String accept = _Base64._encode(sha1.digest()); | 605 String accept = _Base64._encode(sha1.close()); |
| 606 response.headers.add("Sec-WebSocket-Accept", accept); | 606 response.headers.add("Sec-WebSocket-Accept", accept); |
| 607 response.contentLength = 0; | 607 response.contentLength = 0; |
| 608 | 608 |
| 609 // Upgrade the connection and get the underlying socket. | 609 // Upgrade the connection and get the underlying socket. |
| 610 WebSocketConnection conn = | 610 WebSocketConnection conn = |
| 611 new _WebSocketConnection(response.detachSocket()); | 611 new _WebSocketConnection(response.detachSocket()); |
| 612 if (_onOpen != null) _onOpen(conn); | 612 if (_onOpen != null) _onOpen(conn); |
| 613 } | 613 } |
| 614 | 614 |
| 615 void set onOpen(callback(WebSocketConnection connection)) { | 615 void set onOpen(callback(WebSocketConnection connection)) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 Random random = new Random(); | 715 Random random = new Random(); |
| 716 assert(_nonce == null); | 716 assert(_nonce == null); |
| 717 void intToBigEndianBytes(int value, List<int> bytes, int offset) { | 717 void intToBigEndianBytes(int value, List<int> bytes, int offset) { |
| 718 bytes[offset] = (value >> 24) & 0xFF; | 718 bytes[offset] = (value >> 24) & 0xFF; |
| 719 bytes[offset + 1] = (value >> 16) & 0xFF; | 719 bytes[offset + 1] = (value >> 16) & 0xFF; |
| 720 bytes[offset + 2] = (value >> 8) & 0xFF; | 720 bytes[offset + 2] = (value >> 8) & 0xFF; |
| 721 bytes[offset + 3] = value & 0xFF; | 721 bytes[offset + 3] = value & 0xFF; |
| 722 } | 722 } |
| 723 | 723 |
| 724 // Generate 16 random bytes. Use the last four bytes for the hash code. | 724 // Generate 16 random bytes. Use the last four bytes for the hash code. |
| 725 List<int> nonce = new List<int>(16); | 725 List<int> nonce = new List<int>.fixedLength(16); |
| 726 for (int i = 0; i < 4; i++) { | 726 for (int i = 0; i < 4; i++) { |
| 727 int r = random.nextInt(0x100000000); | 727 int r = random.nextInt(0x100000000); |
| 728 intToBigEndianBytes(r, nonce, i * 4); | 728 intToBigEndianBytes(r, nonce, i * 4); |
| 729 } | 729 } |
| 730 _nonce = _Base64._encode(nonce); | 730 _nonce = _Base64._encode(nonce); |
| 731 _hash = random.nextInt(0x100000000); | 731 _hash = random.nextInt(0x100000000); |
| 732 } | 732 } |
| 733 | 733 |
| 734 bool _isWebSocketUpgrade(HttpClientResponse response) { | 734 bool _isWebSocketUpgrade(HttpClientResponse response) { |
| 735 if (response.headers[HttpHeaders.CONNECTION] == null) { | 735 if (response.headers[HttpHeaders.CONNECTION] == null) { |
| 736 return false; | 736 return false; |
| 737 } | 737 } |
| 738 bool isUpgrade = false; | 738 bool isUpgrade = false; |
| 739 response.headers[HttpHeaders.CONNECTION].forEach((String value) { | 739 response.headers[HttpHeaders.CONNECTION].forEach((String value) { |
| 740 if (value.toLowerCase() == "upgrade") isUpgrade = true; | 740 if (value.toLowerCase() == "upgrade") isUpgrade = true; |
| 741 }); | 741 }); |
| 742 if (!isUpgrade) return false; | 742 if (!isUpgrade) return false; |
| 743 String upgrade = response.headers.value(HttpHeaders.UPGRADE); | 743 String upgrade = response.headers.value(HttpHeaders.UPGRADE); |
| 744 if (upgrade == null || upgrade.toLowerCase() != "websocket") { | 744 if (upgrade == null || upgrade.toLowerCase() != "websocket") { |
| 745 return false; | 745 return false; |
| 746 } | 746 } |
| 747 String accept = response.headers.value("Sec-WebSocket-Accept"); | 747 String accept = response.headers.value("Sec-WebSocket-Accept"); |
| 748 if (accept == null) { | 748 if (accept == null) { |
| 749 return false; | 749 return false; |
| 750 } | 750 } |
| 751 SHA1 sha1 = new SHA1(); | 751 SHA1 sha1 = new SHA1(); |
| 752 sha1.update("$_nonce$_webSocketGUID".charCodes); | 752 sha1.add("$_nonce$_webSocketGUID".charCodes); |
| 753 List<int> expectedAccept = sha1.digest(); | 753 List<int> expectedAccept = sha1.close(); |
| 754 List<int> receivedAccept = _Base64._decode(accept); | 754 List<int> receivedAccept = _Base64._decode(accept); |
| 755 if (expectedAccept.length != receivedAccept.length) return false; | 755 if (expectedAccept.length != receivedAccept.length) return false; |
| 756 for (int i = 0; i < expectedAccept.length; i++) { | 756 for (int i = 0; i < expectedAccept.length; i++) { |
| 757 if (expectedAccept[i] != receivedAccept[i]) return false; | 757 if (expectedAccept[i] != receivedAccept[i]) return false; |
| 758 } | 758 } |
| 759 return true; | 759 return true; |
| 760 } | 760 } |
| 761 | 761 |
| 762 Function _onRequest; | 762 Function _onRequest; |
| 763 Function _onOpen; | 763 Function _onOpen; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 | 865 |
| 866 class _WebSocketCloseEvent implements CloseEvent { | 866 class _WebSocketCloseEvent implements CloseEvent { |
| 867 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); | 867 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); |
| 868 bool get wasClean => _wasClean; | 868 bool get wasClean => _wasClean; |
| 869 int get code => _code; | 869 int get code => _code; |
| 870 String get reason => _reason; | 870 String get reason => _reason; |
| 871 bool _wasClean; | 871 bool _wasClean; |
| 872 int _code; | 872 int _code; |
| 873 String _reason; | 873 String _reason; |
| 874 } | 874 } |
| OLD | NEW |