352 lines
14 KiB
JavaScript
352 lines
14 KiB
JavaScript
var PermessageDeflate = require('../lib/permessage_deflate'),
|
|
_zlib = require('zlib'),
|
|
test = require('jstest').Test
|
|
|
|
test.describe("ServerSession", function() { with(this) {
|
|
before(function() { with(this) {
|
|
this.deflate = zlibMock()
|
|
this.inflate = zlibMock()
|
|
this.level = _zlib.Z_DEFAULT_LEVEL
|
|
this.memLevel = _zlib.Z_DEFAULT_MEMLEVEL
|
|
this.strategy = _zlib.Z_DEFAULT_STRATEGY
|
|
|
|
this.ext = PermessageDeflate.configure(options)
|
|
this.zlib = {}
|
|
this.session = ext.configure({ zlib: zlib }).createServerSession([offer])
|
|
|
|
this.message = { data: "hello", rsv1: true }
|
|
}})
|
|
|
|
define("zlibMock", function() {
|
|
var stream = {}
|
|
|
|
this.stub(stream, "on").given("data").yields([new Buffer([0x00, 0x00, 0xff, 0xff])])
|
|
this.stub(stream, "on").given("error", this.instanceOf(Function))
|
|
this.stub(stream, "removeListener")
|
|
|
|
this.stub(stream, "write")
|
|
this.stub(stream, "flush").yields([])
|
|
this.stub(stream, "close").raises(new Error("unexpected close()"))
|
|
|
|
return stream
|
|
})
|
|
|
|
define("options", {})
|
|
define("offer", {})
|
|
|
|
define("response", function() {
|
|
if (this._response === undefined) this._response = this.session.generateResponse()
|
|
return this._response
|
|
})
|
|
|
|
define("processIncomingMessage", function() {
|
|
this.session.processIncomingMessage(this.message, function() {})
|
|
})
|
|
|
|
define("processOutgoingMessage", function() {
|
|
this.session.processOutgoingMessage(this.message, function() {})
|
|
})
|
|
|
|
describe("with default options", function() { with(this) {
|
|
describe("with an empty offer", function() { with(this) {
|
|
it("generates an emoty response", function() { with(this) {
|
|
assertEqual( {}, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 15 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 15 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
|
|
it("uses context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: level, memLevel: memLevel, strategy: strategy }).exactly(1).returning(deflate)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes server_no_context_takeover", function() { with(this) {
|
|
define("offer", { server_no_context_takeover: true })
|
|
|
|
it("includes server_no_context_takeover in the response", function() { with(this) {
|
|
assertEqual( { server_no_context_takeover: true }, response() )
|
|
}})
|
|
|
|
it("uses no context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: level, memLevel: memLevel, strategy: strategy }).exactly(2).returning(deflate)
|
|
expect(deflate, "close").exactly(2)
|
|
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) {
|
|
define("offer", { client_no_context_takeover: true })
|
|
|
|
it("includes client_no_context_takeover in the response", function() { with(this) {
|
|
assertEqual( { client_no_context_takeover: true }, response() )
|
|
}})
|
|
|
|
it("uses no context takeover and 15 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 15 }).exactly(2).returning(inflate)
|
|
expect(inflate, "close").exactly(2)
|
|
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) {
|
|
define("offer", { server_max_window_bits: 13 })
|
|
|
|
it("includes server_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { server_max_window_bits: 13 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 13 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 13, level: level, memLevel: memLevel, strategy: strategy }).exactly(1).returning(deflate)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes invalid server_max_window_bits", function() { with(this) {
|
|
define("offer", { server_max_window_bits: 20 })
|
|
|
|
it("does not create a session", function() { with(this) {
|
|
assertEqual( null, session )
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes client_max_window_bits", function() { with(this) {
|
|
define("offer", { client_max_window_bits: true })
|
|
|
|
it("does not include a client_max_window_bits hint in the response", function() { with(this) {
|
|
assertEqual( {}, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 15 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 15 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes a client_max_window_bits hint", function() { with(this) {
|
|
define("offer", { client_max_window_bits: 13 })
|
|
|
|
it("includes a client_max_window_bits hint in the response", function() { with(this) {
|
|
assertEqual( { client_max_window_bits: 13 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 13 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 13 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes invalid client_max_window_bits", function() { with(this) {
|
|
define("offer", { client_max_window_bits: 20 })
|
|
|
|
it("does not create a session", function() { with(this) {
|
|
assertEqual( null, session )
|
|
}})
|
|
}})
|
|
}})
|
|
|
|
describe("with noContextTakeover", function() { with(this) {
|
|
define("options", { noContextTakeover: true })
|
|
|
|
describe("with an empty offer", function() { with(this) {
|
|
it("includes server_no_context_takeover in the response", function() { with(this) {
|
|
assertEqual( { server_no_context_takeover: true }, response() )
|
|
}})
|
|
|
|
it("uses no context takeover and 15 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: level, memLevel: memLevel, strategy: strategy }).exactly(2).returning(deflate)
|
|
expect(deflate, "close").exactly(2)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
}})
|
|
|
|
describe("with maxWindowBits", function() { with(this) {
|
|
define("options", { maxWindowBits: 12 })
|
|
|
|
describe("with an empty offer", function() { with(this) {
|
|
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) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 12, level: level, memLevel: memLevel, strategy: strategy }).exactly(1).returning(deflate)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer has higher server_max_window_bits", function() { with(this) {
|
|
define("offer", { server_max_window_bits: 13 })
|
|
|
|
it("includes server_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { server_max_window_bits: 12 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 12 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 12, level: level, memLevel: memLevel, strategy: strategy }).exactly(1).returning(deflate)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer has lower server_max_window_bits", function() { with(this) {
|
|
define("offer", { server_max_window_bits: 11 })
|
|
|
|
it("includes server_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { server_max_window_bits: 11 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 11 window bits for deflating outgoing messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 11, level: level, memLevel: memLevel, strategy: strategy }).exactly(1).returning(deflate)
|
|
processOutgoingMessage()
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
}})
|
|
|
|
describe("with requestNoContextTakeover", function() { with(this) {
|
|
define("options", { requestNoContextTakeover: true })
|
|
|
|
describe("with an empty offer", function() { with(this) {
|
|
it("includes client_no_context_takeover in the response", function() { with(this) {
|
|
assertEqual( { client_no_context_takeover: true }, response() )
|
|
}})
|
|
|
|
it("uses no context takeover and 15 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 15 }).exactly(2).returning(inflate)
|
|
expect(inflate, "close").exactly(2)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
}})
|
|
|
|
describe("with requestMaxWindowBits", function() { with(this) {
|
|
define("options", { requestMaxWindowBits: 11 })
|
|
|
|
describe("with an empty offer", function() { with(this) {
|
|
it("does not include client_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( {}, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 15 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 15 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer includes client_max_window_bits", function() { with(this) {
|
|
define("offer", { client_max_window_bits: true })
|
|
|
|
it("includes client_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { client_max_window_bits: 11 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 11 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 11 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer has higher client_max_window_bits", function() { with(this) {
|
|
define("offer", { client_max_window_bits: 12 })
|
|
|
|
it("includes client_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { client_max_window_bits: 11 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 11 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 11 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("when the offer has lower client_max_window_bits", function() { with(this) {
|
|
define("offer", { client_max_window_bits: 10 })
|
|
|
|
it("includes client_max_window_bits in the response", function() { with(this) {
|
|
assertEqual( { client_max_window_bits: 10 }, response() )
|
|
}})
|
|
|
|
it("uses context takeover and 10 window bits for inflating incoming messages", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createInflateRaw").given({ windowBits: 10 }).exactly(1).returning(inflate)
|
|
processIncomingMessage()
|
|
processIncomingMessage()
|
|
}})
|
|
}})
|
|
}})
|
|
|
|
describe("with level", function() { with(this) {
|
|
define("options", { level: _zlib.Z_BEST_SPEED })
|
|
|
|
it("sets the level of the deflate stream", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: _zlib.Z_BEST_SPEED, memLevel: memLevel, strategy: strategy }).returns(deflate)
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("with memLevel", function() { with(this) {
|
|
define("options", { memLevel: 5 })
|
|
|
|
it("sets the memLevel of the deflate stream", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: _zlib.Z_DEFAULT_LEVEL, memLevel: 5, strategy: strategy }).returns(deflate)
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
|
|
describe("with strategy", function() { with(this) {
|
|
define("options", { strategy: _zlib.Z_FILTERED })
|
|
|
|
it("sets the strategy of the deflate stream", function() { with(this) {
|
|
response()
|
|
expect(zlib, "createDeflateRaw").given({ windowBits: 15, level: _zlib.Z_DEFAULT_LEVEL, memLevel: memLevel, strategy: _zlib.Z_FILTERED }).returns(deflate)
|
|
processOutgoingMessage()
|
|
}})
|
|
}})
|
|
}})
|