OLD | NEW |
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 // Matches _WebSocketOpcode. | 9 // Matches _WebSocketOpcode. |
10 class _WebSocketMessageType { | 10 class _WebSocketMessageType { |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 // Send the upgrade response. | 394 // Send the upgrade response. |
395 response | 395 response |
396 ..statusCode = HttpStatus.SWITCHING_PROTOCOLS | 396 ..statusCode = HttpStatus.SWITCHING_PROTOCOLS |
397 ..headers.add(HttpHeaders.CONNECTION, "Upgrade") | 397 ..headers.add(HttpHeaders.CONNECTION, "Upgrade") |
398 ..headers.add(HttpHeaders.UPGRADE, "websocket"); | 398 ..headers.add(HttpHeaders.UPGRADE, "websocket"); |
399 String key = request.headers.value("Sec-WebSocket-Key"); | 399 String key = request.headers.value("Sec-WebSocket-Key"); |
400 _SHA1 sha1 = new _SHA1(); | 400 _SHA1 sha1 = new _SHA1(); |
401 sha1.add("$key$_webSocketGUID".codeUnits); | 401 sha1.add("$key$_webSocketGUID".codeUnits); |
402 String accept = _CryptoUtils.bytesToBase64(sha1.close()); | 402 String accept = _CryptoUtils.bytesToBase64(sha1.close()); |
403 response.headers.add("Sec-WebSocket-Accept", accept); | 403 response.headers.add("Sec-WebSocket-Accept", accept); |
404 if (protocol != null && protocol.isNotEmpty) { | 404 if (protocol != null) { |
405 response.headers.add("Sec-WebSocket-Protocol", protocol); | 405 response.headers.add("Sec-WebSocket-Protocol", protocol); |
406 } | 406 } |
407 response.headers.contentLength = 0; | 407 response.headers.contentLength = 0; |
408 return response.detachSocket() | 408 return response.detachSocket() |
409 .then((socket) => new _WebSocketImpl._fromSocket( | 409 .then((socket) => new _WebSocketImpl._fromSocket( |
410 socket, protocol, true)); | 410 socket, protocol, true)); |
411 } | 411 } |
412 | 412 |
413 var protocols = request.headers['Sec-WebSocket-Protocol']; | 413 var protocols = request.headers['Sec-WebSocket-Protocol']; |
414 if (protocols != null && _protocolSelector != null) { | 414 if (protocols != null && _protocolSelector != null) { |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 Duration _pingInterval; | 762 Duration _pingInterval; |
763 Timer _pingTimer; | 763 Timer _pingTimer; |
764 _WebSocketConsumer _consumer; | 764 _WebSocketConsumer _consumer; |
765 | 765 |
766 int _outCloseCode; | 766 int _outCloseCode; |
767 String _outCloseReason; | 767 String _outCloseReason; |
768 Timer _closeTimer; | 768 Timer _closeTimer; |
769 | 769 |
770 static final HttpClient _httpClient = new HttpClient(); | 770 static final HttpClient _httpClient = new HttpClient(); |
771 | 771 |
772 static Future<WebSocket> connect(String url, List<String> protocols) { | 772 static Future<WebSocket> connect( |
| 773 String url, Iterable<String> protocols, Map<String, dynamic> headers) { |
773 Uri uri = Uri.parse(url); | 774 Uri uri = Uri.parse(url); |
774 if (uri.scheme != "ws" && uri.scheme != "wss") { | 775 if (uri.scheme != "ws" && uri.scheme != "wss") { |
775 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); | 776 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); |
776 } | 777 } |
777 if (uri.userInfo != "") { | 778 if (uri.userInfo != "") { |
778 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); | 779 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); |
779 } | 780 } |
780 | 781 |
781 Random random = new Random(); | 782 Random random = new Random(); |
782 // Generate 16 random bytes. | 783 // Generate 16 random bytes. |
783 Uint8List nonceData = new Uint8List(16); | 784 Uint8List nonceData = new Uint8List(16); |
784 for (int i = 0; i < 16; i++) { | 785 for (int i = 0; i < 16; i++) { |
785 nonceData[i] = random.nextInt(256); | 786 nonceData[i] = random.nextInt(256); |
786 } | 787 } |
787 String nonce = _CryptoUtils.bytesToBase64(nonceData); | 788 String nonce = _CryptoUtils.bytesToBase64(nonceData); |
788 | 789 |
789 uri = new Uri(scheme: uri.scheme == "wss" ? "https" : "http", | 790 uri = new Uri(scheme: uri.scheme == "wss" ? "https" : "http", |
790 userInfo: uri.userInfo, | 791 userInfo: uri.userInfo, |
791 host: uri.host, | 792 host: uri.host, |
792 port: uri.port, | 793 port: uri.port, |
793 path: uri.path, | 794 path: uri.path, |
794 query: uri.query, | 795 query: uri.query, |
795 fragment: uri.fragment); | 796 fragment: uri.fragment); |
796 return _httpClient.openUrl("GET", uri) | 797 return _httpClient.openUrl("GET", uri) |
797 .then((request) { | 798 .then((request) { |
| 799 if (headers != null) { |
| 800 headers.forEach((field, value) => request.headers.add(field, value)); |
| 801 } |
798 // Setup the initial handshake. | 802 // Setup the initial handshake. |
799 request.headers | 803 request.headers |
800 ..add(HttpHeaders.CONNECTION, "Upgrade") | 804 ..set(HttpHeaders.CONNECTION, "Upgrade") |
801 ..set(HttpHeaders.UPGRADE, "websocket") | 805 ..set(HttpHeaders.UPGRADE, "websocket") |
802 ..set("Sec-WebSocket-Key", nonce) | 806 ..set("Sec-WebSocket-Key", nonce) |
803 ..set("Cache-Control", "no-cache") | 807 ..set("Cache-Control", "no-cache") |
804 ..set("Sec-WebSocket-Version", "13"); | 808 ..set("Sec-WebSocket-Version", "13"); |
805 if (protocols.isNotEmpty) { | 809 if (protocols != null) { |
806 request.headers.add("Sec-WebSocket-Protocol", protocols); | 810 request.headers.add("Sec-WebSocket-Protocol", protocols.toList()); |
807 } | 811 } |
808 return request.close(); | 812 return request.close(); |
809 }) | 813 }) |
810 .then((response) { | 814 .then((response) { |
811 void error(String message) { | 815 void error(String message) { |
812 // Flush data. | 816 // Flush data. |
813 response.detachSocket().then((socket) { | 817 response.detachSocket().then((socket) { |
814 socket.destroy(); | 818 socket.destroy(); |
815 }); | 819 }); |
816 throw new WebSocketException(message); | 820 throw new WebSocketException(message); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1008 (code < WebSocketStatus.NORMAL_CLOSURE || | 1012 (code < WebSocketStatus.NORMAL_CLOSURE || |
1009 code == WebSocketStatus.RESERVED_1004 || | 1013 code == WebSocketStatus.RESERVED_1004 || |
1010 code == WebSocketStatus.NO_STATUS_RECEIVED || | 1014 code == WebSocketStatus.NO_STATUS_RECEIVED || |
1011 code == WebSocketStatus.ABNORMAL_CLOSURE || | 1015 code == WebSocketStatus.ABNORMAL_CLOSURE || |
1012 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && | 1016 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && |
1013 code < WebSocketStatus.RESERVED_1015) || | 1017 code < WebSocketStatus.RESERVED_1015) || |
1014 (code >= WebSocketStatus.RESERVED_1015 && | 1018 (code >= WebSocketStatus.RESERVED_1015 && |
1015 code < 3000)); | 1019 code < 3000)); |
1016 } | 1020 } |
1017 } | 1021 } |
OLD | NEW |