11 Commits

14 changed files with 5958 additions and 44 deletions
+1
View File
@@ -2,5 +2,6 @@
.gitignore
.npmignore
.travis.yml
examples
node_modules
spec
+6 -5
View File
@@ -1,11 +1,12 @@
sudo: false
language: node_js
node_js:
- "0.6"
- "0.8"
- "0.10"
- "0.12"
- "iojs"
before_install:
- '[ "${TRAVIS_NODE_VERSION}" = "0.6" ] && npm conf set strict-ssl false || true'
- "iojs-1"
- "iojs-2"
- "iojs-3"
- "4"
- "5"
+14
View File
@@ -1,3 +1,17 @@
### 0.1.5 / 2016-02-24
* Catch errors thrown by `close()` on zlib streams
### 0.1.4 / 2015-11-06
* The server does not send `server_max_window_bits` if the client does not ask
for it; this works around an issue in Firefox.
### 0.1.3 / 2015-04-10
* Fix a race condition causing some fragments of deflate output to be dropped
* Make sure to emit minimal output on all Node versions
### 0.1.2 / 2014-12-18
* Don't allow configure() to be called with unrecognized options
+4
View File
@@ -0,0 +1,4 @@
# Code of Conduct
All projects under the [Faye](https://github.com/faye) umbrella are covered by
the [Code of Conduct](https://github.com/faye/code-of-conduct).
+1 -1
View File
@@ -72,7 +72,7 @@ can be used to set the local session's behaviour and control that of the peer:
(The MIT License)
Copyright (c) 2014-2015 James Coglan
Copyright (c) 2014-2016 James Coglan
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the 'Software'), to deal in
+5809
View File
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
var fs = require('fs'),
deflate = require('..');
var records = fs.readFileSync(__dirname + '/bad.out.log', 'utf8')
.replace(/\s*$/g, '')
.split(/\n/)
.map(JSON.parse);
var client = deflate.createClientSession(),
offer = client.generateOffer(),
server = deflate.createServerSession([offer]),
response = server.generateResponse(),
compressed = [],
size = [0, 0];
client.activate(response);
function compress(index) {
var record = records[index];
if (!record) {
console.log(size, size[0] / size[1]);
return decompress(0);
}
var message = {data: new Buffer(record[3], 'base64')};
size[0] += message.data.length;
server.processOutgoingMessage(message, function(error, message) {
compressed[index] = message;
size[1] += message.data.length;
compress(index + 1);
});
}
function decompress(index) {
var record = records[index];
if (!record) return;
var payload = record[3],
message = compressed[index];
client.processIncomingMessage(message, function(error, message) {
var output = message.data.toString('base64');
if (output !== payload) {
console.error('Failed on', record, message);
process.exit(1);
}
decompress(index + 1);
});
}
compress(0);
+3 -3
View File
@@ -64,12 +64,12 @@ ClientSession.prototype.activate = function(params) {
this._ownContextTakeover = !(this._acceptNoContextTakeover || params.client_no_context_takeover);
this._ownWindowBits = Math.min(
this._acceptMaxWindowBits || common.DEFAULT_MAX_WINDOW_BITS,
params.client_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS
this._acceptMaxWindowBits || common.MAX_WINDOW_BITS,
params.client_max_window_bits || common.MAX_WINDOW_BITS
);
this._peerContextTakeover = !params.server_no_context_takeover;
this._peerWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
this._peerWindowBits = params.server_max_window_bits || common.MAX_WINDOW_BITS;
return true;
};
+1 -1
View File
@@ -8,7 +8,7 @@ var common = {
'client_max_window_bits'
],
DEFAULT_MAX_WINDOW_BITS: 15,
MAX_WINDOW_BITS: 15,
VALID_WINDOW_BITS: [8, 9, 10, 11, 12, 13, 14, 15],
concat: function(buffers, length) {
+27 -23
View File
@@ -21,42 +21,46 @@ ServerSession.validParams = function(params) {
};
ServerSession.prototype.generateResponse = function() {
var params = {};
var response = {};
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.1
if (this._acceptNoContextTakeover || this._params.server_no_context_takeover)
params.server_no_context_takeover = true;
this._ownContextTakeover = !this._acceptNoContextTakeover &&
!this._params.server_no_context_takeover;
if (!this._ownContextTakeover) response.server_no_context_takeover = true;
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.2
if (this._requestNoContextTakeover || this._params.client_no_context_takeover)
params.client_no_context_takeover = true;
this._peerContextTakeover = !this._requestNoContextTakeover &&
!this._params.client_no_context_takeover;
if (!this._peerContextTakeover) response.client_no_context_takeover = true;
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.1
var acceptMax, serverMax;
if (this._acceptMaxWindowBits || this._params.server_max_window_bits) {
acceptMax = this._acceptMaxWindowBits || common.DEFAULT_MAX_WINDOW_BITS;
serverMax = this._params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
params.server_max_window_bits = Math.min(acceptMax, serverMax);
}
this._ownWindowBits = Math.min(this._acceptMaxWindowBits || common.MAX_WINDOW_BITS,
this._params.server_max_window_bits || common.MAX_WINDOW_BITS);
// In violation of the spec, Firefox closes the connection if it does not
// send server_max_window_bits but the server includes this in its response
if (this._ownWindowBits < common.MAX_WINDOW_BITS && this._params.server_max_window_bits)
response.server_max_window_bits = this._ownWindowBits;
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.2
var clientMax = this._params.client_max_window_bits, requestMax;
if (clientMax) {
if (clientMax === true) {
if (this._requestMaxWindowBits) params.client_max_window_bits = this._requestMaxWindowBits;
} else {
requestMax = this._requestMaxWindowBits || common.DEFAULT_MAX_WINDOW_BITS;
params.client_max_window_bits = Math.min(requestMax, clientMax);
}
if (clientMax === true) clientMax = common.MAX_WINDOW_BITS;
this._peerWindowBits = Math.min(this._requestMaxWindowBits || common.MAX_WINDOW_BITS, clientMax);
} else {
this._peerWindowBits = common.MAX_WINDOW_BITS;
}
this._ownContextTakeover = !params.server_no_context_takeover;
this._ownWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
if (this._peerWindowBits < common.MAX_WINDOW_BITS)
response.client_max_window_bits = this._peerWindowBits;
this._peerContextTakeover = !params.client_no_context_takeover;
this._peerWindowBits = params.client_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
return params;
return response;
};
module.exports = ServerSession;
+9 -4
View File
@@ -33,7 +33,7 @@ Session.prototype.processIncomingMessage = function(message, callback) {
inflate.removeListener('data', onData);
inflate.removeListener('error', onError);
if (!self._inflate && inflate.close) inflate.close();
if (!self._inflate) self._close(inflate);
self._lockIn = false;
var next = self._queueIn.shift();
@@ -78,7 +78,7 @@ Session.prototype.processOutgoingMessage = function(message, callback) {
deflate.removeListener('data', onData);
deflate.removeListener('error', onError);
if (!self._deflate && deflate.close) deflate.close();
if (!self._deflate) self._close(deflate);
self._lockOut = false;
var next = self._queueOut.shift();
@@ -114,10 +114,10 @@ Session.prototype.processOutgoingMessage = function(message, callback) {
};
Session.prototype.close = function() {
if (this._inflate && this._inflate.close) this._inflate.close();
this._close(this._inflate);
this._inflate = null;
if (this._deflate && this._deflate.close) this._deflate.close();
this._close(this._deflate);
this._deflate = null;
};
@@ -159,4 +159,9 @@ Session.prototype._getDeflate = function() {
return deflate;
};
Session.prototype._close = function(codec) {
if (!codec || !codec.close) return;
try { codec.close() } catch (error) {}
};
module.exports = Session;
+4 -4
View File
@@ -1,12 +1,12 @@
{ "name" : "permessage-deflate"
, "description" : "Per-message DEFLATE compression extension for WebSocket connections"
, "homepage" : "http://github.com/faye/permessage-deflate-node"
, "homepage" : "https://github.com/faye/permessage-deflate-node"
, "author" : "James Coglan <jcoglan@gmail.com> (http://jcoglan.com/)"
, "keywords" : ["websocket", "compression", "deflate"]
, "license" : "MIT"
, "version" : "0.1.2"
, "engines" : {"node": ">=0.6.0"}
, "version" : "0.1.5"
, "engines" : {"node": ">=0.8.0"}
, "main" : "./lib/permessage_deflate"
, "devDependencies" : {"jstest": ""}
@@ -16,5 +16,5 @@
, "url" : "git://github.com/faye/permessage-deflate-node.git"
}
, "bugs" : "http://github.com/faye/permessage-deflate-node/issues"
, "bugs" : "https://github.com/faye/permessage-deflate-node/issues"
}
+12
View File
@@ -90,6 +90,12 @@ test.describe("ClientSession", function() { with(this) {
processIncomingMessage()
processIncomingMessage()
}})
it("catches errors thrown by zlib", function() { with(this) {
activate()
stub(zlib, "createInflateRaw").returning(inflate)
assertNothingThrown(function() { processIncomingMessage() })
}})
}})
describe("when the response includes client_no_context_takeover", function() { with(this) {
@@ -106,6 +112,12 @@ test.describe("ClientSession", function() { with(this) {
processOutgoingMessage()
processOutgoingMessage()
}})
it("catches errors thrown by zlib", function() { with(this) {
activate()
stub(zlib, "createDeflateRaw").returning(deflate)
assertNothingThrown(function() { processOutgoingMessage() })
}})
}})
describe("when the response includes server_max_window_bits", function() { with(this) {
+15 -3
View File
@@ -2,7 +2,7 @@ var PermessageDeflate = require('../lib/permessage_deflate'),
zlib = require('zlib'),
test = require('jstest').Test
test.describe("ClientSession", function() { with(this) {
test.describe("ServerSession", function() { with(this) {
before(function() { with(this) {
this.ext = PermessageDeflate.configure(options)
this.session = ext.createServerSession([offer])
@@ -81,6 +81,12 @@ test.describe("ClientSession", function() { with(this) {
processOutgoingMessage()
processOutgoingMessage()
}})
it("catches errors thrown by zlib", function() { with(this) {
response()
stub(zlib, "createDeflateRaw").returning(deflate)
assertNothingThrown(function() { processOutgoingMessage() })
}})
}})
describe("when the offer includes client_no_context_takeover", function() { with(this) {
@@ -97,6 +103,12 @@ test.describe("ClientSession", function() { with(this) {
processIncomingMessage()
processIncomingMessage()
}})
it("catches errors thrown by zlib", function() { with(this) {
response()
stub(zlib, "createInflateRaw").returning(inflate)
assertNothingThrown(function() { processIncomingMessage() })
}})
}})
describe("when the offer includes server_max_window_bits", function() { with(this) {
@@ -183,8 +195,8 @@ test.describe("ClientSession", function() { with(this) {
define("options", {maxWindowBits: 12})
describe("with an empty offer", function() { with(this) {
it("includes server_max_window_bits in the response", function() { with(this) {
assertEqual( {server_max_window_bits: 12}, response() )
it("does not include server_max_window_bits in the response", function() { with(this) {
assertEqual( {}, response() )
}})
it("uses context takeover and 12 window bits for deflating outgoing messages", function() { with(this) {