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
@@ -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