websocket-driver
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -0,1 +1,5 @@ | ||
### 0.5.0 / 2014-12-13 | ||
* Support protocol extensions via the websocket-extensions module | ||
### 0.4.0 / 2014-11-08 | ||
@@ -2,0 +6,0 @@ |
var net = require('net'), | ||
websocket = require('../lib/websocket/driver'); | ||
websocket = require('../lib/websocket/driver'), | ||
deflate = require('permessage-deflate'); | ||
var server = net.createServer(function(connection) { | ||
var driver = websocket.server(); | ||
driver.addExtension(deflate); | ||
@@ -7,0 +9,0 @@ driver.on('connect', function() { |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
// Protocol references: | ||
@@ -38,3 +40,3 @@ // | ||
return request.method === 'GET' && | ||
connection.toLowerCase().split(/\s*,\s*/).indexOf('upgrade') >= 0 && | ||
connection.toLowerCase().split(/ *, */).indexOf('upgrade') >= 0 && | ||
upgrade.toLowerCase() === 'websocket'; | ||
@@ -41,0 +43,0 @@ } |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Emitter = require('events').EventEmitter, | ||
@@ -58,2 +60,6 @@ util = require('util'), | ||
addExtension: function(extension) { | ||
return false; | ||
}, | ||
setHeader: function(name, value) { | ||
@@ -60,0 +66,0 @@ if (this.readyState > 0) return false; |
@@ -1,2 +0,5 @@ | ||
var url = require('url'), | ||
'use strict'; | ||
var crypto = require('crypto'), | ||
url = require('url'), | ||
util = require('util'), | ||
@@ -37,5 +40,3 @@ HttpParser = require('../http_parser'), | ||
Client.generateKey = function() { | ||
var buffer = new Buffer(16), i = buffer.length; | ||
while (i--) buffer[i] = Math.floor(Math.random() * 256); | ||
return buffer.toString('base64'); | ||
return crypto.randomBytes(16).toString('base64'); | ||
}; | ||
@@ -62,2 +63,5 @@ | ||
this._validateHandshake(); | ||
if (this.readyState === 3) return; | ||
this._open(); | ||
this.parse(this._http.body); | ||
@@ -67,2 +71,6 @@ }, | ||
_handshakeRequest: function() { | ||
var extensions = this._extensions.generateOffer(); | ||
if (extensions) | ||
this._headers.set('Sec-WebSocket-Extensions', extensions); | ||
var start = 'GET ' + this._pathname + ' HTTP/1.1', | ||
@@ -116,3 +124,7 @@ headers = [start, this._headers.toString(), '']; | ||
this._open(); | ||
try { | ||
this._extensions.activate(this.headers['sec-websocket-extensions']); | ||
} catch (e) { | ||
return this._failHandshake(e.message); | ||
} | ||
} | ||
@@ -119,0 +131,0 @@ }; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Base = require('./base'), | ||
@@ -2,0 +4,0 @@ util = require('util'); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Base = require('./base'), | ||
@@ -69,9 +71,6 @@ Draft75 = require('./draft75'), | ||
var headers = this._request.headers, | ||
key1 = headers['sec-websocket-key1'], | ||
value1 = numberFromKey(key1) / spacesInKey(key1), | ||
key2 = headers['sec-websocket-key2'], | ||
value2 = numberFromKey(key2) / spacesInKey(key2), | ||
md5 = crypto.createHash('md5'); | ||
@@ -78,0 +77,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Headers = function() { | ||
@@ -2,0 +4,0 @@ this.clear(); |
@@ -1,10 +0,15 @@ | ||
var crypto = require('crypto'), | ||
util = require('util'), | ||
Base = require('./base'), | ||
Reader = require('./hybi/stream_reader'); | ||
'use strict'; | ||
var crypto = require('crypto'), | ||
util = require('util'), | ||
Extensions = require('websocket-extensions'), | ||
Base = require('./base'), | ||
Frame = require('./hybi/frame'), | ||
Message = require('./hybi/message'), | ||
Reader = require('./hybi/stream_reader'); | ||
var Hybi = function(request, url, options) { | ||
Base.apply(this, arguments); | ||
this._reset(); | ||
this._extensions = new Extensions(); | ||
this._reader = new Reader(); | ||
@@ -18,3 +23,3 @@ this._stage = 0; | ||
if (typeof this._protocols === 'string') | ||
this._protocols = this._protocols.split(/\s*,\s*/); | ||
this._protocols = this._protocols.split(/ *, */); | ||
@@ -33,3 +38,3 @@ if (!this._request) return; | ||
if (protos !== undefined) { | ||
if (typeof protos === 'string') protos = protos.split(/\s*,\s*/); | ||
if (typeof protos === 'string') protos = protos.split(/ *, */); | ||
this.protocol = protos.filter(function(p) { return supported.indexOf(p) >= 0 })[0]; | ||
@@ -80,5 +85,5 @@ if (this.protocol) this._headers.set('Sec-WebSocket-Protocol', this.protocol); | ||
OPCODE_CODES: [0, 1, 2, 8, 9, 10], | ||
FRAGMENTED_OPCODES: [0, 1, 2], | ||
OPENING_OPCODES: [1, 2], | ||
OPCODE_CODES: [0, 1, 2, 8, 9, 10], | ||
MESSAGE_OPCODES: [0, 1, 2], | ||
OPENING_OPCODES: [1, 2], | ||
@@ -106,2 +111,7 @@ TWO_POWERS: [0, 1, 2, 3, 4, 5, 6, 7].map(function(n) { return Math.pow(2, 8 * n) }), | ||
addExtension: function(extension) { | ||
this._extensions.add(extension); | ||
return true; | ||
}, | ||
parse: function(data) { | ||
@@ -123,3 +133,3 @@ this._reader.put(data); | ||
case 2: | ||
buffer = this._reader.read(this._lengthSize); | ||
buffer = this._reader.read(this._frame.lengthBytes); | ||
if (buffer) this._parseExtendedLength(buffer); | ||
@@ -131,3 +141,3 @@ break; | ||
if (buffer) { | ||
this._mask = buffer; | ||
this._frame.maskingKey = buffer; | ||
this._stage = 4; | ||
@@ -138,3 +148,3 @@ } | ||
case 4: | ||
buffer = this._reader.read(this._length); | ||
buffer = this._reader.read(this._frame.length); | ||
if (buffer) { | ||
@@ -152,57 +162,2 @@ this._emitFrame(buffer); | ||
frame: function(data, type, code) { | ||
if (this.readyState <= 0) return this._queue([data, type, code]); | ||
if (this.readyState !== 1) return false; | ||
if (data instanceof Array) data = new Buffer(data); | ||
var isText = (typeof data === 'string'), | ||
opcode = this.OPCODES[type || (isText ? 'text' : 'binary')], | ||
buffer = isText ? new Buffer(data, 'utf8') : data, | ||
insert = code ? 2 : 0, | ||
length = buffer.length + insert, | ||
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10), | ||
offset = header + (this._masking ? 4 : 0), | ||
masked = this._masking ? this.MASK : 0, | ||
frame = new Buffer(length + offset), | ||
BYTE = this.BYTE, | ||
mask, i; | ||
frame[0] = this.FIN | opcode; | ||
if (length <= 125) { | ||
frame[1] = masked | length; | ||
} else if (length <= 65535) { | ||
frame[1] = masked | 126; | ||
frame[2] = Math.floor(length / 256); | ||
frame[3] = length & BYTE; | ||
} else { | ||
frame[1] = masked | 127; | ||
frame[2] = Math.floor(length / Math.pow(2,56)) & BYTE; | ||
frame[3] = Math.floor(length / Math.pow(2,48)) & BYTE; | ||
frame[4] = Math.floor(length / Math.pow(2,40)) & BYTE; | ||
frame[5] = Math.floor(length / Math.pow(2,32)) & BYTE; | ||
frame[6] = Math.floor(length / Math.pow(2,24)) & BYTE; | ||
frame[7] = Math.floor(length / Math.pow(2,16)) & BYTE; | ||
frame[8] = Math.floor(length / Math.pow(2,8)) & BYTE; | ||
frame[9] = length & BYTE; | ||
} | ||
if (code) { | ||
frame[offset] = Math.floor(code / 256) & BYTE; | ||
frame[offset+1] = code & BYTE; | ||
} | ||
buffer.copy(frame, offset + insert); | ||
if (this._masking) { | ||
mask = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), | ||
Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)]; | ||
new Buffer(mask).copy(frame, header); | ||
Hybi.mask(frame, mask, offset); | ||
} | ||
this._write(frame); | ||
return true; | ||
}, | ||
text: function(message) { | ||
@@ -239,3 +194,100 @@ return this.frame(message, 'text'); | ||
frame: function(data, type, code) { | ||
if (this.readyState <= 0) return this._queue([data, type, code]); | ||
if (this.readyState !== 1) return false; | ||
if (data instanceof Array) data = new Buffer(data); | ||
var message = new Message(), | ||
isText = (typeof data === 'string'), | ||
payload, buffer; | ||
message.rsv1 = message.rsv2 = message.rsv3 = false; | ||
message.opcode = this.OPCODES[type || (isText ? 'text' : 'binary')]; | ||
payload = isText ? new Buffer(data, 'utf8') : data; | ||
if (code) { | ||
buffer = payload; | ||
payload = new Buffer(2 + buffer.length); | ||
payload[0] = ~~(code / 256) & this.BYTE; | ||
payload[1] = code & this.BYTE; | ||
buffer.copy(payload, 2); | ||
} | ||
message.data = payload; | ||
var onMessageReady = function(message) { | ||
var frame = new Frame(); | ||
frame.final = true; | ||
frame.rsv1 = message.rsv1; | ||
frame.rsv2 = message.rsv2; | ||
frame.rsv3 = message.rsv3; | ||
frame.opcode = message.opcode; | ||
frame.masked = !!this._masking; | ||
frame.length = message.data.length; | ||
frame.payload = message.data; | ||
if (frame.masked) frame.maskingKey = crypto.randomBytes(4); | ||
this._sendFrame(frame); | ||
}; | ||
if (this.MESSAGE_OPCODES.indexOf(message.opcode) >= 0) | ||
this._extensions.processOutgoingMessage(message, function(error, message) { | ||
if (error) return this._fail('extension_error', error.message); | ||
onMessageReady.call(this, message); | ||
}, this); | ||
else | ||
onMessageReady.call(this, message); | ||
return true; | ||
}, | ||
_sendFrame: function(frame) { | ||
var length = frame.length, | ||
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10), | ||
offset = header + (frame.masked ? 4 : 0), | ||
buffer = new Buffer(offset + length), | ||
BYTE = this.BYTE, | ||
masked = frame.masked ? this.MASK : 0; | ||
buffer[0] = (frame.final ? this.FIN : 0) | | ||
(frame.rsv1 ? this.RSV1 : 0) | | ||
(frame.rsv2 ? this.RSV2 : 0) | | ||
(frame.rsv3 ? this.RSV3 : 0) | | ||
frame.opcode; | ||
if (length <= 125) { | ||
buffer[1] = masked | length; | ||
} else if (length <= 65535) { | ||
buffer[1] = masked | 126; | ||
buffer[2] = ~~(length / 256); | ||
buffer[3] = length & BYTE; | ||
} else { | ||
buffer[1] = masked | 127; | ||
buffer[2] = ~~(length / Math.pow(2, 56)) & BYTE; | ||
buffer[3] = ~~(length / Math.pow(2, 48)) & BYTE; | ||
buffer[4] = ~~(length / Math.pow(2, 40)) & BYTE; | ||
buffer[5] = ~~(length / Math.pow(2, 32)) & BYTE; | ||
buffer[6] = ~~(length / Math.pow(2, 24)) & BYTE; | ||
buffer[7] = ~~(length / Math.pow(2, 16)) & BYTE; | ||
buffer[8] = ~~(length / Math.pow(2, 8)) & BYTE; | ||
buffer[9] = length & BYTE; | ||
} | ||
if (frame.masked) { | ||
frame.maskingKey.copy(buffer, header); | ||
Hybi.mask(frame.payload, frame.maskingKey).copy(buffer, offset); | ||
} else { | ||
frame.payload.copy(buffer, offset); | ||
} | ||
this._write(buffer); | ||
}, | ||
_handshakeResponse: function() { | ||
var extensions = this._extensions.generateResponse(this._request.headers['sec-websocket-extensions']); | ||
if (extensions) this._headers.set('Sec-WebSocket-Extensions', extensions); | ||
var start = 'HTTP/1.1 101 Switching Protocols', | ||
@@ -249,5 +301,8 @@ headers = [start, this._headers.toString(), '']; | ||
this.frame(reason, 'close', code); | ||
delete this._frame; | ||
delete this._message; | ||
this.readyState = 3; | ||
this._stage = 5; | ||
this.emit('close', new Base.CloseEvent(code, reason)); | ||
this._extensions.close(); | ||
}, | ||
@@ -265,18 +320,23 @@ | ||
if (rsvs.filter(function(rsv) { return rsv }).length > 0) | ||
var frame = this._frame = new Frame(); | ||
frame.final = (data & this.FIN) === this.FIN; | ||
frame.rsv1 = rsvs[0]; | ||
frame.rsv2 = rsvs[1]; | ||
frame.rsv3 = rsvs[2]; | ||
frame.opcode = (data & this.OPCODE); | ||
if (!this._extensions.validFrameRsv(frame)) | ||
return this._fail('protocol_error', | ||
'One or more reserved bits are on: reserved1 = ' + (rsvs[0] ? 1 : 0) + | ||
', reserved2 = ' + (rsvs[1] ? 1 : 0) + | ||
', reserved3 = ' + (rsvs[2] ? 1 : 0)); | ||
'One or more reserved bits are on: reserved1 = ' + (frame.rsv1 ? 1 : 0) + | ||
', reserved2 = ' + (frame.rsv2 ? 1 : 0) + | ||
', reserved3 = ' + (frame.rsv3 ? 1 : 0)); | ||
this._final = (data & this.FIN) === this.FIN; | ||
this._opcode = (data & this.OPCODE); | ||
if (this.OPCODE_CODES.indexOf(frame.opcode) < 0) | ||
return this._fail('protocol_error', 'Unrecognized frame opcode: ' + frame.opcode); | ||
if (this.OPCODE_CODES.indexOf(this._opcode) < 0) | ||
return this._fail('protocol_error', 'Unrecognized frame opcode: ' + this._opcode); | ||
if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && !frame.final) | ||
return this._fail('protocol_error', 'Received fragmented control frame: opcode = ' + frame.opcode); | ||
if (this.FRAGMENTED_OPCODES.indexOf(this._opcode) < 0 && !this._final) | ||
return this._fail('protocol_error', 'Received fragmented control frame: opcode = ' + this._opcode); | ||
if (this._mode && this.OPENING_OPCODES.indexOf(this._opcode) >= 0) | ||
if (this._message && this.OPENING_OPCODES.indexOf(frame.opcode) >= 0) | ||
return this._fail('protocol_error', 'Received new data frame but previous continuous frame is unfinished'); | ||
@@ -288,14 +348,16 @@ | ||
_parseLength: function(data) { | ||
this._masked = (data & this.MASK) === this.MASK; | ||
if (this._requireMasking && !this._masked) | ||
var frame = this._frame; | ||
frame.masked = (data & this.MASK) === this.MASK; | ||
if (this._requireMasking && !frame.masked) | ||
return this._fail('unacceptable', 'Received unmasked frame but masking is required'); | ||
this._length = (data & this.LENGTH); | ||
frame.length = (data & this.LENGTH); | ||
if (this._length >= 0 && this._length <= 125) { | ||
if (frame.length >= 0 && frame.length <= 125) { | ||
if (!this._checkFrameLength()) return; | ||
this._stage = this._masked ? 3 : 4; | ||
this._stage = frame.masked ? 3 : 4; | ||
} else { | ||
this._lengthSize = (this._length === 126 ? 2 : 8); | ||
this._stage = 2; | ||
frame.lengthBytes = (frame.length === 126 ? 2 : 8); | ||
this._stage = 2; | ||
} | ||
@@ -305,14 +367,17 @@ }, | ||
_parseExtendedLength: function(buffer) { | ||
this._length = this._getInteger(buffer); | ||
var frame = this._frame; | ||
frame.length = this._getInteger(buffer); | ||
if (this.FRAGMENTED_OPCODES.indexOf(this._opcode) < 0 && this._length > 125) | ||
return this._fail('protocol_error', 'Received control frame having too long payload: ' + this._length); | ||
if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && frame.length > 125) | ||
return this._fail('protocol_error', 'Received control frame having too long payload: ' + frame.length); | ||
if (!this._checkFrameLength()) return; | ||
this._stage = this._masked ? 3 : 4; | ||
this._stage = frame.masked ? 3 : 4; | ||
}, | ||
_checkFrameLength: function() { | ||
if (this.__blength + this._length > this._maxLength) { | ||
var length = this._message ? this._message.length : 0; | ||
if (length + this._frame.length > this._maxLength) { | ||
this._fail('too_large', 'WebSocket frame length too large'); | ||
@@ -326,45 +391,28 @@ return false; | ||
_emitFrame: function(buffer) { | ||
var payload = Hybi.mask(buffer, this._mask), | ||
isFinal = this._final, | ||
opcode = this._opcode; | ||
var frame = this._frame, | ||
payload = frame.payload = Hybi.mask(buffer, frame.maskingKey), | ||
opcode = frame.opcode, | ||
message, | ||
code, reason, | ||
callbacks, callback; | ||
this._final = this._opcode = this._length = this._lengthSize = this._masked = this._mask = null; | ||
delete this._frame; | ||
if (opcode === this.OPCODES.continuation) { | ||
if (!this._mode) return this._fail('protocol_error', 'Received unexpected continuation frame'); | ||
this._buffer(payload); | ||
if (isFinal) { | ||
var message = this._concatBuffer(); | ||
if (this._mode === 'text') message = this._encode(message); | ||
this._reset(); | ||
if (message === null) | ||
this._fail('encoding_error', 'Could not decode a text frame as UTF-8'); | ||
else | ||
this.emit('message', new Base.MessageEvent(message)); | ||
} | ||
if (!this._message) return this._fail('protocol_error', 'Received unexpected continuation frame'); | ||
this._message.pushFrame(frame); | ||
} | ||
else if (opcode === this.OPCODES.text) { | ||
if (isFinal) { | ||
var message = this._encode(payload); | ||
if (message === null) | ||
this._fail('encoding_error', 'Could not decode a text frame as UTF-8'); | ||
else | ||
this.emit('message', new Base.MessageEvent(message)); | ||
} else { | ||
this._mode = 'text'; | ||
this._buffer(payload); | ||
} | ||
if (opcode === this.OPCODES.text || opcode === this.OPCODES.binary) { | ||
this._message = new Message(); | ||
this._message.pushFrame(frame); | ||
} | ||
else if (opcode === this.OPCODES.binary) { | ||
if (isFinal) { | ||
this.emit('message', new Base.MessageEvent(payload)); | ||
} else { | ||
this._mode = 'binary'; | ||
this._buffer(payload); | ||
} | ||
} | ||
else if (opcode === this.OPCODES.close) { | ||
var code = (payload.length >= 2) ? 256 * payload[0] + payload[1] : null, | ||
reason = (payload.length > 2) ? this._encode(payload.slice(2)) : null; | ||
if (frame.final && this.MESSAGE_OPCODES.indexOf(opcode) >= 0) | ||
return this._emitMessage(this._message); | ||
if (opcode === this.OPCODES.close) { | ||
code = (payload.length >= 2) ? 256 * payload[0] + payload[1] : null; | ||
reason = (payload.length > 2) ? this._encode(payload.slice(2)) : null; | ||
if (!(payload.length === 0) && | ||
@@ -380,10 +428,12 @@ !(code !== null && code >= this.MIN_RESERVED_ERROR && code <= this.MAX_RESERVED_ERROR) && | ||
} | ||
else if (opcode === this.OPCODES.ping) { | ||
if (opcode === this.OPCODES.ping) { | ||
this.frame(payload, 'pong'); | ||
} | ||
else if (opcode === this.OPCODES.pong) { | ||
var callbacks = this._pingCallbacks, | ||
message = this._encode(payload), | ||
callback = callbacks[message]; | ||
if (opcode === this.OPCODES.pong) { | ||
callbacks = this._pingCallbacks; | ||
message = this._encode(payload); | ||
callback = callbacks[message]; | ||
delete callbacks[message]; | ||
@@ -394,22 +444,19 @@ if (callback) callback() | ||
_buffer: function(fragment) { | ||
this.__buffer.push(fragment); | ||
this.__blength += fragment.length; | ||
}, | ||
_emitMessage: function(message) { | ||
var message = this._message; | ||
message.read(); | ||
_concatBuffer: function() { | ||
var buffer = new Buffer(this.__blength), | ||
offset = 0; | ||
delete this._message; | ||
for (var i = 0, n = this.__buffer.length; i < n; i++) { | ||
this.__buffer[i].copy(buffer, offset); | ||
offset += this.__buffer[i].length; | ||
} | ||
return buffer; | ||
}, | ||
this._extensions.processIncomingMessage(message, function(error, message) { | ||
if (error) return this._fail('extension_error', error.message); | ||
_reset: function() { | ||
this._mode = null; | ||
this.__buffer = []; | ||
this.__blength = 0; | ||
var payload = message.data; | ||
if (message.opcode === this.OPCODES.text) payload = this._encode(payload); | ||
if (payload === null) | ||
return this._fail('encoding_error', 'Could not decode a text frame as UTF-8'); | ||
else | ||
this.emit('message', new Base.MessageEvent(payload)); | ||
}, this); | ||
}, | ||
@@ -416,0 +463,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var StreamReader = function() { | ||
@@ -2,0 +4,0 @@ this._queue = []; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Stream = require('stream').Stream, | ||
@@ -2,0 +4,0 @@ url = require('url'), |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var util = require('util'), | ||
@@ -37,4 +39,4 @@ HttpParser = require('../http_parser'), | ||
this._delegate.io = this.io; | ||
this._open(); | ||
this._delegate.on('open', function() { self._open() }); | ||
this.EVENTS.forEach(function(event) { | ||
@@ -59,3 +61,3 @@ this._delegate.on(event, function(e) { self.emit(event, e) }); | ||
['setHeader', 'start', 'state', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) { | ||
['addExtension', 'setHeader', 'start', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) { | ||
instance[method] = function() { | ||
@@ -62,0 +64,0 @@ if (this._delegate) { |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var HTTPParser = process.binding('http_parser').HTTPParser, | ||
@@ -22,3 +24,8 @@ version = HTTPParser.RESPONSE ? 6 : 4; | ||
this._parser.onHeaderValue = function(b, start, length) { | ||
self.headers[current] = b.toString('utf8', start, start + length); | ||
var value = b.toString('utf8', start, start + length); | ||
if (self.headers.hasOwnProperty(current)) | ||
self.headers[current] += ', ' + value; | ||
else | ||
self.headers[current] = value; | ||
}; | ||
@@ -31,7 +38,13 @@ | ||
var headers = info.headers; | ||
var headers = info.headers, key, value; | ||
if (!headers) return; | ||
for (var i = 0, n = headers.length; i < n; i += 2) | ||
self.headers[headers[i].toLowerCase()] = headers[i+1]; | ||
for (var i = 0, n = headers.length; i < n; i += 2) { | ||
key = headers[i].toLowerCase(); | ||
value = headers[i+1]; | ||
if (self.headers.hasOwnProperty(key)) | ||
self.headers[key] += ', ' + value; | ||
else | ||
self.headers[key] = value; | ||
} | ||
@@ -38,0 +51,0 @@ self._complete = true; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
/** | ||
@@ -2,0 +4,0 @@ |
@@ -8,6 +8,7 @@ { "name" : "websocket-driver" | ||
, "version" : "0.4.0" | ||
, "engines" : {"node": ">=0.4.0"} | ||
, "version" : "0.5.0" | ||
, "engines" : {"node": ">=0.6.0"} | ||
, "main" : "./lib/websocket/driver" | ||
, "devDependencies" : {"jstest": ""} | ||
, "dependencies" : {"websocket-extensions": ">=0.1.0"} | ||
, "devDependencies" : {"jstest": "", "permessage-deflate": ""} | ||
@@ -14,0 +15,0 @@ , "scripts" : {"test": "jstest spec/runner.js"} |
@@ -17,2 +17,5 @@ # websocket-driver [![Build Status](https://travis-ci.org/faye/websocket-driver-node.svg)](https://travis-ci.org/faye/websocket-driver-node) | ||
* Negotiate subprotocol selection based on `Sec-WebSocket-Protocol` | ||
* Negotiate and use extensions via the | ||
[websocket-extensions](https://github.com/faye/websocket-extensions-node) | ||
module | ||
* Buffer sent messages until the handshake process is finished | ||
@@ -282,2 +285,9 @@ * Deal with proxies that defer delivery of the draft-76 handshake body | ||
#### `driver.addExtension(extension)` | ||
Registers a protocol extension whose operation will be negotiated via the | ||
`Sec-WebSocket-Extensions` header. `extension` is any extension compatible with | ||
the [websocket-extensions](https://github.com/faye/websocket-extensions-node) | ||
framework. | ||
#### `driver.setHeader(name, value)` | ||
@@ -284,0 +294,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
60172
18
1271
376
1
2
+ Addedwebsocket-extensions@>=0.1.0
+ Addedwebsocket-extensions@0.1.4(transitive)