faye-websocket 0.4.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of faye-websocket might be problematic. Click here for more details.

Files changed (38) hide show
  1. data/CHANGELOG.md +81 -0
  2. data/README.md +408 -0
  3. data/examples/app.rb +4 -1
  4. data/examples/autobahn_client.rb +8 -6
  5. data/examples/client.rb +2 -1
  6. data/examples/config.ru +6 -9
  7. data/{spec → examples}/rainbows.conf +0 -0
  8. data/examples/server.rb +10 -1
  9. data/lib/faye/adapters/rainbows.rb +15 -16
  10. data/lib/faye/adapters/rainbows_client.rb +15 -16
  11. data/lib/faye/adapters/thin.rb +15 -16
  12. data/lib/faye/eventsource.rb +38 -46
  13. data/lib/faye/rack_stream.rb +70 -0
  14. data/lib/faye/websocket.rb +39 -162
  15. data/lib/faye/websocket/api.rb +70 -60
  16. data/lib/faye/websocket/api/event.rb +1 -1
  17. data/lib/faye/websocket/api/event_target.rb +35 -12
  18. data/lib/faye/websocket/client.rb +5 -38
  19. metadata +62 -45
  20. data/CHANGELOG.txt +0 -74
  21. data/README.rdoc +0 -366
  22. data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +0 -61
  23. data/ext/faye_websocket_mask/extconf.rb +0 -5
  24. data/ext/faye_websocket_mask/faye_websocket_mask.c +0 -33
  25. data/lib/faye/websocket/draft75_parser.rb +0 -87
  26. data/lib/faye/websocket/draft76_parser.rb +0 -84
  27. data/lib/faye/websocket/hybi_parser.rb +0 -321
  28. data/lib/faye/websocket/hybi_parser/handshake.rb +0 -78
  29. data/lib/faye/websocket/hybi_parser/stream_reader.rb +0 -29
  30. data/lib/faye/websocket/utf8_match.rb +0 -8
  31. data/spec/faye/websocket/client_spec.rb +0 -162
  32. data/spec/faye/websocket/draft75_parser_examples.rb +0 -48
  33. data/spec/faye/websocket/draft75_parser_spec.rb +0 -27
  34. data/spec/faye/websocket/draft76_parser_spec.rb +0 -34
  35. data/spec/faye/websocket/hybi_parser_spec.rb +0 -149
  36. data/spec/server.crt +0 -15
  37. data/spec/server.key +0 -15
  38. data/spec/spec_helper.rb +0 -68
data/CHANGELOG.md ADDED
@@ -0,0 +1,81 @@
1
+ ### 0.5.0 / 2013-05-05
2
+
3
+ * Extract the protocol handlers into the `websocket-driver` library
4
+ * Support the `rack.hijack` API
5
+ * Add support for Rainbows 4.5 and Puma
6
+ * Officially support JRuby and Rubinius
7
+
8
+
9
+ ### 0.4.7 / 2013-02-14
10
+
11
+ * Emit the `close` event if TCP is closed before CLOSE frame is acked
12
+ * Treat the `Upgrade: websocket` header case-insensitively because of IE10
13
+ * Don not suppress headers in the Thin and Rainbows adapters unless the status is `101`
14
+
15
+
16
+ ### 0.4.6 / 2012-07-09
17
+
18
+ * Add `Connection: close` to EventSource response
19
+
20
+
21
+ ### 0.4.5 / 2012-04-06
22
+
23
+ * Add WebSocket error code `1011`.
24
+ * Handle URLs with no path correctly by sending `GET /`
25
+
26
+
27
+ ### 0.4.4 / 2012-03-16
28
+
29
+ * Fix installation on JRuby with a platform-specific gem
30
+
31
+
32
+ ### 0.4.3 / 2012-03-12
33
+
34
+ * Make `extconf.rb` a no-op on JRuby
35
+
36
+
37
+ ### 0.4.2 / 2012-03-09
38
+
39
+ * Port masking-function C extension to Java for JRuby
40
+
41
+
42
+ ### 0.4.1 / 2012-02-26
43
+
44
+ * Treat anything other than an `Array` as a string when calling `send()`
45
+ * Fix error loading UTF-8 validation code on Ruby 1.9 with `-Ku` flag
46
+
47
+
48
+ ### 0.4.0 / 2012-02-13
49
+
50
+ * Add `ping()` method to server-side `WebSocket` and `EventSource`
51
+ * Buffer `send()` calls until the draft-76 handshake is complete
52
+
53
+
54
+ ### 0.3.0 / 2012-01-13
55
+
56
+ * Add support for `EventSource` connections
57
+ * Support the Thin, Rainbows and Goliath web servers
58
+
59
+
60
+ ### 0.2.0 / 2011-12-21
61
+
62
+ * Add support for `Sec-WebSocket-Protocol` negotiation
63
+ * Support `hixie-76` close frames and 75/76 ignored segments
64
+ * Improve performance of HyBi parsing/framing functions
65
+ * Write masking function in C
66
+
67
+
68
+ ### 0.1.2 / 2011-12-05
69
+
70
+ * Make `hixie-76` sockets work through HAProxy
71
+
72
+
73
+ ### 0.1.1 / 2011-11-30
74
+
75
+ * Fix `add_event_listener()` interface methods
76
+
77
+
78
+ ### 0.1.0 / 2011-11-27
79
+
80
+ * Initial release, based on WebSocket components from Faye
81
+
data/README.md ADDED
@@ -0,0 +1,408 @@
1
+ # faye-websocket
2
+
3
+ * Travis CI build: [![Build
4
+ status](https://secure.travis-ci.org/faye/faye-websocket-ruby.png)](http://travis-ci.org/faye/faye-websocket-ruby)
5
+ * Autobahn tests: [server](http://faye.jcoglan.com/autobahn/servers/),
6
+ [client](http://faye.jcoglan.com/autobahn/clients/)
7
+
8
+ This is a general-purpose WebSocket implementation extracted from the
9
+ [Faye](http://faye.jcoglan.com) project. It provides classes for easily
10
+ building WebSocket servers and clients in Ruby. It does not provide a server
11
+ itself, but rather makes it easy to handle WebSocket connections within an
12
+ existing [Rack](http://rack.rubyforge.org/) application. It does not provide
13
+ any abstraction other than the standard [WebSocket
14
+ API](http://dev.w3.org/html5/websockets/).
15
+
16
+ It also provides an abstraction for handling
17
+ [EventSource](http://dev.w3.org/html5/eventsource/) connections, which are
18
+ one-way connections that allow the server to push data to the client. They are
19
+ based on streaming HTTP responses and can be easier to access via proxies than
20
+ WebSockets.
21
+
22
+ The following web servers are supported. Other servers that implement the
23
+ `rack.hjiack` API should also work.
24
+
25
+ * [Goliath](http://postrank-labs.github.com/goliath/)
26
+ * [Puma](http://puma.io/)
27
+ * [Rainbows](http://rainbows.rubyforge.org/)
28
+ * [Thin](http://code.macournoyer.com/thin/)
29
+
30
+
31
+ ## Installation
32
+
33
+ ```
34
+ $ gem install faye-websocket
35
+ ```
36
+
37
+
38
+ ## Handling WebSocket connections in Rack
39
+
40
+ You can handle WebSockets on the server side by listening for requests using
41
+ the `Faye::WebSocket.websocket?` method, and creating a new socket for the
42
+ request. This socket object exposes the usual WebSocket methods for receiving
43
+ and sending messages. For example this is how you'd implement an echo server:
44
+
45
+ ```ruby
46
+ # app.rb
47
+ require 'faye/websocket'
48
+
49
+ App = lambda do |env|
50
+ if Faye::WebSocket.websocket?(env)
51
+ ws = Faye::WebSocket.new(env)
52
+
53
+ ws.on :message do |event|
54
+ ws.send(event.data)
55
+ end
56
+
57
+ ws.on :close do |event|
58
+ p [:close, event.code, event.reason]
59
+ ws = nil
60
+ end
61
+
62
+ # Return async Rack response
63
+ ws.rack_response
64
+
65
+ else
66
+ # Normal HTTP request
67
+ [200, {'Content-Type' => 'text/plain'}, ['Hello']]
68
+ end
69
+ end
70
+ ```
71
+
72
+ Note that under certain circumstances (notably a draft-76 client connecting
73
+ through an HTTP proxy), the WebSocket handshake will not be complete after you
74
+ call `Faye::WebSocket.new` because the server will not have received the entire
75
+ handshake from the client yet. In this case, calls to `ws.send` will buffer the
76
+ message in memory until the handshake is complete, at which point any buffered
77
+ messages will be sent to the client.
78
+
79
+ If you need to detect when the WebSocket handshake is complete, you can use the
80
+ `onopen` event.
81
+
82
+ If the connection's protocol version supports it, you can call `ws.ping()` to
83
+ send a ping message and wait for the client's response. This method takes a
84
+ message string, and an optional callback that fires when a matching pong
85
+ message is received. It returns `true` iff a ping message was sent. If the
86
+ client does not support ping/pong, this method sends no data and returns
87
+ `false`.
88
+
89
+ ```ruby
90
+ ws.ping 'Mic check, one, two' do
91
+ # fires when pong is received
92
+ end
93
+ ```
94
+
95
+
96
+ ## Using the WebSocket client
97
+
98
+ The client supports both the plain-text `ws` protocol and the encrypted `wss`
99
+ protocol, and has exactly the same interface as a socket you would use in a web
100
+ browser. On the wire it identifies itself as `hybi-13`.
101
+
102
+ ```ruby
103
+ require 'faye/websocket'
104
+ require 'eventmachine'
105
+
106
+ EM.run {
107
+ ws = Faye::WebSocket::Client.new('ws://www.example.com/')
108
+
109
+ ws.on :open do |event|
110
+ p [:open]
111
+ ws.send('Hello, world!')
112
+ end
113
+
114
+ ws.on :message do |event|
115
+ p [:message, event.data]
116
+ end
117
+
118
+ ws.on :close do |event|
119
+ p [:close, event.code, event.reason]
120
+ ws = nil
121
+ end
122
+ }
123
+ ```
124
+
125
+
126
+ ## Subprotocol negotiation
127
+
128
+ The WebSocket protocol allows peers to select and identify the application
129
+ protocol to use over the connection. On the client side, you can set which
130
+ protocols the client accepts by passing a list of protocol names when you
131
+ construct the socket:
132
+
133
+ ```ruby
134
+ ws = Faye::WebSocket::Client.new('ws://www.example.com/', ['irc', 'amqp'])
135
+ ```
136
+
137
+ On the server side, you can likewise pass in the list of protocols the server
138
+ supports after the other constructor arguments:
139
+
140
+ ```ruby
141
+ ws = Faye::WebSocket.new(env, ['irc', 'amqp'])
142
+ ```
143
+
144
+ If the client and server agree on a protocol, both the client- and server-side
145
+ socket objects expose the selected protocol through the `ws.protocol` property.
146
+
147
+
148
+ ## WebSocket API
149
+
150
+ Both the server- and client-side `WebSocket` objects support the following API:
151
+
152
+ * <b>`on(:open) { |event| }`</b> fires when the socket connection is
153
+ established. Event has no attributes.
154
+ * <b>`onerror`</b> fires when the connection attempt fails. Event has no
155
+ attributes.
156
+ * <b>`on(:message) { |event| }`</b> fires when the socket receives a message.
157
+ Event has one attribute, <b>`data`</b>, which is either a `String` (for text
158
+ frames) or an `Array` of byte-sized integers (for binary frames).
159
+ * <b>`on(:error) { |event| }`</b> fires when there is a protocol error due to
160
+ bad data sent by the other peer. This event is purely informational, you do
161
+ not need to implement error recovery.
162
+ * <b>`on(:close) { |event| }`</b> fires when either the client or the server
163
+ closes the connection. Event has two optional attributes, <b>`code`</b> and
164
+ <b>`reason`</b>, that expose the status code and message sent by the peer
165
+ that closed the connection.
166
+ * <b>`send(message)`</b> accepts either a `String` or an `Array` of byte-sized
167
+ integers and sends a text or binary message over the connection to the other
168
+ peer.
169
+ * <b>`ping(message = '', &callback)`</b> sends a ping frame with an optional
170
+ message and fires the callback when a matching pong is received.
171
+ * <b>`close`</b> closes the connection.
172
+ * <b>`version`</b> is a string containing the version of the `WebSocket`
173
+ protocol the connection is using.
174
+ * <b>`protocol`</b> is a string (which may be empty) identifying the
175
+ subprotocol the socket is using.
176
+
177
+
178
+ ## Handling EventSource connections in Rack
179
+
180
+ EventSource connections provide a very similar interface, although because they
181
+ only allow the server to send data to the client, there is no `onmessage` API.
182
+ EventSource allows the server to push text messages to the client, where each
183
+ message has an optional event-type and ID.
184
+
185
+ ```ruby
186
+ # app.rb
187
+ require 'faye/websocket'
188
+
189
+ App = lambda do |env|
190
+ if Faye::EventSource.eventsource?(env)
191
+ es = Faye::EventSource.new(env)
192
+ p [:open, es.url, es.last_event_id]
193
+
194
+ # Periodically send messages
195
+ loop = EM.add_periodic_timer(1) { es.send('Hello') }
196
+
197
+ es.on :close do |event|
198
+ EM.cancel_timer(loop)
199
+ es = nil
200
+ end
201
+
202
+ # Return async Rack response
203
+ es.rack_response
204
+
205
+ else
206
+ # Normal HTTP request
207
+ [200, {'Content-Type' => 'text/plain'}, ['Hello']]
208
+ end
209
+ end
210
+ ```
211
+
212
+ The `send` method takes two optional parameters, `:event` and `:id`. The
213
+ default event-type is `'message'` with no ID. For example, to send a
214
+ `notification` event with ID `99`:
215
+
216
+ ```ruby
217
+ es.send('Breaking News!', :event => 'notification', :id => '99')
218
+ ```
219
+
220
+ The `EventSource` object exposes the following properties:
221
+
222
+ * <b>`url`</b> is a string containing the URL the client used to create the
223
+ EventSource.
224
+ * <b>`last_event_id`</b> is a string containing the last event ID received by
225
+ the client. You can use this when the client reconnects after a dropped
226
+ connection to determine which messages need resending.
227
+
228
+ When you initialize an EventSource with `Faye::EventSource.new`, you can pass
229
+ configuration options after the `env` parameter. Available options are:
230
+
231
+ * <b>`:retry`</b> is a number that tells the client how long (in seconds) it
232
+ should wait after a dropped connection before attempting to reconnect.
233
+ * <b>`:ping`</b> is a number that tells the server how often (in seconds) to
234
+ send 'ping' packets to the client to keep the connection open, to defeat
235
+ timeouts set by proxies. The client will ignore these messages.
236
+
237
+ For example, this creates a connection that pings every 15 seconds and is
238
+ retryable every 10 seconds if the connection is broken:
239
+
240
+ ```ruby
241
+ es = Faye::EventSource.new(es, :ping => 15, :retry => 10)
242
+ ```
243
+
244
+ You can send a ping message at any time by calling `es.ping`. Unlike WebSocket
245
+ the client does not send a response to this; it is merely to send some data
246
+ over the wire to keep the connection alive.
247
+
248
+
249
+ ## Running your socket application
250
+
251
+ The following describes how to run a WebSocket application using all our
252
+ supported web servers.
253
+
254
+
255
+ ### Running the app with Thin
256
+
257
+ If you use Thin to server your application you need to include this line after
258
+ loading `faye/websocket`:
259
+
260
+ ```ruby
261
+ Faye::WebSocket.load_adapter('thin')
262
+ ```
263
+
264
+ Thin can be started via the command line if you've set up a `config.ru` file
265
+ for your application:
266
+
267
+ ```
268
+ $ thin start -R config.ru -p 9292
269
+ ```
270
+
271
+ Or, you can use `rackup`. In development mode, this adds middlewares that don't
272
+ work with async apps, so you must start it in production mode:
273
+
274
+ ```
275
+ $ rackup config.ru -s thin -E production -p 9292
276
+ ```
277
+
278
+ It can also be started using the `Rack::Handler` interface common to many Ruby
279
+ servers. It must be run using EventMachine, and you can configure Thin further
280
+ in a block passed to `run`:
281
+
282
+ ```ruby
283
+ require 'eventmachine'
284
+ require 'rack'
285
+ require 'thin'
286
+ require './app'
287
+
288
+ Faye::WebSocket.load_adapter('thin')
289
+
290
+ EM.run {
291
+ thin = Rack::Handler.get('thin')
292
+
293
+ thin.run(App, :Port => 9292) do |server|
294
+ # You can set options on the server here, for example to set up SSL:
295
+ server.ssl_options = {
296
+ :private_key_file => 'path/to/ssl.key',
297
+ :cert_chain_file => 'path/to/ssl.crt'
298
+ }
299
+ server.ssl = true
300
+ end
301
+ }
302
+ ```
303
+
304
+
305
+ ### Running the app with Puma
306
+
307
+ Puma has a command line interface for starting your application:
308
+
309
+ ```
310
+ $ puma config.ru -p 9292
311
+ ```
312
+
313
+
314
+ ### Running the app with Rainbows
315
+
316
+ If you're using version 4.4 or lower of Rainbows, you need to run it with the
317
+ EventMachine backend and enable the adapter. Put this in your `rainbows.conf`
318
+ file:
319
+
320
+ ```ruby
321
+ Rainbows! { use :EventMachine }
322
+ ```
323
+
324
+ And make sure you load the adapter in your application:
325
+
326
+ ```ruby
327
+ Faye::WebSocket.load_adapter('rainbows')
328
+ ```
329
+
330
+ Version 4.5 of Rainbows does not need this adapter.
331
+
332
+ You can run your `config.ru` file from the command line. Again, `Rack::Lint`
333
+ will complain unless you put the application in production mode.
334
+
335
+ ```
336
+ $ rainbows config.ru -c path/to/rainbows.conf -E production -p 9292
337
+ ```
338
+
339
+
340
+ ### Running the app with Goliath
341
+
342
+ If you use Goliath to server your application you need to include this line
343
+ after loading `faye/websocket`:
344
+
345
+ ```ruby
346
+ Faye::WebSocket.load_adapter('goliath')
347
+ ```
348
+
349
+ Goliath can be made to run arbitrary Rack apps by delegating to them from a
350
+ `Goliath::API` instance. A simple server looks like this:
351
+
352
+ ```ruby
353
+ require 'goliath'
354
+ require './app'
355
+ Faye::WebSocket.load_adapter('goliath')
356
+
357
+ class EchoServer < Goliath::API
358
+ def response(env)
359
+ App.call(env)
360
+ end
361
+ end
362
+ ```
363
+
364
+ `Faye::WebSocket` can also be used inline within a Goliath app:
365
+
366
+ ```ruby
367
+ require 'goliath'
368
+ require 'faye/websocket'
369
+ Faye::WebSocket.load_adapter('goliath')
370
+
371
+ class EchoServer < Goliath::API
372
+ def response(env)
373
+ ws = Faye::WebSocket.new(env)
374
+
375
+ ws.on :message do |event|
376
+ ws.send(event.data)
377
+ end
378
+
379
+ ws.rack_response
380
+ end
381
+ end
382
+ ```
383
+
384
+
385
+ ## License
386
+
387
+ (The MIT License)
388
+
389
+ Copyright (c) 2010-2013 James Coglan
390
+
391
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
392
+ this software and associated documentation files (the 'Software'), to deal in
393
+ the Software without restriction, including without limitation the rights to
394
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
395
+ of the Software, and to permit persons to whom the Software is furnished to do
396
+ so, subject to the following conditions:
397
+
398
+ The above copyright notice and this permission notice shall be included in all
399
+ copies or substantial portions of the Software.
400
+
401
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
402
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
403
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
404
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
405
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
406
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
407
+ SOFTWARE.
408
+