em-websocket-request 0.0.3 → 0.0.4
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.
- 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
|