faye-websocket 0.4.7 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
@@ -1,78 +0,0 @@
1
- module Faye
2
- class WebSocket
3
- class HybiParser
4
-
5
- class Handshake
6
- GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
7
-
8
- attr_reader :protocol
9
-
10
- def initialize(uri, protocols)
11
- @uri = uri
12
- @protocols = protocols
13
- @key = Base64.encode64((1..16).map { rand(255).chr } * '').strip
14
- @accept = Base64.encode64(Digest::SHA1.digest(@key + GUID)).strip
15
- @buffer = []
16
- end
17
-
18
- def request_data
19
- hostname = @uri.host + (@uri.port ? ":#{@uri.port}" : '')
20
- path = (@uri.path == '') ? '/' : @uri.path
21
- headers = [
22
- "GET #{path}#{@uri.query ? '?' : ''}#{@uri.query} HTTP/1.1",
23
- "Host: #{hostname}",
24
- "Upgrade: websocket",
25
- "Connection: Upgrade",
26
- "Sec-WebSocket-Key: #{@key}",
27
- "Sec-WebSocket-Version: 13"
28
- ]
29
-
30
- if @protocols
31
- headers << "Sec-WebSocket-Protocol: #{@protocols * ', '}"
32
- end
33
-
34
- (headers + ['','']).join("\r\n")
35
- end
36
-
37
- def parse(data)
38
- message = []
39
- complete = false
40
- data.each_byte do |byte|
41
- if complete
42
- message << byte
43
- else
44
- @buffer << byte
45
- complete ||= complete?
46
- end
47
- end
48
- message
49
- end
50
-
51
- def complete?
52
- @buffer[-4..-1] == [0x0D, 0x0A, 0x0D, 0x0A]
53
- end
54
-
55
- def valid?
56
- data = WebSocket.encode(@buffer)
57
-
58
- response = Net::HTTPResponse.read_new(Net::BufferedIO.new(StringIO.new(data)))
59
- return false unless response.code.to_i == 101
60
-
61
- upgrade = response['Upgrade']
62
- connection = response['Connection']
63
- protocol = response['Sec-WebSocket-Protocol']
64
-
65
- @protocol = @protocols && @protocols.include?(protocol) ?
66
- protocol :
67
- nil
68
-
69
- upgrade and upgrade =~ /^websocket$/i and
70
- connection and connection.split(/\s*,\s*/).include?('Upgrade') and
71
- ((!@protocols and !protocol) or @protocol) and
72
- response['Sec-WebSocket-Accept'] == @accept
73
- end
74
- end
75
-
76
- end
77
- end
78
- end
@@ -1,29 +0,0 @@
1
- module Faye
2
- class WebSocket
3
- class HybiParser
4
-
5
- class StreamReader
6
- def initialize
7
- @queue = []
8
- end
9
-
10
- def read(length)
11
- read_bytes(length)
12
- end
13
-
14
- def put(bytes)
15
- return unless bytes and bytes.size > 0
16
- @queue.concat(bytes)
17
- end
18
-
19
- private
20
-
21
- def read_bytes(length)
22
- return nil if length > @queue.size
23
- @queue.shift(length)
24
- end
25
- end
26
-
27
- end
28
- end
29
- end
@@ -1,8 +0,0 @@
1
- module Faye
2
- class WebSocket
3
-
4
- # http://www.w3.org/International/questions/qa-forms-utf-8.en.php
5
- UTF8_MATCH = /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/
6
-
7
- end
8
- end
@@ -1,162 +0,0 @@
1
- # encoding=utf-8
2
-
3
- require "spec_helper"
4
-
5
- WebSocketSteps = EM::RSpec.async_steps do
6
- def server(port, backend, secure, &callback)
7
- @server = EchoServer.new
8
- @server.listen(port, backend, secure)
9
- @port = port
10
- EM.add_timer(0.1, &callback)
11
- end
12
-
13
- def stop(&callback)
14
- @server.stop
15
- EM.next_tick(&callback)
16
- end
17
-
18
- def open_socket(url, protocols, &callback)
19
- done = false
20
-
21
- resume = lambda do |open|
22
- unless done
23
- done = true
24
- @open = open
25
- callback.call
26
- end
27
- end
28
-
29
- @ws = Faye::WebSocket::Client.new(url, protocols)
30
-
31
- @ws.onopen = lambda { |e| resume.call(true) }
32
- @ws.onclose = lambda { |e| resume.call(false) }
33
- end
34
-
35
- def close_socket(&callback)
36
- @ws.onclose = lambda do |e|
37
- @open = false
38
- callback.call
39
- end
40
- @ws.close
41
- end
42
-
43
- def check_open(&callback)
44
- @open.should == true
45
- callback.call
46
- end
47
-
48
- def check_closed(&callback)
49
- @open.should == false
50
- callback.call
51
- end
52
-
53
- def check_protocol(protocol, &callback)
54
- @ws.protocol.should == protocol
55
- callback.call
56
- end
57
-
58
- def listen_for_message(&callback)
59
- @ws.add_event_listener('message', lambda { |e| @message = e.data })
60
- callback.call
61
- end
62
-
63
- def send_message(message, &callback)
64
- @ws.send(message)
65
- EM.add_timer(0.1, &callback)
66
- end
67
-
68
- def check_response(message, &callback)
69
- @message.should == message
70
- callback.call
71
- end
72
-
73
- def check_no_response(&callback)
74
- @message.should == nil
75
- callback.call
76
- end
77
- end
78
-
79
- describe Faye::WebSocket::Client do
80
- next if Faye::WebSocket.jruby?
81
- include WebSocketSteps
82
-
83
- let(:protocols) { ["foo", "echo"] }
84
- let(:plain_text_url) { "ws://0.0.0.0:8000/" }
85
- let(:secure_url) { "wss://0.0.0.0:8000/" }
86
-
87
- shared_examples_for "socket client" do
88
- it "can open a connection" do
89
- open_socket(socket_url, protocols)
90
- check_open
91
- check_protocol("echo")
92
- end
93
-
94
- it "cannot open a connection to the wrong host" do
95
- open_socket(blocked_url, protocols)
96
- check_closed
97
- end
98
-
99
- it "cannot open a connection with unacceptable protocols" do
100
- open_socket(socket_url, ["foo"])
101
- check_closed
102
- end
103
-
104
- it "can close the connection" do
105
- open_socket(socket_url, protocols)
106
- close_socket
107
- check_closed
108
- end
109
-
110
- describe "in the OPEN state" do
111
- before { open_socket(socket_url, protocols) }
112
-
113
- it "can send and receive messages" do
114
- listen_for_message
115
- send_message "I expect this to be echoed"
116
- check_response "I expect this to be echoed"
117
- end
118
-
119
- it "sends numbers as strings" do
120
- listen_for_message
121
- send_message 13
122
- check_response "13"
123
- end
124
- end
125
-
126
- describe "in the CLOSED state" do
127
- before do
128
- open_socket(socket_url, protocols)
129
- close_socket
130
- end
131
-
132
- it "cannot send and receive messages" do
133
- listen_for_message
134
- send_message "I expect this to be echoed"
135
- check_no_response
136
- end
137
- end
138
- end
139
-
140
- describe "with a plain-text Thin server" do
141
- let(:socket_url) { plain_text_url }
142
- let(:blocked_url) { secure_url }
143
-
144
- before { server 8000, :thin, false }
145
- after { stop }
146
-
147
- it_should_behave_like "socket client"
148
- end
149
-
150
- describe "with a secure Thin server" do
151
- next if Faye::WebSocket.rbx?
152
-
153
- let(:socket_url) { secure_url }
154
- let(:blocked_url) { plain_text_url }
155
-
156
- before { server 8000, :thin, true }
157
- after { stop }
158
-
159
- it_should_behave_like "socket client"
160
- end
161
- end
162
-
@@ -1,48 +0,0 @@
1
- # encoding=utf-8
2
-
3
- require "spec_helper"
4
-
5
- shared_examples_for "draft-75 parser" do
6
- it "parses text frames" do
7
- @web_socket.should_receive(:receive).with("Hello")
8
- parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
9
- end
10
-
11
- it "parses multiple frames from the same packet" do
12
- @web_socket.should_receive(:receive).with("Hello").exactly(2)
13
- parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
14
- end
15
-
16
- it "parses text frames beginning 0x00-0x7F" do
17
- @web_socket.should_receive(:receive).with("Hello")
18
- parse [0x66, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
19
- end
20
-
21
- it "ignores frames with a length header" do
22
- @web_socket.should_not_receive(:receive)
23
- parse [0x80, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
24
- end
25
-
26
- it "parses text following an ignored block" do
27
- @web_socket.should_receive(:receive).with("Hello")
28
- parse [0x80, 0x02, 0x48, 0x65, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
29
- end
30
-
31
- it "parses multibyte text frames" do
32
- @web_socket.should_receive(:receive).with(encode "Apple = ")
33
- parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
34
- end
35
-
36
- it "parses frames received in several packets" do
37
- @web_socket.should_receive(:receive).with(encode "Apple = ")
38
- parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65]
39
- parse [0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
40
- end
41
-
42
- it "parses fragmented frames" do
43
- @web_socket.should_receive(:receive).with("Hello")
44
- parse [0x00, 0x48, 0x65, 0x6c]
45
- parse [0x6c, 0x6f, 0xff]
46
- end
47
- end
48
-
@@ -1,27 +0,0 @@
1
- # encoding=utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Faye::WebSocket::Draft75Parser do
6
- include EncodingHelper
7
-
8
- before do
9
- @web_socket = mock Faye::WebSocket
10
- @parser = Faye::WebSocket::Draft75Parser.new(@web_socket)
11
- end
12
-
13
- describe :parse do
14
- it_should_behave_like "draft-75 parser"
15
- end
16
-
17
- describe :frame do
18
- it "returns the given string formatted as a WebSocket frame" do
19
- bytes(@parser.frame "Hello").should == [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
20
- end
21
-
22
- it "encodes multibyte characters correctly" do
23
- message = encode "Apple = "
24
- bytes(@parser.frame message).should == [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
25
- end
26
- end
27
- end
@@ -1,34 +0,0 @@
1
- # encoding=utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Faye::WebSocket::Draft76Parser do
6
- include EncodingHelper
7
-
8
- before do
9
- @web_socket = mock Faye::WebSocket
10
- @parser = Faye::WebSocket::Draft76Parser.new(@web_socket)
11
- @parser.instance_eval { @handshake_complete = true }
12
- end
13
-
14
- describe :parse do
15
- it_should_behave_like "draft-75 parser"
16
-
17
- it "closes the socket if a close frame is received" do
18
- @web_socket.should_receive(:close)
19
- parse [0xFF, 0x00]
20
- end
21
- end
22
-
23
- describe :frame do
24
- it "returns the given string formatted as a WebSocket frame" do
25
- bytes(@parser.frame "Hello").should == [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
26
- end
27
-
28
- it "encodes multibyte characters correctly" do
29
- message = encode "Apple = "
30
- bytes(@parser.frame message).should == [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
31
- end
32
- end
33
- end
34
-
@@ -1,149 +0,0 @@
1
- # encoding=utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Faye::WebSocket::HybiParser do
6
- include EncodingHelper
7
-
8
- before do
9
- @web_socket = mock Faye::WebSocket
10
- @parser = Faye::WebSocket::HybiParser.new(@web_socket)
11
- end
12
-
13
- describe :parse do
14
- let(:mask) { (1..4).map { rand 255 } }
15
-
16
- def mask_message(*bytes)
17
- output = []
18
- bytes.each_with_index do |byte, i|
19
- output[i] = byte ^ mask[i % 4]
20
- end
21
- output
22
- end
23
-
24
- it "parses unmasked text frames" do
25
- @web_socket.should_receive(:receive).with("Hello")
26
- parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
27
- end
28
-
29
- it "parses multiple frames from the same packet" do
30
- @web_socket.should_receive(:receive).with("Hello").exactly(2)
31
- parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
32
- end
33
-
34
- it "parses empty text frames" do
35
- @web_socket.should_receive(:receive).with("")
36
- parse [0x81, 0x00]
37
- end
38
-
39
- it "parses fragmented text frames" do
40
- @web_socket.should_receive(:receive).with("Hello")
41
- parse [0x01, 0x03, 0x48, 0x65, 0x6c]
42
- parse [0x80, 0x02, 0x6c, 0x6f]
43
- end
44
-
45
- it "parses masked text frames" do
46
- @web_socket.should_receive(:receive).with("Hello")
47
- parse [0x81, 0x85] + mask + mask_message(0x48, 0x65, 0x6c, 0x6c, 0x6f)
48
- end
49
-
50
- it "parses masked empty text frames" do
51
- @web_socket.should_receive(:receive).with("")
52
- parse [0x81, 0x80] + mask + mask_message()
53
- end
54
-
55
- it "parses masked fragmented text frames" do
56
- @web_socket.should_receive(:receive).with("Hello")
57
- parse [0x01, 0x81] + mask + mask_message(0x48)
58
- parse [0x80, 0x84] + mask + mask_message(0x65, 0x6c, 0x6c, 0x6f)
59
- end
60
-
61
- it "closes the socket if the frame has an unrecognized opcode" do
62
- @web_socket.should_receive(:close).with(1002, nil, false)
63
- parse [0x83, 0x00]
64
- end
65
-
66
- it "closes the socket if a close frame is received" do
67
- @web_socket.should_receive(:close).with(1000, "Hello", false)
68
- parse [0x88, 0x07, 0x03, 0xe8, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
69
- end
70
-
71
- it "parses unmasked multibyte text frames" do
72
- @web_socket.should_receive(:receive).with(encode "Apple = ")
73
- parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
74
- end
75
-
76
- it "parses frames received in several packets" do
77
- @web_socket.should_receive(:receive).with(encode "Apple = ")
78
- parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c]
79
- parse [0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
80
- end
81
-
82
- it "parses fragmented multibyte text frames" do
83
- @web_socket.should_receive(:receive).with(encode "Apple = ")
84
- parse [0x01, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3]
85
- parse [0x80, 0x01, 0xbf]
86
- end
87
-
88
- it "parses masked multibyte text frames" do
89
- @web_socket.should_receive(:receive).with(encode "Apple = ")
90
- parse [0x81, 0x8b] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf)
91
- end
92
-
93
- it "parses masked fragmented multibyte text frames" do
94
- @web_socket.should_receive(:receive).with(encode "Apple = ")
95
- parse [0x01, 0x8a] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3)
96
- parse [0x80, 0x81] + mask + mask_message(0xbf)
97
- end
98
-
99
- it "parses unmasked medium-length text frames" do
100
- @web_socket.should_receive(:receive).with("Hello" * 40)
101
- parse [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
102
- end
103
-
104
- it "parses masked medium-length text frames" do
105
- @web_socket.should_receive(:receive).with("Hello" * 40)
106
- parse [0x81, 0xfe, 0x00, 0xc8] + mask + mask_message(*([0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40))
107
- end
108
-
109
- it "replies to pings with a pong" do
110
- @web_socket.should_receive(:send).with([0x4f, 0x48, 0x41, 0x49], :pong)
111
- parse [0x89, 0x04, 0x4f, 0x48, 0x41, 0x49]
112
- end
113
- end
114
-
115
- describe :frame do
116
- it "returns the given string formatted as a WebSocket frame" do
117
- bytes(@parser.frame "Hello").should == [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
118
- end
119
-
120
- it "encodes multibyte characters correctly" do
121
- message = encode "Apple = "
122
- bytes(@parser.frame message).should == [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
123
- end
124
-
125
- it "encodes medium-length strings using extra length bytes" do
126
- message = "Hello" * 40
127
- bytes(@parser.frame message).should == [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
128
- end
129
-
130
- it "encodes close frames with an error code" do
131
- frame = @parser.frame "Hello", :close, 1002
132
- bytes(frame).should == [0x88, 0x07, 0x03, 0xea, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
133
- end
134
-
135
- it "encodes pong frames" do
136
- bytes(@parser.frame '', :pong).should == [0x8a, 0x00]
137
- end
138
- end
139
-
140
- describe :utf8 do
141
- it "detects valid UTF-8" do
142
- Faye::WebSocket.valid_utf8?( [72, 101, 108, 108, 111, 45, 194, 181, 64, 195, 159, 195, 182, 195, 164, 195, 188, 195, 160, 195, 161, 45, 85, 84, 70, 45, 56, 33, 33] ).should be_true
143
- end
144
-
145
- it "detects invalid UTF-8" do
146
- Faye::WebSocket.valid_utf8?( [206, 186, 225, 189, 185, 207, 131, 206, 188, 206, 181, 237, 160, 128, 101, 100, 105, 116, 101, 100] ).should be_false
147
- end
148
- end
149
- end