em-websocket-request 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +1 -1
- data/lib/em-ws-request/vendor/web-socket-ruby/lib/web_socket.rb +53 -40
- data/lib/em-ws-request/version.rb +1 -1
- data/lib/em-ws-request/wrapper.rb +6 -5
- data/spec/websocket_spec.rb +51 -22
- metadata +27 -34
data/.gitmodules
CHANGED
@@ -79,7 +79,7 @@ class WebSocket
|
|
79
79
|
end
|
80
80
|
|
81
81
|
@path = (uri.path.empty? ? "/" : uri.path) + (uri.query ? "?" + uri.query : "")
|
82
|
-
host = uri.host + (uri.port == default_port ? "" : ":#{uri.port}")
|
82
|
+
host = uri.host + ((!uri.port || uri.port == default_port) ? "" : ":#{uri.port}")
|
83
83
|
origin = params[:origin] || "http://#{uri.host}"
|
84
84
|
key1 = generate_key()
|
85
85
|
key2 = generate_key()
|
@@ -186,47 +186,51 @@ class WebSocket
|
|
186
186
|
if packet =~ /\A\x00(.*)\xff\z/nm
|
187
187
|
return force_encoding($1, "UTF-8")
|
188
188
|
elsif packet == "\xff" && read(1) == "\x00" # closing
|
189
|
-
close(
|
189
|
+
close(1005, "", :peer)
|
190
190
|
return nil
|
191
191
|
else
|
192
192
|
raise(WebSocket::Error, "input must be either '\\x00...\\xff' or '\\xff\\x00'")
|
193
193
|
end
|
194
194
|
|
195
195
|
else
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
196
|
+
begin
|
197
|
+
bytes = read(2).unpack("C*")
|
198
|
+
fin = (bytes[0] & 0x80) != 0
|
199
|
+
opcode = bytes[0] & 0x0f
|
200
|
+
mask = (bytes[1] & 0x80) != 0
|
201
|
+
plength = bytes[1] & 0x7f
|
202
|
+
if plength == 126
|
203
|
+
bytes = read(2)
|
204
|
+
plength = bytes.unpack("n")[0]
|
205
|
+
elsif plength == 127
|
206
|
+
bytes = read(8)
|
207
|
+
(high, low) = bytes.unpack("NN")
|
208
|
+
plength = high * (2 ** 32) + low
|
209
|
+
end
|
210
|
+
if @server && !mask
|
211
|
+
# Masking is required.
|
212
|
+
@socket.close()
|
213
|
+
raise(WebSocket::Error, "received unmasked data")
|
214
|
+
end
|
215
|
+
mask_key = mask ? read(4).unpack("C*") : nil
|
216
|
+
payload = read(plength)
|
217
|
+
payload = apply_mask(payload, mask_key) if mask
|
218
|
+
case opcode
|
219
|
+
when OPCODE_TEXT
|
220
|
+
return force_encoding(payload, "UTF-8")
|
221
|
+
when OPCODE_BINARY
|
222
|
+
raise(WebSocket::Error, "received binary data, which is not supported")
|
223
|
+
when OPCODE_CLOSE
|
224
|
+
close(1005, "", :peer)
|
225
|
+
return nil
|
226
|
+
when OPCODE_PING
|
227
|
+
raise(WebSocket::Error, "received ping, which is not supported")
|
228
|
+
when OPCODE_PONG
|
229
|
+
else
|
230
|
+
raise(WebSocket::Error, "received unknown opcode: %d" % opcode)
|
231
|
+
end
|
232
|
+
rescue EOFError
|
233
|
+
return nil
|
230
234
|
end
|
231
235
|
|
232
236
|
end
|
@@ -259,16 +263,21 @@ class WebSocket
|
|
259
263
|
end
|
260
264
|
|
261
265
|
# Does closing handshake.
|
262
|
-
def close(
|
266
|
+
def close(code = 1005, reason = "", origin = :self)
|
263
267
|
if !@closing_started
|
264
268
|
case @web_socket_version
|
265
269
|
when "hixie-75", "hixie-76"
|
266
270
|
write("\xff\x00")
|
267
271
|
else
|
268
|
-
|
272
|
+
if code == 1005
|
273
|
+
payload = ""
|
274
|
+
else
|
275
|
+
payload = [code].pack("n") + force_encoding(reason.dup(), "ASCII-8BIT")
|
276
|
+
end
|
277
|
+
send_frame(OPCODE_CLOSE, payload, false)
|
269
278
|
end
|
270
279
|
end
|
271
|
-
@socket.close() if
|
280
|
+
@socket.close() if origin == :peer
|
272
281
|
@closing_started = true
|
273
282
|
end
|
274
283
|
|
@@ -332,7 +341,11 @@ class WebSocket
|
|
332
341
|
def read(num_bytes)
|
333
342
|
str = @socket.read(num_bytes)
|
334
343
|
$stderr.printf("recv> %p\n", str) if WebSocket.debug
|
335
|
-
|
344
|
+
if str && str.bytesize == num_bytes
|
345
|
+
return str
|
346
|
+
else
|
347
|
+
raise(EOFError)
|
348
|
+
end
|
336
349
|
end
|
337
350
|
|
338
351
|
def write(data)
|
@@ -8,9 +8,9 @@ module EventMachine
|
|
8
8
|
@web_socket_version = version
|
9
9
|
end
|
10
10
|
|
11
|
-
def send_frame(
|
12
|
-
opcode = type_to_opcode(
|
13
|
-
super(opcode, data,
|
11
|
+
def send_frame(opcode, data, mask = true)
|
12
|
+
opcode = type_to_opcode(opcode) if opcode.is_a?(Symbol)
|
13
|
+
super(opcode, data, mask)
|
14
14
|
end
|
15
15
|
|
16
16
|
def write(data)
|
@@ -29,8 +29,9 @@ module EventMachine
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# Called on a CLOSE frame
|
32
|
-
def close(
|
33
|
-
|
32
|
+
def close(code = 1005, reason = "", origin = :self)
|
33
|
+
origin = :self if origin == :peer # to skip @socket.close
|
34
|
+
super(code, reason, origin)
|
34
35
|
@client.unbind
|
35
36
|
end
|
36
37
|
|
data/spec/websocket_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe EventMachine::WebsocketRequest do
|
|
13
13
|
|
14
14
|
it "should invoke errback on failed upgrade" do
|
15
15
|
EventMachine.run {
|
16
|
-
http =
|
16
|
+
http = websocket_test_request(:timeout => 0)
|
17
17
|
|
18
18
|
http.callback { failed(http) }
|
19
19
|
http.errback {
|
@@ -27,14 +27,14 @@ describe EventMachine::WebsocketRequest do
|
|
27
27
|
EventMachine.run {
|
28
28
|
MSG = "hello bi-directional data exchange"
|
29
29
|
|
30
|
-
|
30
|
+
with_websocket_test_server do |ws|
|
31
31
|
ws.onopen { p [:OPENED_WS, ws]}
|
32
32
|
ws.onmessage {|msg| ws.send msg}
|
33
33
|
ws.onerror {|e| p [:WS_ERROR, e]}
|
34
34
|
ws.onclose { p [:WS_CLOSE, ws]}
|
35
35
|
end
|
36
36
|
|
37
|
-
http =
|
37
|
+
http = websocket_test_request
|
38
38
|
http.errback { failed(http) }
|
39
39
|
http.callback {
|
40
40
|
http.response_header.status.should == 101
|
@@ -55,32 +55,61 @@ describe EventMachine::WebsocketRequest do
|
|
55
55
|
# parser eats up the trailign data
|
56
56
|
# [:receive, "HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nWebSocket-Origin: 127.0.0.1\r\nWebSocket-Location: ws://127.0.0.1:8085/\r\n\r\n\x001\xFF\x002\xFF", :keep_alive?, "#<HTTP::Parser:0x0000010132d000>"]
|
57
57
|
|
58
|
-
|
58
|
+
it "should split multiple messages from websocket server into separate stream callbacks" do
|
59
59
|
EM.run do
|
60
60
|
messages = %w[1 2]
|
61
61
|
recieved = []
|
62
62
|
|
63
|
-
|
64
|
-
ws.onopen
|
65
|
-
ws.send messages[0]
|
66
|
-
ws.send messages[1]
|
67
|
-
|
63
|
+
with_websocket_test_server do |ws|
|
64
|
+
ws.onopen do
|
65
|
+
EventMachine.add_timer(0.1) { ws.send messages[0] }
|
66
|
+
EventMachine.add_timer(0.2) { ws.send messages[1] }
|
67
|
+
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
EventMachine.stop if recieved.size == messages.size
|
81
|
-
}
|
82
|
-
end
|
70
|
+
http = websocket_test_request
|
71
|
+
http.errback { failed(http) }
|
72
|
+
http.callback { http.response_header.status.should == 101; p 'WS CONNECTED' }
|
73
|
+
http.stream {|msg|
|
74
|
+
p ['GOT MSG ', msg]
|
75
|
+
msg.should == messages[recieved.size]
|
76
|
+
recieved.push msg
|
77
|
+
p [:MULTI_MESAGE, recieved]
|
78
|
+
EventMachine.stop if recieved.size == messages.size
|
79
|
+
}
|
83
80
|
end
|
84
81
|
end
|
82
|
+
|
83
|
+
it "should process close on message correctly " do
|
84
|
+
EM.run {
|
85
|
+
MSG = "hello bi-directional data exchange"
|
86
|
+
|
87
|
+
with_websocket_test_server do |ws|
|
88
|
+
ws.onopen { p [:OPENED_WS, ws] }
|
89
|
+
ws.onmessage { |msg| ws.close_websocket }
|
90
|
+
ws.onerror {|e| p [:WS_ERROR, e] }
|
91
|
+
ws.onclose { p [:WS_CLOSE, ws] }
|
92
|
+
end
|
93
|
+
|
94
|
+
http = websocket_test_request
|
95
|
+
http.errback { failed(http) }
|
96
|
+
http.callback { http.send(MSG) }
|
97
|
+
http.stream { |chunk|
|
98
|
+
chunk.should be_nil
|
99
|
+
EventMachine.stop
|
100
|
+
}
|
101
|
+
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def with_websocket_test_server(&block)
|
107
|
+
opts = { :host => "0.0.0.0", :port => 8085, :debug => true }
|
108
|
+
EventMachine::WebSocket.start(opts, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def websocket_test_request(opts = {})
|
112
|
+
req = EventMachine::WebsocketRequest.new('ws://127.0.0.1:8085/')
|
113
|
+
req.get(opts.merge(:keepalive => true))
|
85
114
|
end
|
86
115
|
end
|
metadata
CHANGED
@@ -1,38 +1,34 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-websocket-request
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.3
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Michael Rykov
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-12-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
16
15
|
name: em-http-request
|
17
|
-
|
18
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70226843904280 !ruby/object:Gem::Requirement
|
19
17
|
none: false
|
20
|
-
requirements:
|
18
|
+
requirements:
|
21
19
|
- - ~>
|
22
|
-
- !ruby/object:Gem::Version
|
20
|
+
- !ruby/object:Gem::Version
|
23
21
|
version: 1.0.0
|
24
22
|
type: :runtime
|
25
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70226843904280
|
26
25
|
description: EventMachine WebSocket client
|
27
|
-
email:
|
26
|
+
email:
|
28
27
|
- mrykov@gmail.com
|
29
28
|
executables: []
|
30
|
-
|
31
29
|
extensions: []
|
32
|
-
|
33
30
|
extra_rdoc_files: []
|
34
|
-
|
35
|
-
files:
|
31
|
+
files:
|
36
32
|
- .gitignore
|
37
33
|
- .gitmodules
|
38
34
|
- Gemfile
|
@@ -44,32 +40,29 @@ files:
|
|
44
40
|
- lib/em-ws-request/wrapper.rb
|
45
41
|
- spec/websocket_spec.rb
|
46
42
|
- lib/em-ws-request/vendor/web-socket-ruby/lib/web_socket.rb
|
47
|
-
homepage:
|
43
|
+
homepage: ''
|
48
44
|
licenses: []
|
49
|
-
|
50
45
|
post_install_message:
|
51
46
|
rdoc_options: []
|
52
|
-
|
53
|
-
require_paths:
|
47
|
+
require_paths:
|
54
48
|
- lib
|
55
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
50
|
none: false
|
57
|
-
requirements:
|
58
|
-
- -
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version:
|
61
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
56
|
none: false
|
63
|
-
requirements:
|
64
|
-
- -
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version:
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
67
61
|
requirements: []
|
68
|
-
|
69
62
|
rubyforge_project:
|
70
63
|
rubygems_version: 1.8.11
|
71
64
|
signing_key:
|
72
65
|
specification_version: 3
|
73
66
|
summary: EventMachine WebSocket client
|
74
|
-
test_files:
|
67
|
+
test_files:
|
75
68
|
- spec/websocket_spec.rb
|