Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10481b81db | |||
| 5b3c8131c4 | |||
| b0b0d69ce4 | |||
| 3461e0187b | |||
| 5b59d0fcd8 | |||
| 68990a260b |
+6
-1
@@ -1,3 +1,4 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
@@ -5,7 +6,11 @@ node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "iojs"
|
||||
- "iojs-1"
|
||||
- "iojs-2"
|
||||
- "iojs-3"
|
||||
- "4"
|
||||
- "5"
|
||||
|
||||
before_install:
|
||||
- '[ "${TRAVIS_NODE_VERSION}" = "0.6" ] && npm conf set strict-ssl false || true'
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
### 0.6.3 / 2015-11-06
|
||||
|
||||
* Reject draft-76 handshakes if their Sec-WebSocket-Key headers are invalid
|
||||
* Throw a more helpful error if a client is created with an invalid URL
|
||||
|
||||
### 0.6.2 / 2015-07-18
|
||||
|
||||
* When the peer sends a close frame with no error code, emit 1000
|
||||
|
||||
@@ -20,6 +20,9 @@ var Client = function(_url, options) {
|
||||
var uri = url.parse(this.url),
|
||||
auth = uri.auth && new Buffer(uri.auth, 'utf8').toString('base64');
|
||||
|
||||
if (this.VALID_PROTOCOLS.indexOf(uri.protocol) < 0)
|
||||
throw new Error(this.url + ' is not a valid WebSocket URL');
|
||||
|
||||
this._pathname = (uri.pathname || '/') + (uri.search || '');
|
||||
|
||||
this._headers.set('Host', uri.host);
|
||||
@@ -41,6 +44,8 @@ Client.generateKey = function() {
|
||||
};
|
||||
|
||||
var instance = {
|
||||
VALID_PROTOCOLS: ['ws:', 'wss:'],
|
||||
|
||||
proxy: function(origin, options) {
|
||||
return new Proxy(this, origin, options);
|
||||
},
|
||||
|
||||
@@ -49,6 +49,24 @@ var instance = {
|
||||
},
|
||||
|
||||
_handshakeResponse: function() {
|
||||
var headers = this._request.headers,
|
||||
|
||||
key1 = headers['sec-websocket-key1'],
|
||||
number1 = numberFromKey(key1),
|
||||
spaces1 = spacesInKey(key1),
|
||||
|
||||
key2 = headers['sec-websocket-key2'],
|
||||
number2 = numberFromKey(key2),
|
||||
spaces2 = spacesInKey(key2);
|
||||
|
||||
if (number1 % spaces1 !== 0 || number2 % spaces2 !== 0) {
|
||||
this.emit('error', new Error('Client sent invalid Sec-WebSocket-Key headers'));
|
||||
this.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
this._keyValues = [number1 / spaces1, number2 / spaces2];
|
||||
|
||||
var start = 'HTTP/1.1 101 WebSocket Protocol Handshake',
|
||||
headers = [start, this._headers.toString(), ''];
|
||||
|
||||
@@ -58,16 +76,11 @@ var instance = {
|
||||
_handshakeSignature: function() {
|
||||
if (this._body.length < this.BODY_SIZE) return null;
|
||||
|
||||
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'),
|
||||
buffer = new Buffer(8 + this.BODY_SIZE);
|
||||
var md5 = crypto.createHash('md5'),
|
||||
buffer = new Buffer(8 + this.BODY_SIZE);
|
||||
|
||||
buffer.writeUInt32BE(value1, 0);
|
||||
buffer.writeUInt32BE(value2, 4);
|
||||
buffer.writeUInt32BE(this._keyValues[0], 0);
|
||||
buffer.writeUInt32BE(this._keyValues[1], 4);
|
||||
new Buffer(this._body).copy(buffer, 8, 0, this.BODY_SIZE);
|
||||
|
||||
md5.update(buffer);
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
, "keywords" : ["websocket"]
|
||||
, "license" : "MIT"
|
||||
|
||||
, "version" : "0.6.2"
|
||||
, "version" : "0.6.3"
|
||||
, "engines" : {"node": ">=0.6.0"}
|
||||
, "main" : "./lib/websocket/driver"
|
||||
, "dependencies" : {"websocket-extensions": ">=0.1.1"}
|
||||
|
||||
@@ -109,6 +109,16 @@ test.describe("Client", function() { with(this) {
|
||||
}})
|
||||
}})
|
||||
|
||||
describe("with an invalid URL", function() { with(this) {
|
||||
define("url", function() { return "stream.wikimedia.org/rc" })
|
||||
|
||||
it("throws an error", function() { with(this) {
|
||||
var message
|
||||
try { driver() } catch (e) { message = e.message }
|
||||
assertEqual( "stream.wikimedia.org/rc is not a valid WebSocket URL", message )
|
||||
}})
|
||||
}})
|
||||
|
||||
describe("with custom headers", function() { with(this) {
|
||||
before(function() { with(this) {
|
||||
driver().setHeader("User-Agent", "Chrome")
|
||||
|
||||
@@ -34,6 +34,7 @@ test.describe("Draft76", function() { with(this) {
|
||||
var self = this
|
||||
this._driver.on('open', function(e) { self.open = true })
|
||||
this._driver.on('message', function(e) { self.message += e.data })
|
||||
this._driver.on('error', function(e) { self.error = e })
|
||||
this._driver.on('close', function(e) { self.close = true })
|
||||
this._driver.io.pipe(this.collector())
|
||||
this._driver.io.write(this.body())
|
||||
@@ -81,6 +82,37 @@ test.describe("Draft76", function() { with(this) {
|
||||
driver().start()
|
||||
assertEqual( "hixie-76", driver().version )
|
||||
}})
|
||||
|
||||
describe("with an invalid key header", function() { with(this) {
|
||||
before(function() { with(this) {
|
||||
request().headers["sec-websocket-key1"] = "2 L785 8o% s9Sy9@V. 4<1P5"
|
||||
}})
|
||||
|
||||
it("writes a closing frame to the socket", function() { with(this) {
|
||||
expect(driver().io, "emit").given("data", buffer([0xff, 0x00]))
|
||||
driver().start()
|
||||
}})
|
||||
|
||||
it("does not trigger the onopen event", function() { with(this) {
|
||||
driver().start()
|
||||
assertEqual( false, open )
|
||||
}})
|
||||
|
||||
it("triggers the onerror event", function() { with(this) {
|
||||
driver().start()
|
||||
assertEqual( "Client sent invalid Sec-WebSocket-Key headers", error.message )
|
||||
}})
|
||||
|
||||
it("triggers the onclose event", function() { with(this) {
|
||||
driver().start()
|
||||
assertEqual( true, close )
|
||||
}})
|
||||
|
||||
it("changes the state to closed", function() { with(this) {
|
||||
driver().start()
|
||||
assertEqual( "closed", driver().getState() )
|
||||
}})
|
||||
}})
|
||||
}})
|
||||
|
||||
describe("frame", function() { with(this) {
|
||||
|
||||
Reference in New Issue
Block a user