Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: theturtle32/WebSocket-Node
...
head fork: GICodeWarrior/WebSocket-Node
compare: master
Checking mergeability… Don’t worry, you can still create the pull request.
  • 2 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Aug 11, 2012
@GICodeWarrior GICodeWarrior Implement deferred frame handling and a receive buffer limit.
If frame handling blocks the event loop longer than a given limit, defer the
next frame to the end of the event queue.  This reduces the opportunity for one
client to stall message handling for other clients.

Further, since frame handling is decoupled from the socket data event, a
receive buffer limit is included.  This limit indicates when the socket should
be pause()'ed, preventing the server from queuing many messages it isn't ready
to handle.
c6b6e6e
@GICodeWarrior GICodeWarrior Fork package.json for deploying directly from Github. dba5dba
View
19 lib/WebSocketClient.js
@@ -89,7 +89,22 @@ function WebSocketClient(config) {
// for an acknowledgement to come back before giving up and just
// closing the socket.
closeTimeout: 5000,
-
+
+ // Socket is pause()'ed if the receive buffer contains too much
+ // unprocessed data. This forces the client to back off if the server
+ // is slow. This is a soft limit (no way to set socket receive
+ // buffer), so a single socket data event may provide more than this
+ // limit.
+ // Default is 16KiB
+ receiveBufferSize: 0x4000,
+
+ // Message handling is deferred to the end of the event queue if it
+ // blocks for longer than this limit. This is a soft limit (no way to
+ // preempt), so handling a single message may block longer than this
+ // limit.
+ // Default is 1ms
+ messageBlockingTime: 1,
+
// Options to pass to https.connect if connecting via TLS
tlsOptions: {}
};
@@ -322,4 +337,4 @@ WebSocketClient.prototype.succeedHandshake = function() {
}
};
-module.exports = WebSocketClient;
+module.exports = WebSocketClient;
View
60 lib/WebSocketConnection.js
@@ -34,6 +34,7 @@ function WebSocketConnection(socket, extensions, protocol, maskOutgoingPackets,
this.remoteAddress = socket.remoteAddress;
this.closeReasonCode = -1;
this.closeDescription = null;
+ this.assemblingFrames = false;
// We have to mask outgoing packets if we're acting as a WebSocket client.
this.maskOutgoingPackets = maskOutgoingPackets;
@@ -202,18 +203,33 @@ WebSocketConnection.prototype.handleGracePeriodTimer = function() {
};
WebSocketConnection.prototype.handleSocketData = function(data) {
- // Reset the keepalive timer when receiving data of any kind.
- this.setKeepaliveTimer();
-
// Add received data to our bufferList, which efficiently holds received
// data chunks in a linked list of Buffer objects.
this.bufferList.write(data);
-
- // currentFrame.addData returns true if all data necessary to parse
- // the frame was available. It returns false if we are waiting for
- // more data to come in on the wire.
- while (this.connected && this.currentFrame.addData(this.bufferList)) {
-
+
+ if (!this.assemblingFrames) {
+ this.assembleFrames();
+ }
+};
+
+WebSocketConnection.prototype.assembleFrames = function() {
+ // Reset the keepalive timer when receiving data of any kind.
+ this.setKeepaliveTimer();
+
+ var count = 0;
+
+ var assemblyStarted = Date.now();
+ do {
+ // currentFrame.addData returns true if all data necessary to parse
+ // the frame was available. It returns false if we are waiting for
+ // more data to come in on the wire.
+ if (!this.connected || !this.currentFrame.addData(this.bufferList)) {
+ this.assemblingFrames = false;
+ break;
+ }
+ this.assemblingFrames = true;
+ ++count;
+
// Handle possible parsing errors
if (this.currentFrame.protocolError) {
// Something bad happened.. get rid of this client.
@@ -224,18 +240,36 @@ WebSocketConnection.prototype.handleSocketData = function(data) {
this.drop(WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG, this.currentFrame.dropReason);
return;
}
-
- // For now since we don't support extensions, all RSV bits are illegal
+
+ // For now since we don't support extensions, all RSV bits are
+ // illegal.
if (this.currentFrame.rsv1 || this.currentFrame.rsv2 || this.currentFrame.rsv3) {
this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
"Unsupported usage of rsv bits without negotiated extension.");
}
-
+
if (!this.assembleFragments) {
this.emit('frame', this.currentFrame);
}
this.processFrame(this.currentFrame);
this.currentFrame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ } while (Date.now() - assemblyStarted < this.config.messageBlockingTime);
+
+ if (this.assemblingFrames) {
+ if (this.bufferList.length > this.config.receiveBufferSize) {
+ this.socket.pause();
+ }
+ else {
+ this.socket.resume();
+ }
+
+ // Blocking time limit was exceeded. Handle the next frame after other
+ // clients have a chance to run.
+ setTimeout(this.assembleFrames.bind(this), 0);
+ }
+ else {
+ // Always resume the socket if we don't have a full frame.
+ this.socket.resume();
}
};
@@ -704,4 +738,4 @@ WebSocketConnection.prototype.processOutgoingFrameQueue = function() {
}
};
-module.exports = WebSocketConnection;
+module.exports = WebSocketConnection;
View
19 lib/WebSocketServer.js
@@ -102,7 +102,22 @@ WebSocketServer.prototype.mount = function(config) {
// The number of milliseconds to wait after sending a close frame
// for an acknowledgement to come back before giving up and just
// closing the socket.
- closeTimeout: 5000
+ closeTimeout: 5000,
+
+ // Socket is pause()'ed if the receive buffer contains too much
+ // unprocessed data. This forces the client to back off if the server
+ // is slow. This is a soft limit (no way to set socket receive
+ // buffer), so a single socket data event may provide more than this
+ // limit.
+ // Default is 16KiB
+ receiveBufferSize: 0x4000,
+
+ // Message handling is deferred to the end of the event queue if it
+ // blocks for longer than this limit. This is a soft limit (no way to
+ // preempt), so handling a single message may block longer than this
+ // limit.
+ // Default is 1ms
+ messageBlockingTime: 1
};
extend(this.config, config);
@@ -203,4 +218,4 @@ WebSocketServer.prototype.handleConnectionClose = function(connection, closeReas
this.emit('close', connection, closeReason, description);
};
-module.exports = WebSocketServer;
+module.exports = WebSocketServer;
View
8 package.json
@@ -3,10 +3,14 @@
"description": "Websocket Client & Server Library implementing the WebSocket protocol as specified in RFC 6455.",
"keywords": ["websocket", "socket", "networking", "comet", "push"],
"author": "Brian McKelvey <brian@worlize.com>",
+ "contributors": [
+ { "name": "Brian McKelvey", "email": "brian@worlize.com" },
+ { "name": "Rusty Burchfield", "email": "GICodeWarrior@gmail.com" }
+ ],
"version": "1.0.6",
"repository": {
"type": "git",
- "url": "https://theturtle32@github.com/Worlize/WebSocket-Node.git"
+ "url": "https://github.com/GICodeWarrior/WebSocket-Node.git"
},
"engines": {
"node": ">=0.6.13"
@@ -15,4 +19,4 @@
"directories": {
"lib": "./lib"
}
-}
+}

No commit comments for this range

Something went wrong with that request. Please try again.