| 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 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 5 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 
| 6 | 6 | 
| 7 class _WebSocketMessageType { | 7 class _WebSocketMessageType { | 
| 8   static const int NONE = 0; | 8   static const int NONE = 0; | 
| 9   static const int BINARY = 1; | 9   static const int BINARY = 1; | 
| 10   static const int TEXT = 2; | 10   static const int TEXT = 2; | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 81               if (_currentMessageType == _WebSocketMessageType.NONE) { | 81               if (_currentMessageType == _WebSocketMessageType.NONE) { | 
| 82                 throw new WebSocketException("Protocol error"); | 82                 throw new WebSocketException("Protocol error"); | 
| 83               } | 83               } | 
| 84               break; | 84               break; | 
| 85 | 85 | 
| 86             case _WebSocketOpcode.TEXT: | 86             case _WebSocketOpcode.TEXT: | 
| 87               if (_currentMessageType != _WebSocketMessageType.NONE) { | 87               if (_currentMessageType != _WebSocketMessageType.NONE) { | 
| 88                 throw new WebSocketException("Protocol error"); | 88                 throw new WebSocketException("Protocol error"); | 
| 89               } | 89               } | 
| 90               _currentMessageType = _WebSocketMessageType.TEXT; | 90               _currentMessageType = _WebSocketMessageType.TEXT; | 
| 91               if (onMessageStart !== null) { | 91               if (onMessageStart != null) { | 
| 92                 onMessageStart(_WebSocketMessageType.TEXT); | 92                 onMessageStart(_WebSocketMessageType.TEXT); | 
| 93               } | 93               } | 
| 94               break; | 94               break; | 
| 95 | 95 | 
| 96             case _WebSocketOpcode.BINARY: | 96             case _WebSocketOpcode.BINARY: | 
| 97               if (_currentMessageType != _WebSocketMessageType.NONE) { | 97               if (_currentMessageType != _WebSocketMessageType.NONE) { | 
| 98                 throw new WebSocketException("Protocol error"); | 98                 throw new WebSocketException("Protocol error"); | 
| 99               } | 99               } | 
| 100               _currentMessageType = _WebSocketMessageType.BINARY; | 100               _currentMessageType = _WebSocketMessageType.BINARY; | 
| 101               if (onMessageStart !== null) { | 101               if (onMessageStart != null) { | 
| 102                 onMessageStart(_WebSocketMessageType.BINARY); | 102                 onMessageStart(_WebSocketMessageType.BINARY); | 
| 103               } | 103               } | 
| 104               break; | 104               break; | 
| 105 | 105 | 
| 106             case _WebSocketOpcode.CLOSE: | 106             case _WebSocketOpcode.CLOSE: | 
| 107             case _WebSocketOpcode.PING: | 107             case _WebSocketOpcode.PING: | 
| 108             case _WebSocketOpcode.PONG: | 108             case _WebSocketOpcode.PONG: | 
| 109               // Control frames cannot be fragmented. | 109               // Control frames cannot be fragmented. | 
| 110               if (!_fin) throw new WebSocketException("Protocol error"); | 110               if (!_fin) throw new WebSocketException("Protocol error"); | 
| 111               break; | 111               break; | 
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 185               if (_remainingPayloadBytes == 0) { | 185               if (_remainingPayloadBytes == 0) { | 
| 186                 _controlFrameEnd(); | 186                 _controlFrameEnd(); | 
| 187               } | 187               } | 
| 188             } else { | 188             } else { | 
| 189               switch (_currentMessageType) { | 189               switch (_currentMessageType) { | 
| 190                 case _WebSocketMessageType.NONE: | 190                 case _WebSocketMessageType.NONE: | 
| 191                   throw new WebSocketException("Protocol error"); | 191                   throw new WebSocketException("Protocol error"); | 
| 192 | 192 | 
| 193                 case _WebSocketMessageType.TEXT: | 193                 case _WebSocketMessageType.TEXT: | 
| 194                 case _WebSocketMessageType.BINARY: | 194                 case _WebSocketMessageType.BINARY: | 
| 195                   if (onMessageData !== null) { | 195                   if (onMessageData != null) { | 
| 196                     onMessageData(buffer, index, payload); | 196                     onMessageData(buffer, index, payload); | 
| 197                   } | 197                   } | 
| 198                   index += payload; | 198                   index += payload; | 
| 199                   if (_remainingPayloadBytes == 0) { | 199                   if (_remainingPayloadBytes == 0) { | 
| 200                     _messageFrameEnd(); | 200                     _messageFrameEnd(); | 
| 201                   } | 201                   } | 
| 202                   break; | 202                   break; | 
| 203 | 203 | 
| 204                 default: | 204                 default: | 
| 205                   throw new WebSocketException("Protocol error"); | 205                   throw new WebSocketException("Protocol error"); | 
| 206               } | 206               } | 
| 207             } | 207             } | 
| 208 | 208 | 
| 209             // Hack - as we always do index++ below. | 209             // Hack - as we always do index++ below. | 
| 210             index--; | 210             index--; | 
| 211             break; | 211             break; | 
| 212         } | 212         } | 
| 213 | 213 | 
| 214         // Move to the next byte. | 214         // Move to the next byte. | 
| 215         index++; | 215         index++; | 
| 216       } | 216       } | 
| 217     } catch (e) { | 217     } catch (e) { | 
| 218       if (onClosed !== null) onClosed(WebSocketStatus.PROTOCOL_ERROR, | 218       if (onClosed != null) onClosed(WebSocketStatus.PROTOCOL_ERROR, | 
| 219                                       "Protocol error"); | 219                                       "Protocol error"); | 
| 220       _state = FAILURE; | 220       _state = FAILURE; | 
| 221     } | 221     } | 
| 222   } | 222   } | 
| 223 | 223 | 
| 224   /** | 224   /** | 
| 225    * Indicate that the underlying communication channel has been closed. | 225    * Indicate that the underlying communication channel has been closed. | 
| 226    */ | 226    */ | 
| 227   void closed() { | 227   void closed() { | 
| 228     if (_state == START || _state == CLOSED || _state == FAILURE) return; | 228     if (_state == START || _state == CLOSED || _state == FAILURE) return; | 
| 229     if (onClosed !== null) onClosed(WebSocketStatus.ABNORMAL_CLOSURE, | 229     if (onClosed != null) onClosed(WebSocketStatus.ABNORMAL_CLOSURE, | 
| 230                                     "Connection closed unexpectedly"); | 230                                     "Connection closed unexpectedly"); | 
| 231     _state = CLOSED; | 231     _state = CLOSED; | 
| 232   } | 232   } | 
| 233 | 233 | 
| 234   void _lengthDone() { | 234   void _lengthDone() { | 
| 235     if (_masked) { | 235     if (_masked) { | 
| 236       _state = MASK; | 236       _state = MASK; | 
| 237       _remainingMaskingKeyBytes = 4; | 237       _remainingMaskingKeyBytes = 4; | 
| 238     } else { | 238     } else { | 
| 239       _remainingPayloadBytes = _len; | 239       _remainingPayloadBytes = _len; | 
| 240       _startPayload(); | 240       _startPayload(); | 
| 241     } | 241     } | 
| 242   } | 242   } | 
| 243 | 243 | 
| 244   void _maskDone() { | 244   void _maskDone() { | 
| 245     _remainingPayloadBytes = _len; | 245     _remainingPayloadBytes = _len; | 
| 246     _startPayload(); | 246     _startPayload(); | 
| 247   } | 247   } | 
| 248 | 248 | 
| 249   void _startPayload() { | 249   void _startPayload() { | 
| 250     // If there is no actual payload perform perform callbacks without | 250     // If there is no actual payload perform perform callbacks without | 
| 251     // going through the PAYLOAD state. | 251     // going through the PAYLOAD state. | 
| 252     if (_remainingPayloadBytes == 0) { | 252     if (_remainingPayloadBytes == 0) { | 
| 253       if (_isControlFrame()) { | 253       if (_isControlFrame()) { | 
| 254         switch (_opcode) { | 254         switch (_opcode) { | 
| 255           case _WebSocketOpcode.CLOSE: | 255           case _WebSocketOpcode.CLOSE: | 
| 256             if (onClosed !== null) onClosed(1005, ""); | 256             if (onClosed != null) onClosed(1005, ""); | 
| 257             _state = CLOSED; | 257             _state = CLOSED; | 
| 258             break; | 258             break; | 
| 259           case _WebSocketOpcode.PING: | 259           case _WebSocketOpcode.PING: | 
| 260             if (onPing !== null) onPing(null); | 260             if (onPing != null) onPing(null); | 
| 261             break; | 261             break; | 
| 262           case _WebSocketOpcode.PONG: | 262           case _WebSocketOpcode.PONG: | 
| 263             if (onPong !== null) onPong(null); | 263             if (onPong != null) onPong(null); | 
| 264             break; | 264             break; | 
| 265         } | 265         } | 
| 266         _prepareForNextFrame(); | 266         _prepareForNextFrame(); | 
| 267       } else { | 267       } else { | 
| 268         _messageFrameEnd(); | 268         _messageFrameEnd(); | 
| 269       } | 269       } | 
| 270     } else { | 270     } else { | 
| 271       _state = PAYLOAD; | 271       _state = PAYLOAD; | 
| 272     } | 272     } | 
| 273   } | 273   } | 
| 274 | 274 | 
| 275   void _messageFrameEnd() { | 275   void _messageFrameEnd() { | 
| 276     if (_fin) { | 276     if (_fin) { | 
| 277       if (onMessageEnd !== null) onMessageEnd(); | 277       if (onMessageEnd != null) onMessageEnd(); | 
| 278       _currentMessageType = _WebSocketMessageType.NONE; | 278       _currentMessageType = _WebSocketMessageType.NONE; | 
| 279     } | 279     } | 
| 280     _prepareForNextFrame(); | 280     _prepareForNextFrame(); | 
| 281   } | 281   } | 
| 282 | 282 | 
| 283   void _controlFrameEnd() { | 283   void _controlFrameEnd() { | 
| 284     switch (_opcode) { | 284     switch (_opcode) { | 
| 285       case _WebSocketOpcode.CLOSE: | 285       case _WebSocketOpcode.CLOSE: | 
| 286         int status = WebSocketStatus.NO_STATUS_RECEIVED; | 286         int status = WebSocketStatus.NO_STATUS_RECEIVED; | 
| 287         String reason = ""; | 287         String reason = ""; | 
| 288         if (_controlPayload.length > 0) { | 288         if (_controlPayload.length > 0) { | 
| 289           if (_controlPayload.length == 1) { | 289           if (_controlPayload.length == 1) { | 
| 290             throw new WebSocketException("Protocol error"); | 290             throw new WebSocketException("Protocol error"); | 
| 291           } | 291           } | 
| 292           status = _controlPayload[0] << 8 | _controlPayload[1]; | 292           status = _controlPayload[0] << 8 | _controlPayload[1]; | 
| 293           if (status == WebSocketStatus.NO_STATUS_RECEIVED) { | 293           if (status == WebSocketStatus.NO_STATUS_RECEIVED) { | 
| 294             throw new WebSocketException("Protocol error"); | 294             throw new WebSocketException("Protocol error"); | 
| 295           } | 295           } | 
| 296           if (_controlPayload.length > 2) { | 296           if (_controlPayload.length > 2) { | 
| 297             var decoder = _StringDecoders.decoder(Encoding.UTF_8); | 297             var decoder = _StringDecoders.decoder(Encoding.UTF_8); | 
| 298             decoder.write( | 298             decoder.write( | 
| 299                 _controlPayload.getRange(2, _controlPayload.length - 2)); | 299                 _controlPayload.getRange(2, _controlPayload.length - 2)); | 
| 300             reason = decoder.decoded(); | 300             reason = decoder.decoded(); | 
| 301           } | 301           } | 
| 302         } | 302         } | 
| 303         if (onClosed !== null) onClosed(status, reason); | 303         if (onClosed != null) onClosed(status, reason); | 
| 304         _state = CLOSED; | 304         _state = CLOSED; | 
| 305         break; | 305         break; | 
| 306 | 306 | 
| 307       case _WebSocketOpcode.PING: | 307       case _WebSocketOpcode.PING: | 
| 308         if (onPing !== null) onPing(_controlPayload); | 308         if (onPing != null) onPing(_controlPayload); | 
| 309         break; | 309         break; | 
| 310 | 310 | 
| 311       case _WebSocketOpcode.PONG: | 311       case _WebSocketOpcode.PONG: | 
| 312         if (onPong !== null) onPong(_controlPayload); | 312         if (onPong != null) onPong(_controlPayload); | 
| 313         break; | 313         break; | 
| 314     } | 314     } | 
| 315     _prepareForNextFrame(); | 315     _prepareForNextFrame(); | 
| 316   } | 316   } | 
| 317 | 317 | 
| 318   bool _isControlFrame() { | 318   bool _isControlFrame() { | 
| 319     return _opcode == _WebSocketOpcode.CLOSE || | 319     return _opcode == _WebSocketOpcode.CLOSE || | 
| 320            _opcode == _WebSocketOpcode.PING || | 320            _opcode == _WebSocketOpcode.PING || | 
| 321            _opcode == _WebSocketOpcode.PONG; | 321            _opcode == _WebSocketOpcode.PONG; | 
| 322   } | 322   } | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 365   } | 365   } | 
| 366 | 366 | 
| 367   void _startProcessing(List<int> unparsedData) { | 367   void _startProcessing(List<int> unparsedData) { | 
| 368     _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); | 368     _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); | 
| 369     processor.onMessageStart = _onWebSocketMessageStart; | 369     processor.onMessageStart = _onWebSocketMessageStart; | 
| 370     processor.onMessageData = _onWebSocketMessageData; | 370     processor.onMessageData = _onWebSocketMessageData; | 
| 371     processor.onMessageEnd = _onWebSocketMessageEnd; | 371     processor.onMessageEnd = _onWebSocketMessageEnd; | 
| 372     processor.onPing = _onWebSocketPing; | 372     processor.onPing = _onWebSocketPing; | 
| 373     processor.onPong = _onWebSocketPong; | 373     processor.onPong = _onWebSocketPong; | 
| 374     processor.onClosed = _onWebSocketClosed; | 374     processor.onClosed = _onWebSocketClosed; | 
| 375     if (unparsedData !== null) { | 375     if (unparsedData != null) { | 
| 376       processor.update(unparsedData, 0, unparsedData.length); | 376       processor.update(unparsedData, 0, unparsedData.length); | 
| 377     } | 377     } | 
| 378     _socket.onData = () { | 378     _socket.onData = () { | 
| 379       int available = _socket.available(); | 379       int available = _socket.available(); | 
| 380       List<int> data = new List<int>(available); | 380       List<int> data = new List<int>(available); | 
| 381       int read = _socket.readList(data, 0, available); | 381       int read = _socket.readList(data, 0, available); | 
| 382       processor.update(data, 0, read); | 382       processor.update(data, 0, read); | 
| 383     }; | 383     }; | 
| 384     _socket.onClosed = () { | 384     _socket.onClosed = () { | 
| 385       processor.closed(); | 385       processor.closed(); | 
| 386       if (_closeSent) { | 386       if (_closeSent) { | 
| 387         // Got socket close in response to close frame. Don't treat | 387         // Got socket close in response to close frame. Don't treat | 
| 388         // that as an error. | 388         // that as an error. | 
| 389         if (_closeTimer !== null) _closeTimer.cancel(); | 389         if (_closeTimer != null) _closeTimer.cancel(); | 
| 390       } else { | 390       } else { | 
| 391         if (_onClosed !== null) _onClosed(WebSocketStatus.ABNORMAL_CLOSURE, | 391         if (_onClosed != null) _onClosed(WebSocketStatus.ABNORMAL_CLOSURE, | 
| 392                                           "Unexpected close"); | 392                                           "Unexpected close"); | 
| 393       } | 393       } | 
| 394       _socket.close(); | 394       _socket.close(); | 
| 395     }; | 395     }; | 
| 396   } | 396   } | 
| 397 | 397 | 
| 398   void set onMessage(void callback(Object message)) { | 398   void set onMessage(void callback(Object message)) { | 
| 399     _onMessage = callback; | 399     _onMessage = callback; | 
| 400   } | 400   } | 
| 401 | 401 | 
| 402   void set onClosed(void callback(int status, String reason)) { | 402   void set onClosed(void callback(int status, String reason)) { | 
| 403     _onClosed = callback; | 403     _onClosed = callback; | 
| 404   } | 404   } | 
| 405 | 405 | 
| 406   send(message) { | 406   send(message) { | 
| 407     if (_closeSent) { | 407     if (_closeSent) { | 
| 408       throw new WebSocketException("Connection closed"); | 408       throw new WebSocketException("Connection closed"); | 
| 409     } | 409     } | 
| 410     List<int> data; | 410     List<int> data; | 
| 411     int opcode; | 411     int opcode; | 
| 412     if (message !== null) { | 412     if (message != null) { | 
| 413       if (message is String) { | 413       if (message is String) { | 
| 414         opcode = _WebSocketOpcode.TEXT; | 414         opcode = _WebSocketOpcode.TEXT; | 
| 415         data = _StringEncoders.encoder(Encoding.UTF_8).encodeString(message); | 415         data = _StringEncoders.encoder(Encoding.UTF_8).encodeString(message); | 
| 416       } else { | 416       } else { | 
| 417         if (message is !List<int>) { | 417         if (message is !List<int>) { | 
| 418           throw new ArgumentError(message); | 418           throw new ArgumentError(message); | 
| 419         } | 419         } | 
| 420         opcode = _WebSocketOpcode.BINARY; | 420         opcode = _WebSocketOpcode.BINARY; | 
| 421         data = message; | 421         data = message; | 
| 422       } | 422       } | 
| 423     } else { | 423     } else { | 
| 424       opcode = _WebSocketOpcode.TEXT; | 424       opcode = _WebSocketOpcode.TEXT; | 
| 425     } | 425     } | 
| 426     _sendFrame(opcode, data); | 426     _sendFrame(opcode, data); | 
| 427   } | 427   } | 
| 428 | 428 | 
| 429   close([int status, String reason]) { | 429   close([int status, String reason]) { | 
| 430     if (status == WebSocketStatus.RESERVED_1004 || | 430     if (status == WebSocketStatus.RESERVED_1004 || | 
| 431         status == WebSocketStatus.NO_STATUS_RECEIVED || | 431         status == WebSocketStatus.NO_STATUS_RECEIVED || | 
| 432         status == WebSocketStatus.RESERVED_1015) { | 432         status == WebSocketStatus.RESERVED_1015) { | 
| 433       throw new WebSocketException("Reserved status code $status"); | 433       throw new WebSocketException("Reserved status code $status"); | 
| 434     } | 434     } | 
| 435 | 435 | 
| 436     if (_closeSent) return; | 436     if (_closeSent) return; | 
| 437     List<int> data; | 437     List<int> data; | 
| 438     if (status !== null) { | 438     if (status != null) { | 
| 439       data = new List<int>(); | 439       data = new List<int>(); | 
| 440       data.add((status >> 8) & 0xFF); | 440       data.add((status >> 8) & 0xFF); | 
| 441       data.add(status & 0xFF); | 441       data.add(status & 0xFF); | 
| 442       if (reason !== null) { | 442       if (reason != null) { | 
| 443         data.addAll( | 443         data.addAll( | 
| 444            _StringEncoders.encoder(Encoding.UTF_8).encodeString(reason)); | 444            _StringEncoders.encoder(Encoding.UTF_8).encodeString(reason)); | 
| 445       } | 445       } | 
| 446     } | 446     } | 
| 447     _sendFrame(_WebSocketOpcode.CLOSE, data); | 447     _sendFrame(_WebSocketOpcode.CLOSE, data); | 
| 448 | 448 | 
| 449     if (_closeReceived) { | 449     if (_closeReceived) { | 
| 450       // Close the socket when the close frame has been sent - if it | 450       // Close the socket when the close frame has been sent - if it | 
| 451       // does not take too long. | 451       // does not take too long. | 
| 452       _socket.outputStream.close(); | 452       _socket.outputStream.close(); | 
| 453       _socket.outputStream.onClosed = () { | 453       _socket.outputStream.onClosed = () { | 
| 454         if (_closeTimer !== null) _closeTimer.cancel(); | 454         if (_closeTimer != null) _closeTimer.cancel(); | 
| 455         _socket.close(); | 455         _socket.close(); | 
| 456       }; | 456       }; | 
| 457       _closeTimer = new Timer(5000, (t) { | 457       _closeTimer = new Timer(5000, (t) { | 
| 458         _socket.close(); | 458         _socket.close(); | 
| 459       }); | 459       }); | 
| 460     } else { | 460     } else { | 
| 461       // Half close the socket and expect a close frame in response | 461       // Half close the socket and expect a close frame in response | 
| 462       // before closing the socket. If a close frame does not arrive | 462       // before closing the socket. If a close frame does not arrive | 
| 463       // within a reasonable amount of time just close the socket. | 463       // within a reasonable amount of time just close the socket. | 
| 464       _socket.outputStream.close(); | 464       _socket.outputStream.close(); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 482 | 482 | 
| 483   _onWebSocketMessageData(List<int> buffer, int offset, int count) { | 483   _onWebSocketMessageData(List<int> buffer, int offset, int count) { | 
| 484     if (_currentMessageType == _WebSocketMessageType.TEXT) { | 484     if (_currentMessageType == _WebSocketMessageType.TEXT) { | 
| 485       _decoder.write(buffer.getRange(offset, count)); | 485       _decoder.write(buffer.getRange(offset, count)); | 
| 486     } else { | 486     } else { | 
| 487       _outputStream.write(buffer.getRange(offset, count)); | 487       _outputStream.write(buffer.getRange(offset, count)); | 
| 488     } | 488     } | 
| 489   } | 489   } | 
| 490 | 490 | 
| 491   _onWebSocketMessageEnd() { | 491   _onWebSocketMessageEnd() { | 
| 492     if (_onMessage !== null) { | 492     if (_onMessage != null) { | 
| 493       if (_currentMessageType == _WebSocketMessageType.TEXT) { | 493       if (_currentMessageType == _WebSocketMessageType.TEXT) { | 
| 494         _onMessage(_decoder.decoded()); | 494         _onMessage(_decoder.decoded()); | 
| 495       } else { | 495       } else { | 
| 496         _onMessage(_outputStream.read()); | 496         _onMessage(_outputStream.read()); | 
| 497       } | 497       } | 
| 498     } | 498     } | 
| 499     _decoder = null; | 499     _decoder = null; | 
| 500     _outputStream = null; | 500     _outputStream = null; | 
| 501   } | 501   } | 
| 502 | 502 | 
| 503   _onWebSocketPing(List<int> payload) { | 503   _onWebSocketPing(List<int> payload) { | 
| 504     _sendFrame(_WebSocketOpcode.PONG, payload); | 504     _sendFrame(_WebSocketOpcode.PONG, payload); | 
| 505   } | 505   } | 
| 506 | 506 | 
| 507   _onWebSocketPong(List<int> payload) { | 507   _onWebSocketPong(List<int> payload) { | 
| 508     // Currently pong messages are ignored. | 508     // Currently pong messages are ignored. | 
| 509   } | 509   } | 
| 510 | 510 | 
| 511   _onWebSocketClosed(int status, String reason) { | 511   _onWebSocketClosed(int status, String reason) { | 
| 512     _closeReceived = true; | 512     _closeReceived = true; | 
| 513     if (_onClosed !== null) _onClosed(status, reason); | 513     if (_onClosed != null) _onClosed(status, reason); | 
| 514     if (_closeSent) { | 514     if (_closeSent) { | 
| 515       // Got close frame in response to close frame. Now close the socket. | 515       // Got close frame in response to close frame. Now close the socket. | 
| 516       if (_closeTimer !== null) _closeTimer.cancel(); | 516       if (_closeTimer != null) _closeTimer.cancel(); | 
| 517       _socket.close(); | 517       _socket.close(); | 
| 518     } else { | 518     } else { | 
| 519       if (status != WebSocketStatus.NO_STATUS_RECEIVED) { | 519       if (status != WebSocketStatus.NO_STATUS_RECEIVED) { | 
| 520         close(status); | 520         close(status); | 
| 521       } else { | 521       } else { | 
| 522         close(); | 522         close(); | 
| 523       } | 523       } | 
| 524     } | 524     } | 
| 525   } | 525   } | 
| 526 | 526 | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 547     } else if (dataLength > 125) { | 547     } else if (dataLength > 125) { | 
| 548       header[index++] = 126; | 548       header[index++] = 126; | 
| 549       lengthBytes = 2; | 549       lengthBytes = 2; | 
| 550     } | 550     } | 
| 551     // Write the length in network byte order into the header. | 551     // Write the length in network byte order into the header. | 
| 552     for (int i = 0; i < lengthBytes; i++) { | 552     for (int i = 0; i < lengthBytes; i++) { | 
| 553       header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; | 553       header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; | 
| 554     } | 554     } | 
| 555     assert(index == headerSize); | 555     assert(index == headerSize); | 
| 556     _socket.outputStream.write(header); | 556     _socket.outputStream.write(header); | 
| 557     if (data !== null) { | 557     if (data != null) { | 
| 558       _socket.outputStream.write(data); | 558       _socket.outputStream.write(data); | 
| 559     } | 559     } | 
| 560   } | 560   } | 
| 561 | 561 | 
| 562   Socket _socket; | 562   Socket _socket; | 
| 563   Timer _closeTimer; | 563   Timer _closeTimer; | 
| 564   int _hash; | 564   int _hash; | 
| 565 | 565 | 
| 566   Function _onMessage; | 566   Function _onMessage; | 
| 567   Function _onClosed; | 567   Function _onClosed; | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 600     String key = request.headers.value("Sec-WebSocket-Key"); | 600     String key = request.headers.value("Sec-WebSocket-Key"); | 
| 601     SHA1 sha1 = new SHA1(); | 601     SHA1 sha1 = new SHA1(); | 
| 602     sha1.update("$key$_webSocketGUID".charCodes); | 602     sha1.update("$key$_webSocketGUID".charCodes); | 
| 603     String accept = _Base64._encode(sha1.digest()); | 603     String accept = _Base64._encode(sha1.digest()); | 
| 604     response.headers.add("Sec-WebSocket-Accept", accept); | 604     response.headers.add("Sec-WebSocket-Accept", accept); | 
| 605     response.contentLength = 0; | 605     response.contentLength = 0; | 
| 606 | 606 | 
| 607     // Upgrade the connection and get the underlying socket. | 607     // Upgrade the connection and get the underlying socket. | 
| 608     WebSocketConnection conn = | 608     WebSocketConnection conn = | 
| 609         new _WebSocketConnection(response.detachSocket()); | 609         new _WebSocketConnection(response.detachSocket()); | 
| 610     if (_onOpen !== null) _onOpen(conn); | 610     if (_onOpen != null) _onOpen(conn); | 
| 611   } | 611   } | 
| 612 | 612 | 
| 613   void set onOpen(callback(WebSocketConnection connection)) { | 613   void set onOpen(callback(WebSocketConnection connection)) { | 
| 614     _onOpen = callback; | 614     _onOpen = callback; | 
| 615   } | 615   } | 
| 616 | 616 | 
| 617   bool _isWebSocketUpgrade(HttpRequest request) { | 617   bool _isWebSocketUpgrade(HttpRequest request) { | 
| 618     if (request.method != "GET") { | 618     if (request.method != "GET") { | 
| 619       return false; | 619       return false; | 
| 620     } | 620     } | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 645 } | 645 } | 
| 646 | 646 | 
| 647 | 647 | 
| 648 class _WebSocketClientConnection | 648 class _WebSocketClientConnection | 
| 649     extends _WebSocketConnectionBase implements WebSocketClientConnection { | 649     extends _WebSocketConnectionBase implements WebSocketClientConnection { | 
| 650   _WebSocketClientConnection(HttpClientConnection this._conn, | 650   _WebSocketClientConnection(HttpClientConnection this._conn, | 
| 651                              [List<String> protocols]) { | 651                              [List<String> protocols]) { | 
| 652     _conn.onRequest = _onHttpClientRequest; | 652     _conn.onRequest = _onHttpClientRequest; | 
| 653     _conn.onResponse = _onHttpClientResponse; | 653     _conn.onResponse = _onHttpClientResponse; | 
| 654     _conn.onError = (e) { | 654     _conn.onError = (e) { | 
| 655       if (_onClosed !== null) { | 655       if (_onClosed != null) { | 
| 656         _onClosed(WebSocketStatus.ABNORMAL_CLOSURE, "$e"); | 656         _onClosed(WebSocketStatus.ABNORMAL_CLOSURE, "$e"); | 
| 657       } | 657       } | 
| 658     }; | 658     }; | 
| 659 | 659 | 
| 660     // Generate the nonce now as it is also used to set the hash code. | 660     // Generate the nonce now as it is also used to set the hash code. | 
| 661     _generateNonceAndHash(); | 661     _generateNonceAndHash(); | 
| 662   } | 662   } | 
| 663 | 663 | 
| 664   void set onRequest(void callback(HttpClientRequest request)) { | 664   void set onRequest(void callback(HttpClientRequest request)) { | 
| 665     _onRequest = callback; | 665     _onRequest = callback; | 
| 666   } | 666   } | 
| 667 | 667 | 
| 668   void set onOpen(void callback()) { | 668   void set onOpen(void callback()) { | 
| 669     _onOpen = callback; | 669     _onOpen = callback; | 
| 670   } | 670   } | 
| 671 | 671 | 
| 672   void set onNoUpgrade(void callback(HttpClientResponse request)) { | 672   void set onNoUpgrade(void callback(HttpClientResponse request)) { | 
| 673     _onNoUpgrade = callback; | 673     _onNoUpgrade = callback; | 
| 674   } | 674   } | 
| 675 | 675 | 
| 676   void _onHttpClientRequest(HttpClientRequest request) { | 676   void _onHttpClientRequest(HttpClientRequest request) { | 
| 677     if (_onRequest !== null) { | 677     if (_onRequest != null) { | 
| 678       _onRequest(request); | 678       _onRequest(request); | 
| 679     } | 679     } | 
| 680     // Setup the initial handshake. | 680     // Setup the initial handshake. | 
| 681     request.headers.add(HttpHeaders.CONNECTION, "upgrade"); | 681     request.headers.add(HttpHeaders.CONNECTION, "upgrade"); | 
| 682     request.headers.set(HttpHeaders.UPGRADE, "websocket"); | 682     request.headers.set(HttpHeaders.UPGRADE, "websocket"); | 
| 683     request.headers.set("Sec-WebSocket-Key", _nonce); | 683     request.headers.set("Sec-WebSocket-Key", _nonce); | 
| 684     request.headers.set("Sec-WebSocket-Version", "13"); | 684     request.headers.set("Sec-WebSocket-Version", "13"); | 
| 685     request.contentLength = 0; | 685     request.contentLength = 0; | 
| 686     request.outputStream.close(); | 686     request.outputStream.close(); | 
| 687   } | 687   } | 
| 688 | 688 | 
| 689   void _onHttpClientResponse(HttpClientResponse response) { | 689   void _onHttpClientResponse(HttpClientResponse response) { | 
| 690     if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) { | 690     if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) { | 
| 691       if (_onNoUpgrade !== null) { | 691       if (_onNoUpgrade != null) { | 
| 692         _onNoUpgrade(response); | 692         _onNoUpgrade(response); | 
| 693       } else { | 693       } else { | 
| 694         _conn.detachSocket().socket.close(); | 694         _conn.detachSocket().socket.close(); | 
| 695         throw new WebSocketException("Protocol upgrade refused"); | 695         throw new WebSocketException("Protocol upgrade refused"); | 
| 696       } | 696       } | 
| 697       return; | 697       return; | 
| 698     } | 698     } | 
| 699 | 699 | 
| 700     if (!_isWebSocketUpgrade(response)) { | 700     if (!_isWebSocketUpgrade(response)) { | 
| 701       _conn.detachSocket().socket.close(); | 701       _conn.detachSocket().socket.close(); | 
| 702       throw new WebSocketException("Protocol upgrade failed"); | 702       throw new WebSocketException("Protocol upgrade failed"); | 
| 703       return; | 703       return; | 
| 704     } | 704     } | 
| 705 | 705 | 
| 706     // Connection upgrade successful. | 706     // Connection upgrade successful. | 
| 707     DetachedSocket detached = _conn.detachSocket(); | 707     DetachedSocket detached = _conn.detachSocket(); | 
| 708     _socketConnected(detached.socket); | 708     _socketConnected(detached.socket); | 
| 709     if (_onOpen !== null) _onOpen(); | 709     if (_onOpen != null) _onOpen(); | 
| 710     _startProcessing(detached.unparsedData); | 710     _startProcessing(detached.unparsedData); | 
| 711   } | 711   } | 
| 712 | 712 | 
| 713   void _generateNonceAndHash() { | 713   void _generateNonceAndHash() { | 
| 714     Random random = new Random(); | 714     Random random = new Random(); | 
| 715     assert(_nonce == null); | 715     assert(_nonce == null); | 
| 716     void intToBigEndianBytes(int value, List<int> bytes, int offset) { | 716     void intToBigEndianBytes(int value, List<int> bytes, int offset) { | 
| 717       bytes[offset] = (value >> 24) & 0xFF; | 717       bytes[offset] = (value >> 24) & 0xFF; | 
| 718       bytes[offset + 1] = (value >> 16) & 0xFF; | 718       bytes[offset + 1] = (value >> 16) & 0xFF; | 
| 719       bytes[offset + 2] = (value >> 8) & 0xFF; | 719       bytes[offset + 2] = (value >> 8) & 0xFF; | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 788 | 788 | 
| 789     HttpClient client = new HttpClient(); | 789     HttpClient client = new HttpClient(); | 
| 790     HttpClientConnection conn = client.open("GET", uri.domain, port, path); | 790     HttpClientConnection conn = client.open("GET", uri.domain, port, path); | 
| 791     if (protocols is String) protocols = [protocols]; | 791     if (protocols is String) protocols = [protocols]; | 
| 792     _wsconn = new WebSocketClientConnection(conn, protocols); | 792     _wsconn = new WebSocketClientConnection(conn, protocols); | 
| 793     _wsconn.onOpen = () { | 793     _wsconn.onOpen = () { | 
| 794       // HTTP client not needed after socket have been detached. | 794       // HTTP client not needed after socket have been detached. | 
| 795       client.shutdown(); | 795       client.shutdown(); | 
| 796       client = null; | 796       client = null; | 
| 797       _readyState = WebSocket.OPEN; | 797       _readyState = WebSocket.OPEN; | 
| 798       if (_onopen !== null) _onopen(); | 798       if (_onopen != null) _onopen(); | 
| 799     }; | 799     }; | 
| 800     _wsconn.onMessage = (message) { | 800     _wsconn.onMessage = (message) { | 
| 801       if (_onmessage !== null) { | 801       if (_onmessage != null) { | 
| 802         _onmessage(new _WebSocketMessageEvent(message)); | 802         _onmessage(new _WebSocketMessageEvent(message)); | 
| 803       } | 803       } | 
| 804     }; | 804     }; | 
| 805     _wsconn.onClosed = (status, reason) { | 805     _wsconn.onClosed = (status, reason) { | 
| 806       _readyState = WebSocket.CLOSED; | 806       _readyState = WebSocket.CLOSED; | 
| 807       if (_onclose !== null) { | 807       if (_onclose != null) { | 
| 808         _onclose(new _WebSocketCloseEvent(true, status, reason)); | 808         _onclose(new _WebSocketCloseEvent(true, status, reason)); | 
| 809       } | 809       } | 
| 810     }; | 810     }; | 
| 811     _wsconn.onNoUpgrade = (response) { | 811     _wsconn.onNoUpgrade = (response) { | 
| 812       if (_onclose !== null) { | 812       if (_onclose != null) { | 
| 813         _onclose( | 813         _onclose( | 
| 814             new _WebSocketCloseEvent(true, | 814             new _WebSocketCloseEvent(true, | 
| 815                                      WebSocketStatus.ABNORMAL_CLOSURE, | 815                                      WebSocketStatus.ABNORMAL_CLOSURE, | 
| 816                                      "Connection not upgraded")); | 816                                      "Connection not upgraded")); | 
| 817       } | 817       } | 
| 818     }; | 818     }; | 
| 819   } | 819   } | 
| 820 | 820 | 
| 821   int get readyState => _readyState; | 821   int get readyState => _readyState; | 
| 822   int get bufferedAmount => 0; | 822   int get bufferedAmount => 0; | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 864 | 864 | 
| 865 class _WebSocketCloseEvent implements CloseEvent { | 865 class _WebSocketCloseEvent implements CloseEvent { | 
| 866   _WebSocketCloseEvent(this._wasClean, this._code, this._reason); | 866   _WebSocketCloseEvent(this._wasClean, this._code, this._reason); | 
| 867   bool get wasClean => _wasClean; | 867   bool get wasClean => _wasClean; | 
| 868   int get code => _code; | 868   int get code => _code; | 
| 869   String get reason => _reason; | 869   String get reason => _reason; | 
| 870   bool _wasClean; | 870   bool _wasClean; | 
| 871   int _code; | 871   int _code; | 
| 872   String _reason; | 872   String _reason; | 
| 873 } | 873 } | 
| OLD | NEW | 
|---|