diff --git a/lib/websocket/driver/base.js b/lib/websocket/driver/base.js index dd61457..e4a07e2 100644 --- a/lib/websocket/driver/base.js +++ b/lib/websocket/driver/base.js @@ -77,7 +77,9 @@ var instance = { start: function() { if (this.readyState !== 0) return false; - this._write(this._handshakeResponse()); + var response = this._handshakeResponse(); + if (!response) return false; + this._write(response); if (this._stage !== -1) this._open(); return true; }, diff --git a/lib/websocket/driver/hybi.js b/lib/websocket/driver/hybi.js index 38c77d1..eaab7bf 100644 --- a/lib/websocket/driver/hybi.js +++ b/lib/websocket/driver/hybi.js @@ -281,7 +281,12 @@ var instance = { }, _handshakeResponse: function() { - var extensions = this._extensions.generateResponse(this._request.headers['sec-websocket-extensions']); + try { + var extensions = this._extensions.generateResponse(this._request.headers['sec-websocket-extensions']); + } catch (e) { + return this._fail('protocol_error', e.message); + } + if (extensions) this._headers.set('Sec-WebSocket-Extensions', extensions); var start = 'HTTP/1.1 101 Switching Protocols', @@ -294,12 +299,12 @@ var instance = { delete this._frame; delete this._message; - var wasOpen = this.readyState < 2; + var sendCloseFrame = (this.readyState === 1); this.readyState = 2; this._stage = 5; this._extensions.close(function() { - if (wasOpen) this.frame(reason, 'close', code); + if (sendCloseFrame) this.frame(reason, 'close', code); this.readyState = 3; this.emit('close', new Base.CloseEvent(code, reason)); }, this); diff --git a/spec/websocket/driver/hybi_spec.js b/spec/websocket/driver/hybi_spec.js index 537c436..f6beb50 100644 --- a/spec/websocket/driver/hybi_spec.js +++ b/spec/websocket/driver/hybi_spec.js @@ -79,6 +79,37 @@ test.describe("Hybi", function() { with(this) { }}) }}) + describe("with invalid extensions", function() { with(this) { + before(function() { with(this) { + request().headers["sec-websocket-extensions"] = "x-webkit- -frame" + }}) + + it("does not write a handshake", function() { with(this) { + expect(driver().io, "emit").exactly(0) + 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( "Invalid Sec-WebSocket-Extensions header: x-webkit- -frame", error.message ) + }}) + + it("triggers the onclose event", function() { with(this) { + driver().start() + assertEqual( [1002, "Invalid Sec-WebSocket-Extensions header: x-webkit- -frame"], close ) + }}) + + it("changes the state to closed", function() { with(this) { + driver().start() + assertEqual( "closed", driver().getState() ) + }}) + }}) + describe("with custom headers", function() { with(this) { before(function() { with(this) { driver().setHeader("Authorization", "Bearer WAT")