Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Unified Diff: runtime/bin/websocket_impl.dart

Issue 10392195: Add support for websocket PING and PONG frames (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/websocket_impl.dart
diff --git a/runtime/bin/websocket_impl.dart b/runtime/bin/websocket_impl.dart
index df4834c38860e5dd9263e5a2fb3288ddf685308e..b3482e249e36c66207136c1faa981f92dfb7750d 100644
--- a/runtime/bin/websocket_impl.dart
+++ b/runtime/bin/websocket_impl.dart
@@ -8,7 +8,6 @@ class _WebSocketMessageType {
static final int NONE = 0;
static final int BINARY = 1;
static final int TEXT = 2;
- static final int CLOSE = 3;
}
@@ -54,7 +53,7 @@ class _WebSocketProtocolProcessor {
static final int FAILURE = 6;
_WebSocketProtocolProcessor() {
- _reset();
+ _prepareForNextFrame();
_currentMessageType = _WebSocketMessageType.NONE;
}
@@ -105,20 +104,10 @@ class _WebSocketProtocolProcessor {
break;
case _WebSocketOpcode.CLOSE:
- if (_currentMessageType != _WebSocketMessageType.NONE) {
- throw new WebSocketException("Protocol error");
- }
- _currentMessageType = _WebSocketMessageType.CLOSE;
- break;
-
case _WebSocketOpcode.PING:
- // TODO(sgjesse): Handle ping.
- throw new UnsupportedOperationException("Web socket PING");
- break;
-
case _WebSocketOpcode.PONG:
- // TODO(sgjesse): Handle pong.
- throw new UnsupportedOperationException("Web socket PONG");
+ // Control frames cannot be fragmented.
+ if (!_fin) throw new WebSocketException("Protocol error");
break;
default:
@@ -131,6 +120,9 @@ class _WebSocketProtocolProcessor {
case LEN_FIRST:
_masked = (byte & 0x80) != 0;
_len = byte & 0x7F;
+ if (_isControlFrame() && _len > 126) {
+ throw new WebSocketException("Protocol error");
+ }
if (_len < 126) {
_lengthDone();
} else if (_len == 126) {
@@ -168,6 +160,8 @@ class _WebSocketProtocolProcessor {
} else {
payload = _remainingPayloadBytes;
}
+ _remainingPayloadBytes -= payload;
+
// Unmask payload if masked.
if (_masked) {
for (int i = 0; i < payload; i++) {
@@ -178,67 +172,46 @@ class _WebSocketProtocolProcessor {
}
}
- switch (_currentMessageType) {
- case _WebSocketMessageType.NONE:
- throw new WebSocketException("Protocol error");
- break;
-
- case _WebSocketMessageType.TEXT:
- case _WebSocketMessageType.BINARY:
- if (onMessageData != null) {
- onMessageData(buffer, index, payload);
+ if (_isControlFrame()) {
+ if (payload > 0) {
+ // Allocate a buffer for collecting the control frame
+ // payload if any.
+ if (_controlPayload == null) {
+ _controlPayload = new List<int>();
}
- _remainingPayloadBytes -= payload;
+ _controlPayload.addAll(buffer.getRange(index, payload));
index += payload;
- if (_remainingPayloadBytes == 0) {
- _frameEnd();
- }
- break;
+ }
- case _WebSocketMessageType.CLOSE:
- // Allocate a buffer for holding the close payload if any.
- if (_closePayload == null) {
- _closePayload = new List<int>();
- }
- _closePayload.addAll(buffer.getRange(index, payload));
- _remainingPayloadBytes -= payload;
- index += payload;
- if (_fin) {
- if (_remainingPayloadBytes != 0) {
- throw new WebSocketException("Protocol error");
+ if (_remainingPayloadBytes == 0) {
+ _controlFrameEnd();
+ }
+ } else {
+ switch (_currentMessageType) {
+ case _WebSocketMessageType.NONE:
+ throw new WebSocketException("Protocol error");
+ break;
+
+ case _WebSocketMessageType.TEXT:
+ case _WebSocketMessageType.BINARY:
+ if (onMessageData != null) {
+ onMessageData(buffer, index, payload);
}
- int status;
- String reason;
- if (_closePayload.length > 0) {
- if (_closePayload.length == 1) {
- throw new WebSocketException("Protocol error");
- }
- status = _closePayload[0] << 8 | _closePayload[1];
- if (_closePayload.length > 2) {
- var decoder = _StringDecoders.decoder(Encoding.UTF_8);
- decoder.write(_closePayload.getRange(
- 2, _closePayload.length - 2));
- reason = decoder.decoded;
- }
+ index += payload;
+ if (_remainingPayloadBytes == 0) {
+ _messageFrameEnd();
}
- if (onClosed != null) onClosed(status, reason);
- _currentMessageType = _WebSocketMessageType.NONE;
- _state = CLOSED;
- }
- break;
+ break;
- default:
- throw new WebSocketException("Protocol error");
- break;
+ default:
+ throw new WebSocketException("Protocol error");
+ break;
+
+ }
}
// Hack - as we always do index++ below.
index--;
- break;
-
- default:
- throw new WebSocketException("Protocol error");
- break;
}
// Move to the next byte.
@@ -274,33 +247,79 @@ class _WebSocketProtocolProcessor {
}
void _startPayload() {
- // Check whether there is any payload. If not indicate empty
- // message or close without state and reason.
+ // If there is no actual payload perform perform callbacks without
+ // going through the PAYLOAD state.
if (_remainingPayloadBytes == 0) {
- if (_currentMessageType ==_WebSocketMessageType.CLOSE) {
- if (onClosed != null) onClosed(null, null);
- _state = CLOSED;
+ if (_isControlFrame()) {
+ switch (_opcode) {
+ case _WebSocketOpcode.CLOSE:
+ if (onClosed != null) onClosed(null, null);
+ _state = CLOSED;
+ break;
+ case _WebSocketOpcode.PING:
+ if (onPing != null) onPing(null);
+ break;
+ case _WebSocketOpcode.PONG:
+ if (onPong != null) onPong(null);
+ break;
+ }
+ _prepareForNextFrame();
} else {
- _frameEnd();
+ _messageFrameEnd();
}
} else {
_state = PAYLOAD;
}
}
- void _frameEnd() {
- if (_remainingPayloadBytes != 0) {
- throw new WebSocketException("Protocol error");
- }
+ void _messageFrameEnd() {
if (_fin) {
if (onMessageEnd != null) onMessageEnd();
_currentMessageType = _WebSocketMessageType.NONE;
}
- _reset();
+ _prepareForNextFrame();
}
- void _reset() {
- _state = START;
+ void _controlFrameEnd() {
+ switch (_opcode) {
+ case _WebSocketOpcode.CLOSE:
+ int status;
+ String reason;
+ if (_controlPayload.length > 0) {
+ if (_controlPayload.length == 1) {
+ throw new WebSocketException("Protocol error");
+ }
+ status = _controlPayload[0] << 8 | _controlPayload[1];
+ if (_controlPayload.length > 2) {
+ var decoder = _StringDecoders.decoder(Encoding.UTF_8);
+ decoder.write(
+ _controlPayload.getRange(2, _controlPayload.length - 2));
+ reason = decoder.decoded;
+ }
+ }
+ if (onClosed != null) onClosed(status, reason);
+ _state = CLOSED;
+ break;
+
+ case _WebSocketOpcode.PING:
+ if (onPing != null) onPing(_controlPayload);
+ break;
+
+ case _WebSocketOpcode.PONG:
+ if (onPong != null) onPong(_controlPayload);
+ break;
+ }
+ _prepareForNextFrame();
+ }
+
+ bool _isControlFrame() {
+ return _opcode == _WebSocketOpcode.CLOSE ||
+ _opcode == _WebSocketOpcode.PING ||
+ _opcode == _WebSocketOpcode.PONG;
+ }
+
+ void _prepareForNextFrame() {
+ if (_state != CLOSED && _state != FAILURE) _state = START;
_fin = null;
_opcode = null;
_len = null;
@@ -310,6 +329,7 @@ class _WebSocketProtocolProcessor {
_remainingMaskingKeyBytes = null;
_remainingPayloadBytes = null;
_unmaskingIndex = 0;
+ _controlPayload = null;
}
void _reportError(e) {
@@ -335,11 +355,13 @@ class _WebSocketProtocolProcessor {
int _unmaskingIndex;
int _currentMessageType;
- List<int> _closePayload;
+ List<int> _controlPayload;
Function onMessageStart;
Function onMessageData;
Function onMessageEnd;
+ Function onPing;
+ Function onPong;
Function onClosed;
Function onError;
}
@@ -359,6 +381,8 @@ class _WebSocketConnectionBase {
processor.onMessageStart = _onWebSocketMessageStart;
processor.onMessageData = _onWebSocketMessageData;
processor.onMessageEnd = _onWebSocketMessageEnd;
+ processor.onPing = _onWebSocketPing;
+ processor.onPong = _onWebSocketPong;
processor.onClosed = _onWebSocketClosed;
processor.onError = _onWebSocketError;
if (unparsedData != null) {
@@ -486,6 +510,14 @@ class _WebSocketConnectionBase {
_outputStream = null;
}
+ _onWebSocketPing(List<int> payload) {
+ _sendFrame(_WebSocketOpcode.PONG, payload);
+ }
+
+ _onWebSocketPong(List<int> payload) {
+ // Currently pong messages are ignored.
+ }
+
_onWebSocketClosed(int status, String reason) {
_closeReceived = true;
if (_onClosed != null) _onClosed(status, reason);
@@ -503,7 +535,7 @@ class _WebSocketConnectionBase {
_socket.close();
}
- _sendFrame(int opcode, List<int> data) {
+ _sendFrame(int opcode, [List<int> data]) {
bool mask = false; // Masking not implemented for server.
int dataLength = data == null ? 0 : data.length;
// Determine the header size.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698