Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c7b9a9e21 | |||
| 0de9386f81 | |||
| ef6a4a2ecc | |||
| 47b3b3614b | |||
| 5da6a768b0 | |||
| f03aef1954 | |||
| adebc51630 | |||
| 958de927aa | |||
| 037afc350c | |||
| 10b5d6be57 | |||
| f48eaac6d3 | |||
| a71a06180a |
@@ -1 +1,2 @@
|
||||
lib
|
||||
node_modules
|
||||
|
||||
+5
-3
@@ -1,10 +1,12 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.6"
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
- "0.12"
|
||||
- "iojs"
|
||||
|
||||
before_install:
|
||||
- '[ "${TRAVIS_NODE_VERSION}" = "0.6" ] && npm conf set strict-ssl false || true'
|
||||
- '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@~1.4.0'
|
||||
|
||||
script: make test
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
### 0.1.2 / 2014-12-18
|
||||
|
||||
* Don't allow configure() to be called with unrecognized options
|
||||
|
||||
### 0.1.1 / 2014-12-15
|
||||
|
||||
* Fix race condition when using context takeover, where adjacent messages have
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
SHELL := /bin/bash
|
||||
PATH := node_modules/.bin:$(PATH)
|
||||
|
||||
source_files := $(shell find src -name '*.js')
|
||||
target_files := $(source_files:src/%.js=lib/%.js)
|
||||
|
||||
.PHONY: all clean test
|
||||
|
||||
all: $(target_files)
|
||||
|
||||
lib/%.js: src/%.js
|
||||
mkdir -p $(dir $@)
|
||||
babel $< --out-file $@ --source-maps true
|
||||
|
||||
clean:
|
||||
rm -rf lib
|
||||
|
||||
test: all
|
||||
jstest spec/runner.js
|
||||
@@ -72,22 +72,21 @@ can be used to set the local session's behaviour and control that of the peer:
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 James Coglan
|
||||
Copyright (c) 2014-2015 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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util'),
|
||||
common = require('./common'),
|
||||
Session = require('./session');
|
||||
|
||||
var ClientSession = function(options) {
|
||||
Session.call(this, options);
|
||||
};
|
||||
util.inherits(ClientSession, Session);
|
||||
|
||||
ClientSession.validParams = function(params) {
|
||||
if (!common.validParams(params)) return false;
|
||||
|
||||
if (params.hasOwnProperty('client_max_window_bits')) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(params.client_max_window_bits) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
ClientSession.prototype.generateOffer = function() {
|
||||
var offer = {};
|
||||
|
||||
if (this._acceptNoContextTakeover)
|
||||
offer.client_no_context_takeover = true;
|
||||
|
||||
if (this._acceptMaxWindowBits !== undefined) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(this._acceptMaxWindowBits) < 0) {
|
||||
throw new Error('Invalid value for maxWindowBits');
|
||||
}
|
||||
offer.client_max_window_bits = this._acceptMaxWindowBits;
|
||||
} else {
|
||||
offer.client_max_window_bits = true;
|
||||
}
|
||||
|
||||
if (this._requestNoContextTakeover)
|
||||
offer.server_no_context_takeover = true;
|
||||
|
||||
if (this._requestMaxWindowBits !== undefined) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(this._requestMaxWindowBits) < 0) {
|
||||
throw new Error('Invalid valud for requestMaxWindowBits');
|
||||
}
|
||||
offer.server_max_window_bits = this._requestMaxWindowBits;
|
||||
}
|
||||
|
||||
return offer;
|
||||
};
|
||||
|
||||
ClientSession.prototype.activate = function(params) {
|
||||
if (!ClientSession.validParams(params)) return false;
|
||||
|
||||
if (this._acceptMaxWindowBits && params.client_max_window_bits) {
|
||||
if (params.client_max_window_bits > this._acceptMaxWindowBits) return false;
|
||||
}
|
||||
|
||||
if (this._requestNoContextTakeover && !params.server_no_context_takeover)
|
||||
return false;
|
||||
|
||||
if (this._requestMaxWindowBits) {
|
||||
if (!params.server_max_window_bits) return false;
|
||||
if (params.server_max_window_bits > this._requestMaxWindowBits) return false;
|
||||
}
|
||||
|
||||
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._peerContextTakeover = !params.server_no_context_takeover;
|
||||
this._peerWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = ClientSession;
|
||||
@@ -1,51 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var common = {
|
||||
VALID_PARAMS: [
|
||||
'server_no_context_takeover',
|
||||
'client_no_context_takeover',
|
||||
'server_max_window_bits',
|
||||
'client_max_window_bits'
|
||||
],
|
||||
|
||||
DEFAULT_MAX_WINDOW_BITS: 15,
|
||||
VALID_WINDOW_BITS: [8, 9, 10, 11, 12, 13, 14, 15],
|
||||
|
||||
concat: function(buffers, length) {
|
||||
var buffer = new Buffer(length),
|
||||
offset = 0;
|
||||
|
||||
for (var i = 0, n = buffers.length; i < n; i++) {
|
||||
buffers[i].copy(buffer, offset);
|
||||
offset += buffers[i].length;
|
||||
}
|
||||
return buffer;
|
||||
},
|
||||
|
||||
fetch: function(options, key, _default) {
|
||||
if (options.hasOwnProperty(key))
|
||||
return options[key];
|
||||
else
|
||||
return _default;
|
||||
},
|
||||
|
||||
validParams: function(params) {
|
||||
var keys = Object.keys(params), i = keys.length;
|
||||
while (i--) {
|
||||
if (this.VALID_PARAMS.indexOf(keys[i]) < 0) return false;
|
||||
if (params[keys[i]] instanceof Array) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('server_no_context_takeover')) {
|
||||
if (params.server_no_context_takeover !== true) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('client_no_context_takeover')) {
|
||||
if (params.client_no_context_takeover !== true) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('server_max_window_bits')) {
|
||||
if (this.VALID_WINDOW_BITS.indexOf(params.server_max_window_bits) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = common;
|
||||
@@ -1,32 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var ClientSession = require('./client_session'),
|
||||
ServerSession = require('./server_session');
|
||||
|
||||
var PermessageDeflate = {
|
||||
configure: function(options) {
|
||||
var opts = this._options || {};
|
||||
for (var key in opts) options[key] = opts[key];
|
||||
return Object.create(this, {_options: {value: options}});
|
||||
},
|
||||
|
||||
createClientSession: function() {
|
||||
return new ClientSession(this._options || {});
|
||||
},
|
||||
|
||||
createServerSession: function(offers) {
|
||||
for (var i = 0, n = offers.length; i < n; i++) {
|
||||
if (ServerSession.validParams(offers[i]))
|
||||
return new ServerSession(this._options || {}, offers[i]);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
name: 'permessage-deflate',
|
||||
type: 'permessage',
|
||||
rsv1: true,
|
||||
rsv2: false,
|
||||
rsv3: false
|
||||
};
|
||||
|
||||
module.exports = PermessageDeflate;
|
||||
@@ -1,62 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util'),
|
||||
common = require('./common'),
|
||||
Session = require('./session');
|
||||
|
||||
var ServerSession = function(options, params) {
|
||||
Session.call(this, options);
|
||||
this._params = params;
|
||||
};
|
||||
util.inherits(ServerSession, Session);
|
||||
|
||||
ServerSession.validParams = function(params) {
|
||||
if (!common.validParams(params)) return false;
|
||||
|
||||
if (params.hasOwnProperty('client_max_window_bits')) {
|
||||
if ([true].concat(common.VALID_WINDOW_BITS).indexOf(params.client_max_window_bits) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
ServerSession.prototype.generateResponse = function() {
|
||||
var params = {};
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
this._ownContextTakeover = !params.server_no_context_takeover;
|
||||
this._ownWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
this._peerContextTakeover = !params.client_no_context_takeover;
|
||||
this._peerWindowBits = params.client_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
module.exports = ServerSession;
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var zlib = require('zlib'),
|
||||
common = require('./common');
|
||||
|
||||
var VERSION = process.version.match(/\d+/g).map(function(n) { return parseInt(n, 10) });
|
||||
|
||||
var Session = function(options) {
|
||||
this._level = common.fetch(options, 'level', zlib.Z_DEFAULT_LEVEL);
|
||||
this._memLevel = common.fetch(options, 'memLevel', zlib.Z_DEFAULT_MEMLEVEL);
|
||||
this._strategy = common.fetch(options, 'strategy', zlib.Z_DEFAULT_STRATEGY);
|
||||
|
||||
this._acceptNoContextTakeover = common.fetch(options, 'noContextTakeover', false);
|
||||
this._acceptMaxWindowBits = common.fetch(options, 'maxWindowBits', undefined);
|
||||
this._requestNoContextTakeover = common.fetch(options, 'requestNoContextTakeover', false);
|
||||
this._requestMaxWindowBits = common.fetch(options, 'requestMaxWindowBits', undefined);
|
||||
|
||||
this._queueIn = [];
|
||||
this._queueOut = [];
|
||||
};
|
||||
|
||||
Session.prototype.processIncomingMessage = function(message, callback) {
|
||||
if (!message.rsv1) return callback(null, message);
|
||||
if (this._lockIn) return this._queueIn.push([message, callback]);
|
||||
|
||||
var inflate = this._getInflate(),
|
||||
chunks = [],
|
||||
length = 0,
|
||||
self = this;
|
||||
|
||||
if (this._inflate) this._lockIn = true;
|
||||
|
||||
var return_ = function(error, message) {
|
||||
return_ = function() {};
|
||||
|
||||
inflate.removeListener('data', onData);
|
||||
inflate.removeListener('error', onError);
|
||||
if (!self._inflate && inflate.close) inflate.close();
|
||||
|
||||
self._lockIn = false;
|
||||
var next = self._queueIn.shift();
|
||||
if (next) self.processIncomingMessage.apply(self, next);
|
||||
|
||||
callback(error, message);
|
||||
};
|
||||
|
||||
var onData = function(data) {
|
||||
chunks.push(data);
|
||||
length += data.length;
|
||||
};
|
||||
|
||||
var onError = function(error) {
|
||||
return_(error, null);
|
||||
};
|
||||
|
||||
inflate.on('data', onData);
|
||||
inflate.on('error', onError);
|
||||
|
||||
inflate.write(message.data);
|
||||
inflate.write(new Buffer([0x00, 0x00, 0xff, 0xff]));
|
||||
|
||||
inflate.flush(function() {
|
||||
message.data = common.concat(chunks, length);
|
||||
return_(null, message);
|
||||
});
|
||||
};
|
||||
|
||||
Session.prototype.processOutgoingMessage = function(message, callback) {
|
||||
if (this._lockOut) return this._queueOut.push([message, callback]);
|
||||
|
||||
var deflate = this._getDeflate(),
|
||||
chunks = [],
|
||||
length = 0,
|
||||
self = this;
|
||||
|
||||
if (this._deflate) this._lockOut = true;
|
||||
|
||||
var return_ = function(error, message) {
|
||||
return_ = function() {};
|
||||
|
||||
deflate.removeListener('data', onData);
|
||||
deflate.removeListener('error', onError);
|
||||
if (!self._deflate && deflate.close) deflate.close();
|
||||
|
||||
self._lockOut = false;
|
||||
var next = self._queueOut.shift();
|
||||
if (next) self.processOutgoingMessage.apply(self, next);
|
||||
|
||||
callback(error, message);
|
||||
};
|
||||
|
||||
var onData = function(data) {
|
||||
var tail = data.slice(Math.max(data.length - 4, 0), data.length),
|
||||
isEnd = (tail[0] === 0x00 && tail[1] === 0x00 && tail[2] === 0xff && tail[3] === 0xff);
|
||||
|
||||
if (isEnd) data = data.slice(0, data.length - 4);
|
||||
|
||||
chunks.push(data);
|
||||
length += data.length;
|
||||
|
||||
if (isEnd) {
|
||||
message.rsv1 = true;
|
||||
message.data = common.concat(chunks, length);
|
||||
return_(null, message);
|
||||
}
|
||||
};
|
||||
|
||||
var onError = function(error) {
|
||||
return_(error, null);
|
||||
};
|
||||
|
||||
deflate.on('data', onData);
|
||||
deflate.on('error', onError);
|
||||
|
||||
deflate.write(message.data);
|
||||
if (VERSION[0] === 0 && VERSION[1] < 10) deflate.flush();
|
||||
};
|
||||
|
||||
Session.prototype.close = function() {
|
||||
if (this._inflate && this._inflate.close) this._inflate.close();
|
||||
this._inflate = null;
|
||||
|
||||
if (this._deflate && this._deflate.close) this._deflate.close();
|
||||
this._deflate = null;
|
||||
};
|
||||
|
||||
Session.prototype._getInflate = function() {
|
||||
if (this._inflate) return this._inflate;
|
||||
var inflate = zlib.createInflateRaw({windowBits: this._peerWindowBits});
|
||||
if (this._peerContextTakeover) this._inflate = inflate;
|
||||
return inflate;
|
||||
};
|
||||
|
||||
Session.prototype._getDeflate = function() {
|
||||
if (this._deflate) return this._deflate;
|
||||
|
||||
var deflate = zlib.createDeflateRaw({
|
||||
flush: zlib.Z_SYNC_FLUSH,
|
||||
windowBits: this._ownWindowBits,
|
||||
level: this._level,
|
||||
memLevel: this._memLevel,
|
||||
strategy: this._strategy
|
||||
});
|
||||
if (this._ownContextTakeover) this._deflate = deflate;
|
||||
return deflate;
|
||||
};
|
||||
|
||||
module.exports = Session;
|
||||
+2
-4
@@ -5,12 +5,10 @@
|
||||
, "keywords" : ["websocket", "compression", "deflate"]
|
||||
, "license" : "MIT"
|
||||
|
||||
, "version" : "0.1.1"
|
||||
, "version" : "0.1.3"
|
||||
, "engines" : {"node": ">=0.6.0"}
|
||||
, "main" : "./lib/permessage_deflate"
|
||||
, "devDependencies" : {"jstest": ""}
|
||||
|
||||
, "scripts" : {"test": "jstest spec/runner.js"}
|
||||
, "devDependencies" : {"babel": "", "jstest": ""}
|
||||
|
||||
, "repository" : { "type" : "git"
|
||||
, "url" : "git://github.com/faye/permessage-deflate-node.git"
|
||||
|
||||
+10
-11
@@ -9,7 +9,6 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
this.deflate = zlibMock()
|
||||
this.inflate = zlibMock()
|
||||
this.flush = zlib.Z_SYNC_FLUSH
|
||||
this.level = zlib.Z_DEFAULT_LEVEL
|
||||
this.memLevel = zlib.Z_DEFAULT_MEMLEVEL
|
||||
this.strategy = zlib.Z_DEFAULT_STRATEGY
|
||||
@@ -25,7 +24,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
this.stub(stream, "removeListener")
|
||||
|
||||
this.stub(stream, "write")
|
||||
this.stub(stream, "flush", function(cb) { if(cb) cb() });
|
||||
this.stub(stream, "flush").yields([])
|
||||
this.stub(stream, "close").raises(new Error("unexpected close()"))
|
||||
|
||||
return stream
|
||||
@@ -71,7 +70,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -102,7 +101,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses no context takeover and 15 window bits to deflate outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(deflate, "close").exactly(2)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
@@ -141,7 +140,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 8 window bits for deflating outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 8, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 8, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -170,7 +169,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses no context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(deflate, "close").exactly(2)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
@@ -192,7 +191,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 9 window bits for deflating outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 9, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 9, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -215,7 +214,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 8 window bits for deflating outgoing messages", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 8, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 8, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -310,7 +309,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the level of the deflate stream", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_BEST_SPEED, memLevel: memLevel, strategy: strategy}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_BEST_SPEED, memLevel: memLevel, strategy: strategy}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
@@ -320,7 +319,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the memLevel of the deflate stream", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: 5, strategy: strategy}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: 5, strategy: strategy}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
@@ -330,7 +329,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the strategy of the deflate stream", function() { with(this) {
|
||||
activate()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: memLevel, strategy: zlib.Z_FILTERED}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: memLevel, strategy: zlib.Z_FILTERED}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
require('babel/polyfill');
|
||||
|
||||
require('./client_session_spec')
|
||||
require('./server_session_spec')
|
||||
|
||||
+11
-12
@@ -9,7 +9,6 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
this.deflate = zlibMock()
|
||||
this.inflate = zlibMock()
|
||||
this.flush = zlib.Z_SYNC_FLUSH
|
||||
this.level = zlib.Z_DEFAULT_LEVEL
|
||||
this.memLevel = zlib.Z_DEFAULT_MEMLEVEL
|
||||
this.strategy = zlib.Z_DEFAULT_STRATEGY
|
||||
@@ -25,7 +24,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
this.stub(stream, "removeListener")
|
||||
|
||||
this.stub(stream, "write")
|
||||
this.stub(stream, "flush", function(cb) { if(cb) cb() });
|
||||
this.stub(stream, "flush").yields([])
|
||||
this.stub(stream, "close").raises(new Error("unexpected close()"))
|
||||
|
||||
return stream
|
||||
@@ -62,7 +61,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -77,7 +76,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses no context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(deflate, "close").exactly(2)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
@@ -109,7 +108,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 13 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 13, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 13, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -172,7 +171,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses no context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: level, memLevel: memLevel, strategy: strategy}).exactly(2).returning(deflate)
|
||||
expect(deflate, "close").exactly(2)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
@@ -190,7 +189,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 12 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 12, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 12, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -205,7 +204,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 12 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 12, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 12, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -220,7 +219,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("uses context takeover and 11 window bits for deflating outgoing messages", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 11, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 11, level: level, memLevel: memLevel, strategy: strategy}).exactly(1).returning(deflate)
|
||||
processOutgoingMessage()
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
@@ -312,7 +311,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the level of the deflate stream", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_BEST_SPEED, memLevel: memLevel, strategy: strategy}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_BEST_SPEED, memLevel: memLevel, strategy: strategy}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
@@ -322,7 +321,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the memLevel of the deflate stream", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: 5, strategy: strategy}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: 5, strategy: strategy}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
@@ -332,7 +331,7 @@ test.describe("ClientSession", function() { with(this) {
|
||||
|
||||
it("sets the strategy of the deflate stream", function() { with(this) {
|
||||
response()
|
||||
expect(zlib, "createDeflateRaw").given({flush: flush, windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: memLevel, strategy: zlib.Z_FILTERED}).returns(deflate)
|
||||
expect(zlib, "createDeflateRaw").given({windowBits: 15, level: zlib.Z_DEFAULT_LEVEL, memLevel: memLevel, strategy: zlib.Z_FILTERED}).returns(deflate)
|
||||
processOutgoingMessage()
|
||||
}})
|
||||
}})
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import Session from './session';
|
||||
import * as common from './common';
|
||||
|
||||
export default class ClientSession extends Session {
|
||||
static validParams(params) {
|
||||
if (!common.validParams(params)) return false;
|
||||
|
||||
if (params.hasOwnProperty('client_max_window_bits')) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(params.client_max_window_bits) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
generateOffer() {
|
||||
let offer = {};
|
||||
|
||||
if (this._acceptNoContextTakeover)
|
||||
offer.client_no_context_takeover = true;
|
||||
|
||||
if (this._acceptMaxWindowBits !== undefined) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(this._acceptMaxWindowBits) < 0) {
|
||||
throw new Error('Invalid value for maxWindowBits');
|
||||
}
|
||||
offer.client_max_window_bits = this._acceptMaxWindowBits;
|
||||
} else {
|
||||
offer.client_max_window_bits = true;
|
||||
}
|
||||
|
||||
if (this._requestNoContextTakeover)
|
||||
offer.server_no_context_takeover = true;
|
||||
|
||||
if (this._requestMaxWindowBits !== undefined) {
|
||||
if (common.VALID_WINDOW_BITS.indexOf(this._requestMaxWindowBits) < 0) {
|
||||
throw new Error('Invalid valud for requestMaxWindowBits');
|
||||
}
|
||||
offer.server_max_window_bits = this._requestMaxWindowBits;
|
||||
}
|
||||
|
||||
return offer;
|
||||
}
|
||||
|
||||
activate(params) {
|
||||
if (!ClientSession.validParams(params)) return false;
|
||||
|
||||
if (this._acceptMaxWindowBits && params.client_max_window_bits) {
|
||||
if (params.client_max_window_bits > this._acceptMaxWindowBits) return false;
|
||||
}
|
||||
|
||||
if (this._requestNoContextTakeover && !params.server_no_context_takeover)
|
||||
return false;
|
||||
|
||||
if (this._requestMaxWindowBits) {
|
||||
if (!params.server_max_window_bits) return false;
|
||||
if (params.server_max_window_bits > this._requestMaxWindowBits) return false;
|
||||
}
|
||||
|
||||
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._peerContextTakeover = !params.server_no_context_takeover;
|
||||
this._peerWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
const VALID_PARAMS = [
|
||||
'server_no_context_takeover',
|
||||
'client_no_context_takeover',
|
||||
'server_max_window_bits',
|
||||
'client_max_window_bits'
|
||||
];
|
||||
|
||||
export const DEFAULT_MAX_WINDOW_BITS = 15;
|
||||
export const VALID_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15];
|
||||
|
||||
export function concat(buffers, length) {
|
||||
let buffer = new Buffer(length),
|
||||
offset = 0;
|
||||
|
||||
for (let buf of buffers) {
|
||||
buf.copy(buffer, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export function validateOptions(options, validKeys) {
|
||||
for (let key in options) {
|
||||
if (validKeys.indexOf(key) < 0)
|
||||
throw new Error(`Unrecognized option: ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function validParams(params) {
|
||||
for (let key of Object.keys(params)) {
|
||||
if (VALID_PARAMS.indexOf(key) < 0) return false;
|
||||
if (params[key] instanceof Array) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('server_no_context_takeover')) {
|
||||
if (params.server_no_context_takeover !== true) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('client_no_context_takeover')) {
|
||||
if (params.client_no_context_takeover !== true) return false;
|
||||
}
|
||||
if (params.hasOwnProperty('server_max_window_bits')) {
|
||||
if (this.VALID_WINDOW_BITS.indexOf(params.server_max_window_bits) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import ClientSession from './client_session';
|
||||
import ServerSession from './server_session';
|
||||
import { validateOptions } from './common';
|
||||
|
||||
const VALID_OPTIONS = [
|
||||
'level',
|
||||
'memLevel',
|
||||
'strategy',
|
||||
'noContextTakeover',
|
||||
'maxWindowBits',
|
||||
'requestNoContextTakeover',
|
||||
'requestMaxWindowBits'
|
||||
];
|
||||
|
||||
const PermessageDeflate = {
|
||||
configure(options) {
|
||||
validateOptions(options, VALID_OPTIONS);
|
||||
let opts = this._options || {};
|
||||
for (let key in opts) options[key] = opts[key];
|
||||
return Object.create(this, {_options: {value: options}});
|
||||
},
|
||||
|
||||
createClientSession() {
|
||||
return new ClientSession(this._options || {});
|
||||
},
|
||||
|
||||
createServerSession(offers) {
|
||||
for (let offer of offers) {
|
||||
if (ServerSession.validParams(offer))
|
||||
return new ServerSession(this._options || {}, offer);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
name: 'permessage-deflate',
|
||||
type: 'permessage',
|
||||
rsv1: true,
|
||||
rsv2: false,
|
||||
rsv3: false
|
||||
};
|
||||
|
||||
export default PermessageDeflate;
|
||||
@@ -0,0 +1,58 @@
|
||||
import Session from './session';
|
||||
import * as common from './common';
|
||||
|
||||
export default class ServerSession extends Session {
|
||||
constructor(options, params) {
|
||||
super(options);
|
||||
this._params = params;
|
||||
}
|
||||
|
||||
static validParams(params) {
|
||||
if (!common.validParams(params)) return false;
|
||||
|
||||
if (params.hasOwnProperty('client_max_window_bits')) {
|
||||
if ([true].concat(common.VALID_WINDOW_BITS).indexOf(params.client_max_window_bits) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
generateResponse() {
|
||||
let params = {};
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.1
|
||||
let 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);
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.2
|
||||
let 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);
|
||||
}
|
||||
}
|
||||
|
||||
this._ownContextTakeover = !params.server_no_context_takeover;
|
||||
this._ownWindowBits = params.server_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
this._peerContextTakeover = !params.client_no_context_takeover;
|
||||
this._peerWindowBits = params.client_max_window_bits || common.DEFAULT_MAX_WINDOW_BITS;
|
||||
|
||||
return params;
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
import zlib from 'zlib';
|
||||
import { concat } from './common';
|
||||
|
||||
export default class Session {
|
||||
constructor({ level = zlib.Z_DEFAULT_LEVEL,
|
||||
memLevel = zlib.Z_DEFAULT_MEMLEVEL,
|
||||
strategy = zlib.Z_DEFAULT_STRATEGY,
|
||||
|
||||
noContextTakeover = false,
|
||||
maxWindowBits,
|
||||
requestNoContextTakeover = false,
|
||||
requestMaxWindowBits }) {
|
||||
|
||||
this._level = level;
|
||||
this._memLevel = memLevel;
|
||||
this._strategy = strategy;
|
||||
|
||||
this._acceptNoContextTakeover = noContextTakeover;
|
||||
this._acceptMaxWindowBits = maxWindowBits;
|
||||
this._requestNoContextTakeover = requestNoContextTakeover;
|
||||
this._requestMaxWindowBits = requestMaxWindowBits;
|
||||
|
||||
this._queueIn = [];
|
||||
this._queueOut = [];
|
||||
}
|
||||
|
||||
processIncomingMessage(message, callback) {
|
||||
if (!message.rsv1) return callback(null, message);
|
||||
if (this._lockIn) return this._queueIn.push([message, callback]);
|
||||
|
||||
let [inflate, chunks, length] = [this._getInflate(), [], 0];
|
||||
if (this._inflate) this._lockIn = true;
|
||||
|
||||
let return_ = (error, message) => {
|
||||
return_ = () => {};
|
||||
|
||||
inflate.removeListener('data', onData);
|
||||
inflate.removeListener('error', onError);
|
||||
if (!this._inflate && inflate.close) inflate.close();
|
||||
|
||||
this._lockIn = false;
|
||||
let next = this._queueIn.shift();
|
||||
if (next) this.processIncomingMessage.apply(this, next);
|
||||
|
||||
callback(error, message);
|
||||
};
|
||||
|
||||
let onData = (data) => {
|
||||
chunks.push(data);
|
||||
length += data.length;
|
||||
};
|
||||
|
||||
let onError = (error) => return_(error, null);
|
||||
|
||||
inflate.on('data', onData);
|
||||
inflate.on('error', onError);
|
||||
|
||||
inflate.write(message.data);
|
||||
inflate.write(new Buffer([0x00, 0x00, 0xff, 0xff]));
|
||||
|
||||
inflate.flush(() => {
|
||||
message.data = concat(chunks, length);
|
||||
return_(null, message);
|
||||
});
|
||||
}
|
||||
|
||||
processOutgoingMessage(message, callback) {
|
||||
if (this._lockOut) return this._queueOut.push([message, callback]);
|
||||
|
||||
let [deflate, chunks, length] = [this._getDeflate(), [], 0];
|
||||
if (this._deflate) this._lockOut = true;
|
||||
|
||||
let return_ = (error, message) => {
|
||||
return_ = () => {};
|
||||
|
||||
deflate.removeListener('data', onData);
|
||||
deflate.removeListener('error', onError);
|
||||
if (!this._deflate && deflate.close) deflate.close();
|
||||
|
||||
this._lockOut = false;
|
||||
let next = this._queueOut.shift();
|
||||
if (next) this.processOutgoingMessage.apply(this, next);
|
||||
|
||||
callback(error, message);
|
||||
};
|
||||
|
||||
let onData = (data) => {
|
||||
chunks.push(data);
|
||||
length += data.length;
|
||||
};
|
||||
|
||||
let onError = (error) => return_(error, null);
|
||||
|
||||
deflate.on('data', onData);
|
||||
deflate.on('error', onError);
|
||||
deflate.write(message.data);
|
||||
|
||||
let onFlush = () => {
|
||||
let data = concat(chunks, length);
|
||||
message.data = data.slice(0, data.length - 4);
|
||||
message.rsv1 = true;
|
||||
return_(null, message);
|
||||
};
|
||||
|
||||
if (deflate.params !== undefined)
|
||||
deflate.flush(zlib.Z_SYNC_FLUSH, onFlush);
|
||||
else
|
||||
deflate.flush(onFlush);
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this._inflate && this._inflate.close) this._inflate.close();
|
||||
this._inflate = null;
|
||||
|
||||
if (this._deflate && this._deflate.close) this._deflate.close();
|
||||
this._deflate = null;
|
||||
}
|
||||
|
||||
_getInflate() {
|
||||
if (this._inflate) return this._inflate;
|
||||
let inflate = zlib.createInflateRaw({windowBits: this._peerWindowBits});
|
||||
if (this._peerContextTakeover) this._inflate = inflate;
|
||||
return inflate;
|
||||
}
|
||||
|
||||
_getDeflate() {
|
||||
if (this._deflate) return this._deflate;
|
||||
|
||||
let deflate = zlib.createDeflateRaw({
|
||||
windowBits: this._ownWindowBits,
|
||||
level: this._level,
|
||||
memLevel: this._memLevel,
|
||||
strategy: this._strategy
|
||||
});
|
||||
|
||||
let flush = deflate.flush;
|
||||
|
||||
// This monkey-patch is needed to make Node 0.10 produce optimal output.
|
||||
// Without this it uses Z_FULL_FLUSH and effectively drops all its context
|
||||
// state on every flush.
|
||||
|
||||
if (deflate._flushFlag !== undefined && deflate.params === undefined)
|
||||
deflate.flush = function(callback) {
|
||||
let ws = this._writableState;
|
||||
if (ws.ended || ws.ending || ws.needDrain) {
|
||||
flush.call(this, callback);
|
||||
} else {
|
||||
this._flushFlag = zlib.Z_SYNC_FLUSH;
|
||||
this.write(new Buffer(0), '', callback);
|
||||
}
|
||||
};
|
||||
|
||||
if (this._ownContextTakeover) this._deflate = deflate;
|
||||
return deflate;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user