Chromium Code Reviews| 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 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 // before closing the socket. If a close frame does not arrive | 448 // before closing the socket. If a close frame does not arrive |
| 449 // within a reasonable amount of time just close the socket. | 449 // within a reasonable amount of time just close the socket. |
| 450 _socket.outputStream.close(); | 450 _socket.outputStream.close(); |
| 451 _closeTimer = new Timer(5000, (t) { | 451 _closeTimer = new Timer(5000, (t) { |
| 452 _socket.close(); | 452 _socket.close(); |
| 453 }); | 453 }); |
| 454 } | 454 } |
| 455 _closeSent = true; | 455 _closeSent = true; |
| 456 } | 456 } |
| 457 | 457 |
| 458 int hashCode() => _hash; | |
| 459 | |
| 458 _onWebSocketMessageStart(int type) { | 460 _onWebSocketMessageStart(int type) { |
| 459 _currentMessageType = type; | 461 _currentMessageType = type; |
| 460 if (_currentMessageType == _WebSocketMessageType.TEXT) { | 462 if (_currentMessageType == _WebSocketMessageType.TEXT) { |
| 461 _decoder = _StringDecoders.decoder(Encoding.UTF_8); | 463 _decoder = _StringDecoders.decoder(Encoding.UTF_8); |
| 462 } else { | 464 } else { |
| 463 _outputStream = new ListOutputStream(); | 465 _outputStream = new ListOutputStream(); |
| 464 } | 466 } |
| 465 } | 467 } |
| 466 | 468 |
| 467 _onWebSocketMessageData(List<int> buffer, int offset, int count) { | 469 _onWebSocketMessageData(List<int> buffer, int offset, int count) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 void _reportError(e) { | 541 void _reportError(e) { |
| 540 if (_onError != null) { | 542 if (_onError != null) { |
| 541 _onError(e); | 543 _onError(e); |
| 542 } else { | 544 } else { |
| 543 throw e; | 545 throw e; |
| 544 } | 546 } |
| 545 } | 547 } |
| 546 | 548 |
| 547 Socket _socket; | 549 Socket _socket; |
| 548 Timer _closeTimer; | 550 Timer _closeTimer; |
| 551 int _hash; | |
| 549 | 552 |
| 550 Function _onMessage; | 553 Function _onMessage; |
| 551 Function _onClosed; | 554 Function _onClosed; |
| 552 Function _onError; | 555 Function _onError; |
| 553 | 556 |
| 554 int _currentMessageType = _WebSocketMessageType.NONE; | 557 int _currentMessageType = _WebSocketMessageType.NONE; |
| 555 _StringDecoder _decoder; | 558 _StringDecoder _decoder; |
| 556 ListOutputStream _outputStream; | 559 ListOutputStream _outputStream; |
| 557 bool _closeReceived = false; | 560 bool _closeReceived = false; |
| 558 bool _closeSent = false; | 561 bool _closeSent = false; |
| 559 } | 562 } |
| 560 | 563 |
| 561 | 564 |
| 562 class _WebSocketConnection | 565 class _WebSocketConnection |
| 563 extends _WebSocketConnectionBase implements WebSocketConnection { | 566 extends _WebSocketConnectionBase implements WebSocketConnection { |
| 564 _WebSocketConnection(DetachedSocket detached) { | 567 _WebSocketConnection(DetachedSocket detached) { |
| 568 _hash = detached.socket.hashCode(); | |
| 565 _socketConnected(detached.socket); | 569 _socketConnected(detached.socket); |
| 566 _startProcessing(detached.unparsedData); | 570 _startProcessing(detached.unparsedData); |
| 567 } | 571 } |
| 568 } | 572 } |
| 569 | 573 |
| 570 | 574 |
| 571 class _WebSocketHandler implements WebSocketHandler { | 575 class _WebSocketHandler implements WebSocketHandler { |
| 572 void onRequest(HttpRequest request, HttpResponse response) { | 576 void onRequest(HttpRequest request, HttpResponse response) { |
| 573 // Check that this is a web socket upgrade. | 577 // Check that this is a web socket upgrade. |
| 574 if (!_isWebSocketUpgrade(request)) { | 578 if (!_isWebSocketUpgrade(request)) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 } | 632 } |
| 629 | 633 |
| 630 | 634 |
| 631 class _WebSocketClientConnection | 635 class _WebSocketClientConnection |
| 632 extends _WebSocketConnectionBase implements WebSocketClientConnection { | 636 extends _WebSocketConnectionBase implements WebSocketClientConnection { |
| 633 _WebSocketClientConnection(HttpClientConnection this._conn, | 637 _WebSocketClientConnection(HttpClientConnection this._conn, |
| 634 [List<String> protocols]) { | 638 [List<String> protocols]) { |
| 635 _conn.onRequest = _onHttpClientRequest; | 639 _conn.onRequest = _onHttpClientRequest; |
| 636 _conn.onResponse = _onHttpClientResponse; | 640 _conn.onResponse = _onHttpClientResponse; |
| 637 _conn.onError = (e) => _reportError(e); | 641 _conn.onError = (e) => _reportError(e); |
| 642 | |
| 643 // Generate the nonce now as it is also used to set the hash code. | |
|
Mads Ager (google)
2012/05/14 09:19:39
I don't actually know if it would be a security is
Søren Gjesse
2012/05/14 15:52:41
Done.
| |
| 644 _generateNonceAndHash(); | |
| 638 } | 645 } |
| 639 | 646 |
| 640 void set onRequest(void callback(HttpClientRequest request)) { | 647 void set onRequest(void callback(HttpClientRequest request)) { |
| 641 _onRequest = callback; | 648 _onRequest = callback; |
| 642 } | 649 } |
| 643 | 650 |
| 644 void set onOpen(void callback()) { | 651 void set onOpen(void callback()) { |
| 645 _onOpen = callback; | 652 _onOpen = callback; |
| 646 } | 653 } |
| 647 | 654 |
| 648 void set onNoUpgrade(void callback(HttpClientResponse request)) { | 655 void set onNoUpgrade(void callback(HttpClientResponse request)) { |
| 649 _onNoUpgrade = callback; | 656 _onNoUpgrade = callback; |
| 650 } | 657 } |
| 651 | 658 |
| 652 void _onHttpClientRequest(HttpClientRequest request) { | 659 void _onHttpClientRequest(HttpClientRequest request) { |
| 653 if (_onRequest != null) { | 660 if (_onRequest != null) { |
| 654 _onRequest(request); | 661 _onRequest(request); |
| 655 } | 662 } |
| 656 // Setup the initial handshake. | 663 // Setup the initial handshake. |
| 657 _generateNonce(); | |
| 658 request.headers.add(HttpHeaders.CONNECTION, "upgrade"); | 664 request.headers.add(HttpHeaders.CONNECTION, "upgrade"); |
| 659 request.headers.set(HttpHeaders.UPGRADE, "websocket"); | 665 request.headers.set(HttpHeaders.UPGRADE, "websocket"); |
| 660 request.headers.set("Sec-WebSocket-Key", _nonce); | 666 request.headers.set("Sec-WebSocket-Key", _nonce); |
| 661 request.headers.set("Sec-WebSocket-Version", "13"); | 667 request.headers.set("Sec-WebSocket-Version", "13"); |
| 662 request.contentLength = 0; | 668 request.contentLength = 0; |
| 663 request.outputStream.close(); | 669 request.outputStream.close(); |
| 664 } | 670 } |
| 665 | 671 |
| 666 void _onHttpClientResponse(HttpClientResponse response) { | 672 void _onHttpClientResponse(HttpClientResponse response) { |
| 667 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) { | 673 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 680 return; | 686 return; |
| 681 } | 687 } |
| 682 | 688 |
| 683 // Connection upgrade successful. | 689 // Connection upgrade successful. |
| 684 DetachedSocket detached = _conn.detachSocket(); | 690 DetachedSocket detached = _conn.detachSocket(); |
| 685 _socketConnected(detached.socket); | 691 _socketConnected(detached.socket); |
| 686 if (_onOpen != null) _onOpen(); | 692 if (_onOpen != null) _onOpen(); |
| 687 _startProcessing(detached.unparsedData); | 693 _startProcessing(detached.unparsedData); |
| 688 } | 694 } |
| 689 | 695 |
| 690 void _generateNonce() { | 696 void _generateNonceAndHash() { |
| 691 assert(_nonce == null); | 697 assert(_nonce == null); |
| 692 void intToBigEndianBytes(int value, List<int> bytes, int offset) { | 698 void intToBigEndianBytes(int value, List<int> bytes, int offset) { |
| 693 bytes[offset] = (value >> 24) & 0xFF; | 699 bytes[offset] = (value >> 24) & 0xFF; |
| 694 bytes[offset + 1] = (value >> 16) & 0xFF; | 700 bytes[offset + 1] = (value >> 16) & 0xFF; |
| 695 bytes[offset + 2] = (value >> 8) & 0xFF; | 701 bytes[offset + 2] = (value >> 8) & 0xFF; |
| 696 bytes[offset + 3] = value & 0xFF; | 702 bytes[offset + 3] = value & 0xFF; |
| 697 } | 703 } |
| 698 | 704 |
| 699 // Generate 16 random bytes. | 705 // Generate 16 random bytes. Use the last four bytes for the hash code. |
| 700 List<int> nonce = new List<int>(16); | 706 List<int> nonce = new List<int>(16); |
| 707 int r; | |
| 701 for (int i = 0; i < 4; i++) { | 708 for (int i = 0; i < 4; i++) { |
| 702 int r = (Math.random() * 0x100000000).toInt(); | 709 r = (Math.random() * 0x100000000).toInt(); |
| 703 intToBigEndianBytes(r, nonce, i * 4); | 710 intToBigEndianBytes(r, nonce, i * 4); |
| 704 } | 711 } |
| 705 _nonce = _Base64._encode(nonce); | 712 _nonce = _Base64._encode(nonce); |
| 713 _hash = r; | |
| 706 } | 714 } |
| 707 | 715 |
| 708 bool _isWebSocketUpgrade(HttpClientResponse response) { | 716 bool _isWebSocketUpgrade(HttpClientResponse response) { |
| 709 if (response.headers[HttpHeaders.CONNECTION] == null) { | 717 if (response.headers[HttpHeaders.CONNECTION] == null) { |
| 710 return false; | 718 return false; |
| 711 } | 719 } |
| 712 bool isUpgrade = false; | 720 bool isUpgrade = false; |
| 713 response.headers[HttpHeaders.CONNECTION].forEach((String value) { | 721 response.headers[HttpHeaders.CONNECTION].forEach((String value) { |
| 714 if (value.toLowerCase() == "upgrade") isUpgrade = true; | 722 if (value.toLowerCase() == "upgrade") isUpgrade = true; |
| 715 }); | 723 }); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 | 848 |
| 841 class _WebSocketCloseEvent implements CloseEvent { | 849 class _WebSocketCloseEvent implements CloseEvent { |
| 842 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); | 850 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); |
| 843 bool get wasClean() => _wasClean; | 851 bool get wasClean() => _wasClean; |
| 844 int get code() => _code; | 852 int get code() => _code; |
| 845 String get reason() => _reason; | 853 String get reason() => _reason; |
| 846 bool _wasClean; | 854 bool _wasClean; |
| 847 int _code; | 855 int _code; |
| 848 String _reason; | 856 String _reason; |
| 849 } | 857 } |
| OLD | NEW |