Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 157 lines (129 sloc) 4.61 kB
cf820c5 @majek Add a license block to source files
majek authored
1 # ***** BEGIN LICENSE BLOCK *****
2 # Copyright (c) 2011-2012 VMware, Inc.
3 #
4 # For the license see COPYING.
5 # ***** END LICENSE BLOCK *****
6
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
7 FayeWebsocket = require('faye-websocket')
8
69d1e7f @majek Initial commit
majek authored
9 utils = require('./utils')
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
10 transport = require('./transport')
69d1e7f @majek Initial commit
majek authored
11
b74e0cc @majek Simplifying transports, everything is now a polling transport.
majek authored
12
69d1e7f @majek Initial commit
majek authored
13 exports.app =
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
14 _websocket_check: (req, connection, head) ->
1c4bed6 @brycekahle Use faye for websocket request checks. No need to duplicate them.
brycekahle authored
15 if not FayeWebsocket.isWebSocket(req)
69d1e7f @majek Initial commit
majek authored
16 throw {
04b3351 @majek All websocket errors should end with 400.
majek authored
17 status: 400
1c4bed6 @brycekahle Use faye for websocket request checks. No need to duplicate them.
brycekahle authored
18 message: 'Not a valid websocket request'
69d1e7f @majek Initial commit
majek authored
19 }
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
20
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
21 sockjs_websocket: (req, connection, head) ->
22 @_websocket_check(req, connection, head)
dfd84b8 @glasser Allow specifying options to Faye constructor
glasser authored
23 ws = new FayeWebsocket(req, connection, head, null,
24 @options.faye_server_options)
378c795 @majek Use faye 0.4, update code to use ws.onopen faye callback.
majek authored
25 ws.onopen = =>
26 # websockets possess no session_id
27 transport.registerNoSession(req, @,
28 new WebSocketReceiver(ws, connection))
69d1e7f @majek Initial commit
majek authored
29 return true
ab2c7aa @majek support for websockets hybi-10, ie: new firefox and development chrome
majek authored
30
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
31 raw_websocket: (req, connection, head) ->
32 @_websocket_check(req, connection, head)
33 ver = req.headers['sec-websocket-version'] or ''
d9ed0e5 @majek Cosmetic
majek authored
34 if ['8', '13'].indexOf(ver) is -1
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
35 throw {
36 status: 400
37 message: 'Only supported WebSocket protocol is RFC 6455.'
38 }
dfd84b8 @glasser Allow specifying options to Faye constructor
glasser authored
39 ws = new FayeWebsocket(req, connection, head, null,
40 @options.faye_server_options)
378c795 @majek Use faye 0.4, update code to use ws.onopen faye callback.
majek authored
41 ws.onopen = =>
42 new RawWebsocketSessionReceiver(req, connection, @, ws)
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
43 return true
44
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
45
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
46 class WebSocketReceiver extends transport.GenericReceiver
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
47 protocol: "websocket"
48
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
49 constructor: (@ws, @connection) ->
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
50 try
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
51 @connection.setKeepAlive(true, 5000)
52 @connection.setNoDelay(true)
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
53 catch x
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
54 @ws.addEventListener('message', (m) => @didMessage(m.data))
8c12b38 @brycekahle #129, #162 add ws ping-pong and close if no response
brycekahle authored
55 @heartbeat_cb = => @heartbeat_timeout()
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
56 super @connection
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
57
58 setUp: ->
59 super
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
60 @ws.addEventListener('close', @thingy_end_cb)
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
61
62 tearDown: ->
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
63 @ws.removeEventListener('close', @thingy_end_cb)
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
64 super
65
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
66 didMessage: (payload) ->
67 if @ws and @session and payload.length > 0
68 try
69 message = JSON.parse(payload)
70 catch x
7489fc6 @brycekahle Upgrade to faye-websocket 0.10.0 and use proper close code
brycekahle authored
71 return @didClose(3000, 'Broken framing.')
7010788 @majek Fix #58 - don't emit an array - always a string
majek authored
72 if payload[0] is '['
73 for msg in message
74 @session.didMessage(msg)
75 else
76 @session.didMessage(message)
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
77
78 doSendFrame: (payload) ->
79 if @ws
80 try
81 @ws.send(payload)
82 return true
b28bd76 @majek #93 - cosmetic - unify "catch" statement
majek authored
83 catch x
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
84 return false
85
204b18f @brycekahle Fix websocket bad json tests
brycekahle authored
86 didClose: (status=1000, reason="Normal closure") ->
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
87 super
88 try
204b18f @brycekahle Fix websocket bad json tests
brycekahle authored
89 @ws.close(status, reason, false)
75144c1 @majek Fix #36 - Use faye-websocket websocket server implementation
majek authored
90 catch x
91 @ws = null
283decf @majek #36 - Emergency fix for being incompetent. (via @shripadk)
majek authored
92 @connection = null
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
93
8c12b38 @brycekahle #129, #162 add ws ping-pong and close if no response
brycekahle authored
94 heartbeat: ->
95 supportsHeartbeats = @ws.ping null, ->
96 clearTimeout(hto_ref)
97
98 if supportsHeartbeats
99 hto_ref = setTimeout(@heartbeat_cb, 10000)
100 else
101 super
102
103 heartbeat_timeout: ->
104 @session.close(3000, 'No response from heartbeat')
105
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
106
107
108 Transport = transport.Transport
109
110 # Inheritance only for decorateConnection.
111 class RawWebsocketSessionReceiver extends transport.Session
112 constructor: (req, conn, server, @ws) ->
113 @prefix = server.options.prefix
114 @readyState = Transport.OPEN
98a3c9d @glasser Correct version of 73c3e3.
glasser authored
115 @recv = {connection: conn, protocol: "websocket-raw"}
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
116
117 @connection = new transport.SockJSConnection(@)
118 @decorateConnection(req)
119 server.emit('connection', @connection)
120 @_end_cb = => @didClose()
121 @ws.addEventListener('close', @_end_cb)
122 @_message_cb = (m) => @didMessage(m)
123 @ws.addEventListener('message', @_message_cb)
124
125 didMessage: (m) ->
126 if @readyState is Transport.OPEN
127 @connection.emit('data', m.data)
128 return
129
130 send: (payload) ->
131 if @readyState isnt Transport.OPEN
132 return false
133 @ws.send(payload)
134 return true
135
136 close: (status=1000, reason="Normal closure") ->
137 if @readyState isnt Transport.OPEN
138 return false
139 @readyState = Transport.CLOSING
d94a2e6 @majek #99 - Never require client to send back an acknowledgment for ws closure
majek authored
140 @ws.close(status, reason, false)
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
141 return true
142
143 didClose: ->
f29fb5b @majek Fix #75 - raw websockets never emitted close event
majek authored
144 if not @ws
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
145 return
146 @ws.removeEventListener('message', @_message_cb)
147 @ws.removeEventListener('close', @_end_cb)
148 try
d94a2e6 @majek #99 - Never require client to send back an acknowledgment for ws closure
majek authored
149 @ws.close(1000, "Normal closure", false)
e203719 @majek sockjs/sockjs-protocol#35 - Support raw websocket /websocket interface
majek authored
150 catch x
151 @ws = null
f29fb5b @majek Fix #75 - raw websockets never emitted close event
majek authored
152
153 @readyState = Transport.CLOSED
154 @connection.emit('end')
155 @connection.emit('close')
156 @connection = null
Something went wrong with that request. Please try again.