em-websocket-server 0.13 → 0.15

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.
@@ -1,29 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <title>em-websocket-server test</title>
5
- </head>
6
- <body>
7
-
8
- <h1>em-websocket-server timesync demo</h1>
9
- <h2 id="time">opening socket</h2>
10
-
11
- <script>
12
- var webSocket = new WebSocket('ws://localhost:8000/time');
13
-
14
- webSocket.onopen = function(event){
15
- document.getElementById('time').innerHTML = 'waiting for socket';
16
- };
17
-
18
- webSocket.onmessage = function(event){
19
- var object = JSON.parse(event.data);
20
- document.getElementById('time').innerHTML = object.time;
21
- };
22
-
23
- webSocket.onclose = function(event){
24
- document.getElementById('time').innerHTML = 'socket closed';
25
- };
26
- </script>
27
-
28
- </body>
29
- </html>
@@ -1,37 +0,0 @@
1
- $:.unshift File.dirname(__FILE__) + '/../lib'
2
-
3
- require 'rubygems'
4
- require 'web_socket'
5
- require 'json'
6
-
7
- class TimeServer < WebSocket::Server
8
-
9
- def on_connect
10
- puts "Connection Accepted"
11
- @timer = EM.add_periodic_timer(5, EM.Callback(self, :sync_time))
12
- end
13
-
14
- def on_disconnect
15
- puts "Connection released"
16
- EM.cancel_timer @timer
17
- end
18
-
19
- def on_receive msg
20
- end
21
-
22
- def sync_time
23
- puts "Hi"
24
- send_message({ :time => Time.now }.to_json)
25
- end
26
-
27
- end
28
-
29
-
30
- EM.epoll = true if EM.epoll?
31
- EM.kqueue = true if EM.kqueue?
32
-
33
- EM.set_descriptor_table_size(10240)
34
-
35
- EM.run do
36
- EM.start_server "0.0.0.0", 8000, TimeServer
37
- end
@@ -1,13 +0,0 @@
1
- require 'rubygems'
2
- require 'eventmachine'
3
- require 'digest'
4
- require 'pp'
5
-
6
- module WebSocket
7
- VERSION = 0.13
8
- end
9
-
10
- require 'web_socket/util.rb'
11
- require 'web_socket/frame.rb'
12
- require 'web_socket/server.rb'
13
- require 'web_socket/client.rb'
@@ -1,71 +0,0 @@
1
-
2
- module WebSocket
3
-
4
- class Client < EM::Connection
5
-
6
- def path
7
- "/chat"
8
- end
9
-
10
- def host
11
- "localhost:8000"
12
- end
13
-
14
- def origin
15
- "localhost"
16
- end
17
-
18
- # em override
19
- def post_init
20
- @connected = false
21
- end
22
-
23
- def connection_completed
24
- send_headers
25
- end
26
-
27
- # em override
28
- def unbind
29
- on_disconnect
30
- end
31
-
32
- def on_disconnect
33
- end
34
-
35
- def send_message msg
36
- send_data Frame.encode(msg)
37
- end
38
-
39
- private
40
-
41
- def receive_data data
42
- unless @connected
43
- handshake data
44
- else
45
- while msg = data.slice!(/\000([^\377]*)\377/)
46
- on_receive Frame.decode(msg)
47
- end
48
- end
49
- end
50
-
51
- def handshake data
52
-
53
- #convert the headers to a hash
54
- @headers = Util.parse_headers(data)
55
- @connected = true
56
-
57
- on_connect
58
- end
59
-
60
- def send_headers
61
- result = "GET #{path} HTTP/1.1\r\n"
62
- result << "Upgrade: WebSocket\r\n"
63
- result << "Connection: Upgrade\r\n"
64
- result << "Host: #{host}\r\n"
65
- result << "Origin: #{origin}\r\n\r\n"
66
-
67
- send_data result
68
- end
69
- end
70
-
71
- end
@@ -1,20 +0,0 @@
1
- module WebSocket
2
-
3
- class Frame
4
-
5
- # Frames need to start with 0x00-0x7f byte and end with
6
- # an 0xFF byte. Per spec, we can also set the first
7
- # byte to a value betweent 0x80 and 0xFF, followed by
8
- # a leading length indicator. No support yet.
9
- def self.encode data
10
- "\x00#{data}\xff"
11
- end
12
-
13
- # Strip leading and trailing bytes
14
- def self.decode data
15
- data.gsub(/^(\x00)|(\xff)$/, "")
16
- end
17
-
18
- end
19
-
20
- end
@@ -1,202 +0,0 @@
1
- module WebSocket
2
-
3
- class Server < EM::Connection
4
-
5
- @@logger = nil
6
- @@num_connections = 0
7
- @@callbacks = {}
8
- @@accepted_origins = []
9
-
10
- attr_accessor :connected,
11
- :headers
12
-
13
- def initialize *args
14
- super
15
- @connected = false
16
- @protocol_version = 75
17
- end
18
-
19
- def valid_origin?
20
- @@accepted_origins.empty? || @@accepted_origins.include?(origin)
21
- end
22
-
23
- #not doing anything with this yet
24
- def valid_path?
25
- true
26
- end
27
-
28
- def valid_upgrade?
29
- @headers[:upgrade] =~ /websocket/i
30
- end
31
-
32
- def origin
33
- @headers[:origin]
34
- end
35
-
36
- def host
37
- @headers[:host]
38
- end
39
-
40
- def path
41
- @headers[:path]
42
- end
43
-
44
- def cookies
45
- @headers[:cookie]
46
- end
47
-
48
- def protocol
49
- @headers[:protocol]
50
- end
51
-
52
- def self.path name, &block
53
- @@callbacks[name] = block
54
- end
55
-
56
- #tcp connection established
57
- def post_init
58
- @@num_connections += 1
59
- end
60
-
61
- #must be public for em
62
- def unbind
63
- @@num_connections -= 1
64
- on_disconnect
65
- end
66
-
67
- def send_message msg
68
- send_data Frame.encode(msg)
69
- end
70
-
71
- protected
72
-
73
- #override this method
74
- def on_receive msg
75
- log msg
76
- end
77
-
78
- #override this method
79
- def on_connect
80
- log "connected"
81
- end
82
-
83
- #override this method
84
- def on_disconnect
85
- log "disconnected"
86
- end
87
-
88
- def log msg
89
- if @@logger
90
- @@logger.info msg
91
- else
92
- puts msg
93
- end
94
- end
95
-
96
- private
97
-
98
- # when the connection receives data from the client
99
- # we either handshake or handle the message at
100
- # the app layer
101
- def receive_data data
102
- unless @connected
103
- handshake data
104
- else
105
- while msg = data.slice!(/\000([^\377]*)\377/)
106
- on_receive Frame.decode(msg)
107
- end
108
- end
109
- end
110
-
111
- # parse the headers, validate the origin and path
112
- # and respond with appropiate headers for a
113
- # healthy relationship with the client
114
- def handshake data
115
- #convert the headers to a hash
116
- @headers, challenge = Util.parse_headers(data)
117
-
118
- if challenge
119
- @protocol_version = 76
120
-
121
- key1 = @headers[:'sec-websocket-key1']
122
- key2 = @headers[:'sec-websocket-key2']
123
-
124
- part1 = number_from_key(key1)
125
- part2 = number_from_key(key2)
126
-
127
- unless part1 && part2
128
- close_connection
129
- return
130
- end
131
-
132
- buffer = []
133
- buffer += big_endian_bytes(part1)
134
- buffer += big_endian_bytes(part2)
135
- buffer += challenge.bytes.to_a
136
-
137
- md5 = Digest::MD5.new
138
- hash = md5.digest(buffer.pack('c*'))
139
- end
140
-
141
- # close the connection if the connection
142
- # originates from an invalid source
143
- close_connection unless valid_origin?
144
-
145
- # close the connection if a callback
146
- # is not registered for the path
147
- close_connection unless valid_path?
148
-
149
- # don't respond to non-websocket HTTP requests
150
- close_connection unless valid_upgrade?
151
-
152
- #complete the handshake
153
- send_headers(hash)
154
-
155
- @connected = true
156
-
157
- on_connect
158
- end
159
-
160
- # send the handshake response headers to
161
- # complete the initial com
162
- def send_headers(hash)
163
- response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
164
- response << "Upgrade: WebSocket\r\n"
165
- response << "Connection: Upgrade\r\n"
166
- if @protocol_version > 75
167
- response << "Sec-WebSocket-Origin: #{origin}\r\n"
168
- response << "Sec-WebSocket-Location: ws://#{host}#{path}\r\n"
169
- response << "Sec-WebSocket-protocol: ws://#{host}#{path}\r\n"
170
- else
171
- response << "WebSocket-Origin: #{origin}\r\n"
172
- response << "WebSocket-Location: ws://#{host}#{path}\r\n"
173
- end
174
- response << "\r\n"
175
- response << hash if @protocol_version > 75
176
-
177
-
178
- send_data response
179
- end
180
-
181
- def number_from_key(key)
182
- digits = key.scan(/\d+/).join.to_i
183
- spaces = key.scan(/\s+/).join.length
184
-
185
- if spaces > 0
186
- return digits / spaces
187
- else
188
- return nil
189
- end
190
- end
191
-
192
- def big_endian_bytes(num)
193
- bytes = []
194
- 4.times do
195
- bytes.unshift(num & 0xff)
196
- num >>= 8
197
- end
198
- bytes
199
- end
200
- end
201
-
202
- end
@@ -1,55 +0,0 @@
1
- module WebSocket
2
-
3
- class Util
4
-
5
- @@path_regex = /^GET (\/[^\s]*) HTTP\/1\.1$/
6
- @@hs_regex = /^HTTP\/1\.1 101 Web Socket Protocol Handshake$/
7
- @@header_regex = /^([^:]+):\s*([^$]+)/
8
-
9
- # Parse http style headers into a ruby hash
10
- def self.parse_headers data
11
- lines = data.split("\r\n")
12
- line = lines.shift
13
-
14
- headers = {}
15
-
16
- case line
17
- when @@path_regex
18
- headers[:path] = @@path_regex.match(line)[1]
19
- when @@hs_regex
20
- #do nothing
21
- else
22
- throw "Unrecognized Header!"
23
- end
24
-
25
- while line = lines.shift
26
- if line.chomp.empty?
27
- break
28
- end
29
-
30
- kvp = @@header_regex.match(line)
31
- headers[kvp[1].strip.downcase.to_sym] = kvp[2].strip
32
- end
33
-
34
- challenge = lines.pop if lines
35
-
36
- [headers, challenge]
37
- end
38
-
39
- # encode ruby hash into HTTP style headers
40
- def self.encode_headers data
41
- result = ""
42
-
43
- data.each_pair do |k,v|
44
- result << k.to_s
45
- result << ": "
46
- result << v.to_s
47
- result << "\r\n"
48
- end
49
-
50
- result << "\r\n"
51
- result
52
- end
53
-
54
- end
55
- end