websocket 1.0.1 → 1.0.2
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/CHANGELOG.md +10 -0
- data/README.md +1 -1
- data/autobahn-server.json +1 -1
- data/examples/client.rb +1 -1
- data/examples/server.rb +1 -1
- data/examples/tests/autobahn_server.rb +24 -0
- data/lib/websocket.rb +11 -0
- data/lib/websocket/frame/base.rb +19 -4
- data/lib/websocket/frame/handler/base.rb +8 -12
- data/lib/websocket/frame/handler/handler03.rb +15 -1
- data/lib/websocket/frame/handler/handler05.rb +1 -0
- data/lib/websocket/frame/handler/handler07.rb +10 -0
- data/lib/websocket/frame/handler/handler75.rb +5 -2
- data/lib/websocket/frame/incoming.rb +8 -0
- data/lib/websocket/frame/outgoing.rb +6 -0
- data/lib/websocket/handshake/base.rb +38 -2
- data/lib/websocket/handshake/client.rb +66 -11
- data/lib/websocket/handshake/handler/base.rb +16 -0
- data/lib/websocket/handshake/handler/client.rb +1 -0
- data/lib/websocket/handshake/handler/client01.rb +3 -0
- data/lib/websocket/handshake/handler/client04.rb +9 -1
- data/lib/websocket/handshake/handler/client75.rb +1 -0
- data/lib/websocket/handshake/handler/client76.rb +35 -17
- data/lib/websocket/handshake/handler/server.rb +0 -19
- data/lib/websocket/handshake/handler/server04.rb +5 -0
- data/lib/websocket/handshake/handler/server75.rb +3 -1
- data/lib/websocket/handshake/handler/server76.rb +11 -1
- data/lib/websocket/handshake/server.rb +72 -0
- data/lib/websocket/version.rb +1 -1
- data/spec/frame/incoming_03_spec.rb +1 -1
- data/spec/frame/incoming_04_spec.rb +1 -1
- data/spec/frame/incoming_05_spec.rb +1 -1
- data/spec/frame/incoming_07_spec.rb +1 -1
- data/spec/frame/incoming_75_spec.rb +1 -1
- data/spec/handshake/client_76_spec.rb +1 -1
- metadata +4 -3
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.0.2
|
4
|
+
|
5
|
+
- allow configuration of max frame size via WebSocket.max_frame_size option
|
6
|
+
- much better documentation
|
7
|
+
- remove handler-specific methods from public list
|
8
|
+
- refactor code for easier use
|
9
|
+
- make parsers return more consistent values
|
10
|
+
- fix server handshake #to_s when no version was found
|
11
|
+
- add #uri to server handshake
|
12
|
+
|
3
13
|
## 1.0.1
|
4
14
|
|
5
15
|
- allow creating client with :uri and :url options
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Currently WebSocket Ruby supports all existing drafts of WebSocket, which includ
|
|
9
9
|
|
10
10
|
- [hixie-75](http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75)
|
11
11
|
- [hixie-76](http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76)
|
12
|
-
- [all hybi drafts (00-
|
12
|
+
- [all hybi drafts (00-13)](http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17)
|
13
13
|
- [RFC 6455](http://datatracker.ietf.org/doc/rfc6455/)
|
14
14
|
|
15
15
|
## Installation
|
data/autobahn-server.json
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
"options": {"failByDrop": false},
|
3
3
|
"outdir": "./autobahn/server",
|
4
4
|
|
5
|
-
"servers": [{"agent": "WebSocket-Ruby v1.0.
|
5
|
+
"servers": [{"agent": "WebSocket-Ruby v1.0.2", "url": "ws://localhost:9001", "options": {"version": 18}}],
|
6
6
|
|
7
7
|
"cases": ["*"],
|
8
8
|
"exclude-cases": [],
|
data/examples/client.rb
CHANGED
@@ -2,7 +2,7 @@ require "#{File.expand_path(File.dirname(__FILE__))}/base"
|
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
# Example WebSocket Client (using EventMachine)
|
5
|
-
# @example
|
5
|
+
# @example
|
6
6
|
# ws = WebSocket::EventMachine::Client.connect(:host => "0.0.0.0", :port => 8080)
|
7
7
|
# ws.onmessage { |msg| ws.send "Pong: #{msg}" }
|
8
8
|
# ws.send "data"
|
data/examples/server.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "#{File.expand_path(File.dirname(__FILE__))}/base"
|
2
2
|
|
3
3
|
# Example WebSocket Server (using EventMachine)
|
4
|
-
# @example
|
4
|
+
# @example
|
5
5
|
# WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 8080) do |ws|
|
6
6
|
# ws.onopen { ws.send "Hello Client!"}
|
7
7
|
# ws.onmessage { |msg| ws.send "Pong: #{msg}" }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../server"
|
2
|
+
|
3
|
+
EM.epoll
|
4
|
+
EM.run do
|
5
|
+
|
6
|
+
trap("TERM") { stop }
|
7
|
+
trap("INT") { stop }
|
8
|
+
|
9
|
+
WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 9001) do |ws|
|
10
|
+
|
11
|
+
ws.onmessage do |msg, type|
|
12
|
+
ws.send msg, :type => type
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "Server started at port 9001"
|
18
|
+
|
19
|
+
def stop
|
20
|
+
puts "Terminating WebSocket Server"
|
21
|
+
EventMachine.stop
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/websocket.rb
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
module WebSocket
|
7
7
|
class Error < RuntimeError; end
|
8
8
|
|
9
|
+
# Default WebSocket version to use
|
9
10
|
DEFAULT_VERSION = 13
|
10
11
|
ROOT = File.expand_path(File.dirname(__FILE__))
|
11
12
|
|
@@ -13,4 +14,14 @@ module WebSocket
|
|
13
14
|
autoload :Handler, "#{ROOT}/websocket/handler"
|
14
15
|
autoload :Handshake, "#{ROOT}/websocket/handshake"
|
15
16
|
|
17
|
+
# Limit of frame size payload in bytes
|
18
|
+
def self.max_frame_size
|
19
|
+
@max_frame_size ||= 20 * 1024 * 1024 # 20MB
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set limit of frame size payload in bytes
|
23
|
+
def self.max_frame_size=(val)
|
24
|
+
@max_frame_size = val
|
25
|
+
end
|
26
|
+
|
16
27
|
end
|
data/lib/websocket/frame/base.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Frame
|
3
|
+
# @abstract Subclass and override to implement custom frames
|
3
4
|
class Base
|
4
5
|
|
5
6
|
attr_reader :data, :type, :version, :error
|
6
7
|
|
7
8
|
# Initialize frame
|
8
9
|
# @param args [Hash] Arguments for frame
|
10
|
+
# @option args [String] :data default data for frame
|
11
|
+
# @option args [String] :type Type of frame - available types are "text", "binary", "ping", "pong" and "close"(support depends on draft version)
|
9
12
|
# @option args [Integer] :version Version of draft. Currently supported version are 75, 76 and 00-13.
|
10
|
-
# @option args [String] :type Type of frame - available types are "text", "binary", "ping", "pong" and "close"(support depends on draft version)
|
11
|
-
# @option args [String] :data default data for frame
|
12
13
|
def initialize(args = {})
|
13
14
|
@type = args[:type]
|
14
15
|
@data = Data.new(args[:data].to_s)
|
15
16
|
@version = args[:version] || DEFAULT_VERSION
|
16
|
-
|
17
|
+
include_version
|
17
18
|
end
|
18
19
|
|
19
20
|
# Check if some errors occured
|
@@ -22,9 +23,21 @@ module WebSocket
|
|
22
23
|
!!@error
|
23
24
|
end
|
24
25
|
|
26
|
+
# Is selected type supported for selected handler?
|
27
|
+
def support_type?
|
28
|
+
supported_frames.include?(@type)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Implement in submodules
|
32
|
+
def supported_frames
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
25
36
|
private
|
26
37
|
|
27
|
-
|
38
|
+
# Include set of methods for selected protocol version
|
39
|
+
# @return [Boolean] false if protocol number is unknown, otherwise true
|
40
|
+
def include_version
|
28
41
|
case @version
|
29
42
|
when 75..76 then extend Handler::Handler75
|
30
43
|
when 0..2 then extend Handler::Handler75
|
@@ -36,6 +49,8 @@ module WebSocket
|
|
36
49
|
end
|
37
50
|
end
|
38
51
|
|
52
|
+
# Changes state to error and sets error message
|
53
|
+
# @param [String] message Error message to set
|
39
54
|
def set_error(message)
|
40
55
|
@error = message
|
41
56
|
end
|
@@ -3,34 +3,30 @@ module WebSocket
|
|
3
3
|
module Handler
|
4
4
|
module Base
|
5
5
|
|
6
|
-
MAX_FRAME_SIZE = 20 * 1024 * 1024 # 20MB
|
7
|
-
|
8
|
-
# Is selected type supported for selected handler?
|
9
|
-
def support_type?
|
10
|
-
supported_frames.include?(@type)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Implement in submodules
|
14
|
-
def supported_frames
|
15
|
-
raise NotImplementedError
|
16
|
-
end
|
17
|
-
|
18
6
|
private
|
19
7
|
|
20
8
|
# Convert data to raw frame ready to send to client
|
9
|
+
# @return [String] Encoded frame
|
21
10
|
def encode_frame
|
22
11
|
raise NotImplementedError
|
23
12
|
end
|
24
13
|
|
25
14
|
# Convert raw data to decoded frame
|
15
|
+
# @return [WebSocket::Frame::Incoming] Frame if found, nil otherwise
|
26
16
|
def decode_frame
|
27
17
|
raise NotImplementedError
|
28
18
|
end
|
29
19
|
|
20
|
+
# Check if frame is one of control frames
|
21
|
+
# @param [Symbol] frame_type Frame type
|
22
|
+
# @return [Boolean] True if given frame type is control frame
|
30
23
|
def control_frame?(frame_type)
|
31
24
|
![:text, :binary, :continuation].include?(frame_type)
|
32
25
|
end
|
33
26
|
|
27
|
+
# Check if frame is one of data frames
|
28
|
+
# @param [Symbol] frame_type Frame type
|
29
|
+
# @return [Boolean] True if given frame type is data frame
|
34
30
|
def data_frame?(frame_type)
|
35
31
|
[:text, :binary].include?(frame_type)
|
36
32
|
end
|
@@ -7,12 +7,14 @@ module WebSocket
|
|
7
7
|
|
8
8
|
include Base
|
9
9
|
|
10
|
+
# @see WebSocket::Frame::Base#supported_frames
|
10
11
|
def supported_frames
|
11
12
|
[:text, :binary, :close, :ping, :pong]
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
15
16
|
|
17
|
+
# @see WebSocket::Frame::Handler::Base#encode_frame
|
16
18
|
def encode_frame
|
17
19
|
frame = ''
|
18
20
|
|
@@ -38,6 +40,7 @@ module WebSocket
|
|
38
40
|
set_error(e.message.to_sym) and return
|
39
41
|
end
|
40
42
|
|
43
|
+
# @see WebSocket::Frame::Handler::Base#decode_frame
|
41
44
|
def decode_frame
|
42
45
|
while @data.size > 1
|
43
46
|
pointer = 0
|
@@ -85,7 +88,7 @@ module WebSocket
|
|
85
88
|
frame_length = pointer + payload_length
|
86
89
|
frame_length += 4 if mask
|
87
90
|
|
88
|
-
raise(WebSocket::Error, :frame_too_long) if frame_length >
|
91
|
+
raise(WebSocket::Error, :frame_too_long) if frame_length > WebSocket.max_frame_size
|
89
92
|
|
90
93
|
# Check buffer size
|
91
94
|
return if @data.getbyte(frame_length-1) == nil # Buffer incomplete
|
@@ -135,8 +138,10 @@ module WebSocket
|
|
135
138
|
# This allows flipping the more bit to fin for draft 04
|
136
139
|
def fin; false; end
|
137
140
|
|
141
|
+
# Allow turning on or off masking
|
138
142
|
def masking?; false; end
|
139
143
|
|
144
|
+
# Hash of frame names and it's opcodes
|
140
145
|
FRAME_TYPES = {
|
141
146
|
:continuation => 0,
|
142
147
|
:close => 1,
|
@@ -146,12 +151,21 @@ module WebSocket
|
|
146
151
|
:binary => 5
|
147
152
|
}
|
148
153
|
|
154
|
+
# Hash of frame opcodes and it's names
|
149
155
|
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
150
156
|
|
157
|
+
# Convert frame type name to opcode
|
158
|
+
# @param [Symbol] frame_type Frame type name
|
159
|
+
# @return [Integer] opcode or nil
|
160
|
+
# @raise [WebSocket::Error] if frame opcode is not known
|
151
161
|
def type_to_opcode(frame_type)
|
152
162
|
FRAME_TYPES[frame_type] || raise(WebSocket::Error, :unknown_frame_type)
|
153
163
|
end
|
154
164
|
|
165
|
+
# Convert frame opcode to type name
|
166
|
+
# @param [Integer] opcode Opcode
|
167
|
+
# @return [Symbol] Frame type name or nil
|
168
|
+
# @raise [WebSocket::Error] if frame type name is not known
|
155
169
|
def opcode_to_type(opcode)
|
156
170
|
FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error, :unknown_opcode)
|
157
171
|
end
|
@@ -9,6 +9,7 @@ module WebSocket
|
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
+
# Hash of frame names and it's opcodes
|
12
13
|
FRAME_TYPES = {
|
13
14
|
:continuation => 0,
|
14
15
|
:text => 1,
|
@@ -18,12 +19,21 @@ module WebSocket
|
|
18
19
|
:pong => 10,
|
19
20
|
}
|
20
21
|
|
22
|
+
# Hash of frame opcodes and it's names
|
21
23
|
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
22
24
|
|
25
|
+
# Convert frame type name to opcode
|
26
|
+
# @param [Symbol] frame_type Frame type name
|
27
|
+
# @return [Integer] opcode or nil
|
28
|
+
# @raise [WebSocket::Error] if frame opcode is not known
|
23
29
|
def type_to_opcode(frame_type)
|
24
30
|
FRAME_TYPES[frame_type] || raise(WebSocket::Error, :unknown_frame_type)
|
25
31
|
end
|
26
32
|
|
33
|
+
# Convert frame opcode to type name
|
34
|
+
# @param [Integer] opcode Opcode
|
35
|
+
# @return [Symbol] Frame type name or nil
|
36
|
+
# @raise [WebSocket::Error] if frame type name is not known
|
27
37
|
def opcode_to_type(opcode)
|
28
38
|
FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error, :unknown_opcode)
|
29
39
|
end
|
@@ -7,12 +7,14 @@ module WebSocket
|
|
7
7
|
|
8
8
|
include Base
|
9
9
|
|
10
|
+
# @see WebSocket::Frame::Base#supported_frames
|
10
11
|
def supported_frames
|
11
12
|
[:text, :close]
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
15
16
|
|
17
|
+
# @see WebSocket::Frame::Handler::Base#encode_frame
|
16
18
|
def encode_frame
|
17
19
|
case @type
|
18
20
|
when :close then "\xff\x00"
|
@@ -23,6 +25,7 @@ module WebSocket
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
# @see WebSocket::Frame::Handler::Base#decode_frame
|
26
29
|
def decode_frame
|
27
30
|
return if @data.size == 0
|
28
31
|
|
@@ -43,7 +46,7 @@ module WebSocket
|
|
43
46
|
break unless (b & 0x80) == 0x80
|
44
47
|
end
|
45
48
|
|
46
|
-
set_error(:frame_too_long) and return if length >
|
49
|
+
set_error(:frame_too_long) and return if length > ::WebSocket.max_frame_size
|
47
50
|
|
48
51
|
unless @data.getbyte(pointer+length-1) == nil
|
49
52
|
# Straight from spec - I'm sure this isn't crazy...
|
@@ -62,7 +65,7 @@ module WebSocket
|
|
62
65
|
set_error(:invalid_frame) and return if @data.getbyte(0) != 0x00
|
63
66
|
|
64
67
|
# Addition to the spec to protect against malicious requests
|
65
|
-
set_error(:frame_too_long) and return if @data.size >
|
68
|
+
set_error(:frame_too_long) and return if @data.size > ::WebSocket.max_frame_size
|
66
69
|
|
67
70
|
msg = @data.slice!(/\A\x00[^\xff]*\xff/)
|
68
71
|
if msg
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Frame
|
3
|
+
# Construct or parse incoming WebSocket Frame.
|
4
|
+
# @note You should NEVER use this class directly - use Client or Server subclasses instead, as they contain additional frame options(i.e. Client-side masking in draft 04)
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# frame = WebSocket::Frame::Incoming::Server.new(:version => @handshake.version)
|
8
|
+
# frame << "\x81\x05\x48\x65\x6c\x6c\x6f\x81\x06\x77\x6f\x72\x6c\x64\x21"
|
9
|
+
# frame.next # "Hello"
|
10
|
+
# frame.next # "world!""
|
3
11
|
class Incoming < Base
|
4
12
|
|
5
13
|
autoload :Client, "#{::WebSocket::ROOT}/websocket/frame/incoming/client"
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Frame
|
3
|
+
# Construct or parse incoming WebSocket Frame.
|
4
|
+
# @note You should NEVER use this class directly - use Client or Server subclasses instead, as they contain additional frame options(i.e. Client-side masking in draft 04)
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# frame = WebSocket::Frame::Outgoing::Server.new(:version => @handshake.version, :data => "Hello", :type => :text)
|
8
|
+
# frame.to_s # "\x81\x05\x48\x65\x6c\x6c\x6f"
|
3
9
|
class Outgoing < Base
|
4
10
|
|
5
11
|
autoload :Client, "#{::WebSocket::ROOT}/websocket/frame/outgoing/client"
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Handshake
|
3
|
+
# @abstract Subclass and override to implement custom handshakes
|
3
4
|
class Base
|
4
5
|
|
5
6
|
attr_reader :host, :port, :path, :query,
|
6
7
|
:error, :state, :version, :secure
|
7
8
|
|
9
|
+
# Initialize new WebSocket Handshake and set it's state to :new
|
8
10
|
def initialize(args = {})
|
9
11
|
@state = :new
|
10
12
|
|
@@ -12,32 +14,63 @@ module WebSocket
|
|
12
14
|
@headers = {}
|
13
15
|
end
|
14
16
|
|
17
|
+
# @abstract Add data to handshake
|
15
18
|
def <<(data)
|
16
19
|
raise NotImplementedError
|
17
20
|
end
|
18
21
|
|
22
|
+
# Return textual representation of handshake request or response
|
23
|
+
# @return [String] text of response
|
24
|
+
def to_s
|
25
|
+
""
|
26
|
+
end
|
27
|
+
|
28
|
+
# Is parsing of data finished?
|
29
|
+
# @return [Boolena] True if request was completely parsed or error occured. False otherwise
|
19
30
|
def finished?
|
20
31
|
@state == :finished || @state == :error
|
21
32
|
end
|
22
33
|
|
34
|
+
# Is parsed data valid?
|
35
|
+
# @return [Boolean] False if some errors occured. Reason for error could be found in error method
|
23
36
|
def valid?
|
24
37
|
finished? && @error == nil
|
25
38
|
end
|
26
39
|
|
40
|
+
# @abstract Should send data after parsing is finished?
|
27
41
|
def should_respond?
|
28
42
|
raise NotImplementedError
|
29
43
|
end
|
30
44
|
|
45
|
+
# Data left from parsing. Sometimes data that doesn't belong to handshake are added - use this method to retrieve them.
|
46
|
+
# @return [String] String if some data are available. Nil otherwise
|
31
47
|
def leftovers
|
32
48
|
@leftovers.split("\n", reserved_leftover_lines + 1)[reserved_leftover_lines]
|
33
49
|
end
|
34
50
|
|
51
|
+
# URI of request.
|
52
|
+
# @return [String] Full URI with protocol
|
53
|
+
# @example
|
54
|
+
# @handshake.uri #=> "ws://example.com/path?query=true"
|
55
|
+
def uri
|
56
|
+
uri = secure ? "wss://" : "ws://"
|
57
|
+
uri << host
|
58
|
+
uri << ":#{port}" if port
|
59
|
+
uri << path
|
60
|
+
uri << "?#{query}" if query
|
61
|
+
uri
|
62
|
+
end
|
63
|
+
|
35
64
|
private
|
36
65
|
|
66
|
+
# Number of lines after header that should be handled as belonging to handshake. Any data after those lines will be handled as leftovers.
|
67
|
+
# @return [Integer] Number of lines
|
37
68
|
def reserved_leftover_lines
|
38
69
|
0
|
39
70
|
end
|
40
71
|
|
72
|
+
# Changes state to error and sets error message
|
73
|
+
# @param [String] message Error message to set
|
41
74
|
def set_error(message)
|
42
75
|
@state = :error
|
43
76
|
@error = message
|
@@ -45,14 +78,16 @@ module WebSocket
|
|
45
78
|
|
46
79
|
HEADER = /^([^:]+):\s*(.+)$/
|
47
80
|
|
81
|
+
# Parse data imported to handshake and sets state to finished if necessary.
|
82
|
+
# @return [Boolean] True if finished parsing. False if not all data received yet.
|
48
83
|
def parse_data
|
49
84
|
header, @leftovers = @data.split("\r\n\r\n", 2)
|
50
|
-
return unless @leftovers # The whole header has not been received yet.
|
85
|
+
return false unless @leftovers # The whole header has not been received yet.
|
51
86
|
|
52
87
|
lines = header.split("\r\n")
|
53
88
|
|
54
89
|
first_line = lines.shift
|
55
|
-
return unless parse_first_line(first_line)
|
90
|
+
return false unless parse_first_line(first_line)
|
56
91
|
|
57
92
|
lines.each do |line|
|
58
93
|
h = HEADER.match(line)
|
@@ -60,6 +95,7 @@ module WebSocket
|
|
60
95
|
end
|
61
96
|
|
62
97
|
@state = :finished
|
98
|
+
true
|
63
99
|
end
|
64
100
|
|
65
101
|
end
|
@@ -2,8 +2,53 @@ require 'URI' unless defined?(URI)
|
|
2
2
|
|
3
3
|
module WebSocket
|
4
4
|
module Handshake
|
5
|
+
# Construct or parse a client WebSocket handshake.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# @handshake = WebSocket::Handshake::Client.new(:url => 'ws://example.com')
|
9
|
+
#
|
10
|
+
# # Create request
|
11
|
+
# @handshake.to_s # GET /demo HTTP/1.1
|
12
|
+
# # Upgrade: websocket
|
13
|
+
# # Connection: Upgrade
|
14
|
+
# # Host: example.com
|
15
|
+
# # Sec-WebSocket-Origin: http://example.com
|
16
|
+
# # Sec-WebSocket-Version: 17
|
17
|
+
# # Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
18
|
+
#
|
19
|
+
# # Parse server response
|
20
|
+
# @handshake << <<EOF
|
21
|
+
# HTTP/1.1 101 Switching Protocols
|
22
|
+
# Upgrade: websocket
|
23
|
+
# Connection: Upgrade
|
24
|
+
# Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
25
|
+
#
|
26
|
+
# EOF
|
27
|
+
#
|
28
|
+
# # All data received?
|
29
|
+
# @handshake.finished?
|
30
|
+
#
|
31
|
+
# # No parsing errors?
|
32
|
+
# @handshake.valid?
|
33
|
+
#
|
5
34
|
class Client < Base
|
6
35
|
|
36
|
+
# Initialize new WebSocket Client
|
37
|
+
#
|
38
|
+
# @param [Hash] args Arguments for client
|
39
|
+
#
|
40
|
+
# @option args [String] :host Host of request. Required if no :url param was provided.
|
41
|
+
# @option args [String] :origin Origin of request. Optional, should be used mostly by browsers. Default: nil
|
42
|
+
# @option args [String] :path Path of request. Should start with '/'. Default: '/'
|
43
|
+
# @option args [Integer] :port Port of request. Default: nil
|
44
|
+
# @option args [String] :query. Query for request. Should be in format "aaa=bbb&ccc=ddd"
|
45
|
+
# @option args [Boolean] :secure Defines protocol to use. If true then wss://, otherwise ws://. This option will not change default port - it should be handled by programmer.
|
46
|
+
# @option args [String] :url URL of request. Must by in format like ws://example.com/path?query=true. Every part of this url will be overriden by more specific arguments.
|
47
|
+
# @option args [String] :uri Alias to :url
|
48
|
+
# @option args [Integer] :version Version of WebSocket to use. Default: 13 (this is version from RFC)
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Websocket::Handshake::Client.new(:url => "ws://example.com/path?query=true")
|
7
52
|
def initialize(args = {})
|
8
53
|
super
|
9
54
|
|
@@ -32,6 +77,18 @@ module WebSocket
|
|
32
77
|
include_version
|
33
78
|
end
|
34
79
|
|
80
|
+
# Add text of response from Server. This method will parse content immediately and update state and error(if neccessary)
|
81
|
+
#
|
82
|
+
# @param [String] data Data to add
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# @handshake << <<EOF
|
86
|
+
# HTTP/1.1 101 Switching Protocols
|
87
|
+
# Upgrade: websocket
|
88
|
+
# Connection: Upgrade
|
89
|
+
# Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
90
|
+
#
|
91
|
+
# EOF
|
35
92
|
def <<(data)
|
36
93
|
@data << data
|
37
94
|
if parse_data
|
@@ -39,21 +96,16 @@ module WebSocket
|
|
39
96
|
end
|
40
97
|
end
|
41
98
|
|
99
|
+
# Should send content to server after finished parsing?
|
100
|
+
# @return [Boolean] false
|
42
101
|
def should_respond?
|
43
102
|
false
|
44
103
|
end
|
45
104
|
|
46
|
-
def uri
|
47
|
-
uri = @secure ? "wss://" : "ws://"
|
48
|
-
uri << @host
|
49
|
-
uri << ":#{@port}" if @port
|
50
|
-
uri << @path
|
51
|
-
uri << "?#{@query}" if @query
|
52
|
-
uri
|
53
|
-
end
|
54
|
-
|
55
105
|
private
|
56
106
|
|
107
|
+
# Include set of methods for selected protocol version
|
108
|
+
# @return [Boolean] false if protocol number is unknown, otherwise true
|
57
109
|
def include_version
|
58
110
|
case @version
|
59
111
|
when 75 then extend Handler::Client75
|
@@ -67,11 +119,14 @@ module WebSocket
|
|
67
119
|
|
68
120
|
FIRST_LINE = /^HTTP\/1\.1 (\d{3})[\w\s]*$/
|
69
121
|
|
122
|
+
# Parse first line of Server response.
|
123
|
+
# @param [String] line Line to parse
|
124
|
+
# @return [Boolean] True if parsed correctly. False otherwise
|
70
125
|
def parse_first_line(line)
|
71
126
|
line_parts = line.match(FIRST_LINE)
|
72
|
-
set_error(:invalid_header) and return unless line_parts
|
127
|
+
set_error(:invalid_header) and return false unless line_parts
|
73
128
|
status = line_parts[1]
|
74
|
-
set_error(:invalid_status_code) and return unless status == '101'
|
129
|
+
set_error(:invalid_status_code) and return false unless status == '101'
|
75
130
|
|
76
131
|
return true
|
77
132
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Handshake
|
3
3
|
module Handler
|
4
|
+
# This module and it's descendants are included in client or server handshake in order to extend basic functionality
|
4
5
|
module Base
|
5
6
|
|
7
|
+
# @see WebSocket::Handshake::Base#to_s
|
6
8
|
def to_s
|
7
9
|
result = [ header_line ]
|
8
10
|
handshake_keys.each do |key|
|
@@ -15,6 +17,20 @@ module WebSocket
|
|
15
17
|
|
16
18
|
private
|
17
19
|
|
20
|
+
# Set first line of text representation according to specification.
|
21
|
+
# @return [String] First line of HTTP header
|
22
|
+
def header_line
|
23
|
+
""
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set handshake headers. Provided as array because some protocol version require specific order of fields.
|
27
|
+
# @return [Array] List of headers as arrays [ key, value ]
|
28
|
+
def handshake_keys
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set data to send after headers. In most cases it will be blank data.
|
33
|
+
# @return [String] data
|
18
34
|
def finishing_line
|
19
35
|
""
|
20
36
|
end
|
@@ -8,12 +8,14 @@ module WebSocket
|
|
8
8
|
|
9
9
|
include Client
|
10
10
|
|
11
|
+
# @see WebSocket::Handshake::Base#valid?
|
11
12
|
def valid?
|
12
13
|
super && verify_accept
|
13
14
|
end
|
14
15
|
|
15
16
|
private
|
16
17
|
|
18
|
+
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
17
19
|
def handshake_keys
|
18
20
|
keys = [
|
19
21
|
["Upgrade", "websocket"],
|
@@ -23,19 +25,25 @@ module WebSocket
|
|
23
25
|
host += ":#{@port}" if @port
|
24
26
|
keys << ["Host", host]
|
25
27
|
keys << ["Sec-WebSocket-Origin", @origin] if @origin
|
26
|
-
keys << ["Sec-WebSocket-Version", @version]
|
28
|
+
keys << ["Sec-WebSocket-Version", @version ]
|
27
29
|
keys << ["Sec-WebSocket-Key", key]
|
28
30
|
keys
|
29
31
|
end
|
30
32
|
|
33
|
+
# Sec-WebSocket-Key value
|
34
|
+
# @return [String] key
|
31
35
|
def key
|
32
36
|
@key ||= Base64.encode64((1..16).map { rand(255).chr } * '').strip
|
33
37
|
end
|
34
38
|
|
39
|
+
# Value of Sec-WebSocket-Accept that should be delivered back by server
|
40
|
+
# @return [Sering] accept
|
35
41
|
def accept
|
36
42
|
@accept ||= Base64.encode64(Digest::SHA1.digest(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')).strip
|
37
43
|
end
|
38
44
|
|
45
|
+
# Verify if received header Sec-WebSocket-Accept matches generated one.
|
46
|
+
# @return [Boolean] True if accept is matching. False otherwise(appropriate error is set)
|
39
47
|
def verify_accept
|
40
48
|
set_error(:invalid_accept) and return false unless @headers['sec-websocket-accept'] == accept
|
41
49
|
true
|
@@ -7,28 +7,19 @@ module WebSocket
|
|
7
7
|
|
8
8
|
include Client75
|
9
9
|
|
10
|
-
|
11
|
-
@key1 ||= generate_key(:key1)
|
12
|
-
end
|
13
|
-
|
14
|
-
def key2
|
15
|
-
@key2 ||= generate_key(:key2)
|
16
|
-
end
|
17
|
-
|
18
|
-
def key3
|
19
|
-
@key3 ||= generate_key3
|
20
|
-
end
|
21
|
-
|
10
|
+
# @see WebSocket::Handshake::Base#valid?
|
22
11
|
def valid?
|
23
12
|
super && verify_challenge
|
24
13
|
end
|
25
14
|
|
26
15
|
private
|
27
16
|
|
17
|
+
# @see WebSocket::Handshake::Base#reserved_leftover_lines
|
28
18
|
def reserved_leftover_lines
|
29
19
|
1
|
30
20
|
end
|
31
21
|
|
22
|
+
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
32
23
|
def handshake_keys
|
33
24
|
keys = super
|
34
25
|
keys << ['Sec-WebSocket-Key1', key1]
|
@@ -36,11 +27,31 @@ module WebSocket
|
|
36
27
|
keys
|
37
28
|
end
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
# @see WebSocket::Handshake::Handler::Base#finishing_line
|
31
|
+
def finishing_line
|
32
|
+
key3
|
42
33
|
end
|
43
34
|
|
35
|
+
# Sec-WebSocket-Key1 value
|
36
|
+
# @return [String] key
|
37
|
+
def key1
|
38
|
+
@key1 ||= generate_key(:key1)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sec-WebSocket-Key2 value
|
42
|
+
# @return [String] key
|
43
|
+
def key2
|
44
|
+
@key2 ||= generate_key(:key2)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Value of third key, sent in body
|
48
|
+
# @return [String] key
|
49
|
+
def key3
|
50
|
+
@key3 ||= generate_key3
|
51
|
+
end
|
52
|
+
|
53
|
+
# Expected challenge that should be sent by server
|
54
|
+
# @return [String] challenge
|
44
55
|
def challenge
|
45
56
|
return @challenge if defined?(@challenge)
|
46
57
|
key1 && key2
|
@@ -51,12 +62,18 @@ module WebSocket
|
|
51
62
|
@challenge = Digest::MD5.digest(sum)
|
52
63
|
end
|
53
64
|
|
54
|
-
|
55
|
-
|
65
|
+
# Verify if challenge sent by server match generated one
|
66
|
+
# @return [Boolena] True if challenge matches, false otherwise(sets appropriate error)
|
67
|
+
def verify_challenge
|
68
|
+
set_error(:invalid_challenge) and return false unless @leftovers == challenge
|
69
|
+
true
|
56
70
|
end
|
57
71
|
|
58
72
|
NOISE_CHARS = ("\x21".."\x2f").to_a() + ("\x3a".."\x7e").to_a()
|
59
73
|
|
74
|
+
# Generate Sec-WebSocket-Key1 and Sec-WebSocket-Key2
|
75
|
+
# @param [String] name of key. Will be used to set number variable needed later. Valid values: key1, key2
|
76
|
+
# @return [String] generated key
|
60
77
|
def generate_key(key)
|
61
78
|
spaces = 1 + rand(12)
|
62
79
|
max = 0xffffffff / spaces
|
@@ -75,6 +92,7 @@ module WebSocket
|
|
75
92
|
return key
|
76
93
|
end
|
77
94
|
|
95
|
+
# Generate third key
|
78
96
|
def generate_key3
|
79
97
|
return [rand(0x100000000)].pack("N") + [rand(0x100000000)].pack("N")
|
80
98
|
end
|
@@ -5,25 +5,6 @@ module WebSocket
|
|
5
5
|
|
6
6
|
include Base
|
7
7
|
|
8
|
-
def host
|
9
|
-
@headers["host"].to_s.split(":")[0].to_s
|
10
|
-
end
|
11
|
-
|
12
|
-
def port
|
13
|
-
@headers["host"].to_s.split(":")[1]
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def handshake_location
|
19
|
-
location = @secure ? "wss://" : "ws://"
|
20
|
-
location << host
|
21
|
-
location << ":#{port}" if port
|
22
|
-
location << path
|
23
|
-
location << "?#{@query}" if @query
|
24
|
-
location
|
25
|
-
end
|
26
|
-
|
27
8
|
end
|
28
9
|
end
|
29
10
|
end
|
@@ -8,16 +8,19 @@ module WebSocket
|
|
8
8
|
|
9
9
|
include Server
|
10
10
|
|
11
|
+
# @see WebSocket::Handshake::Base#valid?
|
11
12
|
def valid?
|
12
13
|
super && (@headers['sec-websocket-key'] ? true : (set_error(:invalid_handshake_authentication) and false))
|
13
14
|
end
|
14
15
|
|
15
16
|
private
|
16
17
|
|
18
|
+
# @see WebSocket::Handshake::Handler::Base#header_line
|
17
19
|
def header_line
|
18
20
|
"HTTP/1.1 101 Switching Protocols"
|
19
21
|
end
|
20
22
|
|
23
|
+
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
21
24
|
def handshake_keys
|
22
25
|
[
|
23
26
|
["Upgrade", "websocket"],
|
@@ -26,6 +29,8 @@ module WebSocket
|
|
26
29
|
]
|
27
30
|
end
|
28
31
|
|
32
|
+
# Signature of response, created from client request Sec-WebSocket-Key
|
33
|
+
# @return [String] signature
|
29
34
|
def signature
|
30
35
|
return unless key = @headers['sec-websocket-key']
|
31
36
|
string_to_sign = "#{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
@@ -7,16 +7,18 @@ module WebSocket
|
|
7
7
|
|
8
8
|
private
|
9
9
|
|
10
|
+
# @see WebSocket::Handshake::Handler::Base#header_line
|
10
11
|
def header_line
|
11
12
|
"HTTP/1.1 101 Web Socket Protocol Handshake"
|
12
13
|
end
|
13
14
|
|
15
|
+
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
14
16
|
def handshake_keys
|
15
17
|
[
|
16
18
|
["Upgrade", "WebSocket"],
|
17
19
|
["Connection", "Upgrade"],
|
18
20
|
["WebSocket-Origin", @headers['origin']],
|
19
|
-
["WebSocket-Location",
|
21
|
+
["WebSocket-Location", uri]
|
20
22
|
]
|
21
23
|
end
|
22
24
|
|
@@ -7,35 +7,42 @@ module WebSocket
|
|
7
7
|
|
8
8
|
include Server
|
9
9
|
|
10
|
+
# @see WebSocket::Handshake::Base#valid?
|
10
11
|
def valid?
|
11
12
|
super && !!finishing_line
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
15
16
|
|
17
|
+
# @see WebSocket::Handshake::Base#reserved_leftover_lines
|
16
18
|
def reserved_leftover_lines
|
17
19
|
1
|
18
20
|
end
|
19
21
|
|
22
|
+
# @see WebSocket::Handshake::Handler::Base#header_line
|
20
23
|
def header_line
|
21
24
|
"HTTP/1.1 101 WebSocket Protocol Handshake"
|
22
25
|
end
|
23
26
|
|
27
|
+
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
24
28
|
def handshake_keys
|
25
29
|
[
|
26
30
|
["Upgrade", "WebSocket"],
|
27
31
|
["Connection", "Upgrade"],
|
28
32
|
["Sec-WebSocket-Origin", @headers['origin']],
|
29
|
-
["Sec-WebSocket-Location",
|
33
|
+
["Sec-WebSocket-Location", uri]
|
30
34
|
]
|
31
35
|
end
|
32
36
|
|
37
|
+
# @see WebSocket::Handshake::Handler::Base#finishing_line
|
33
38
|
def finishing_line
|
34
39
|
@finishing_line ||= challenge_response
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
38
43
|
|
44
|
+
# Response to client challenge from request Sec-WebSocket-Key1, Sec-WebSocket-Key2 and leftovers
|
45
|
+
# @return [String] Challenge response or nil if error occured
|
39
46
|
def challenge_response
|
40
47
|
# Refer to 5.2 4-9 of the draft 76
|
41
48
|
first = numbers_over_spaces(@headers['sec-websocket-key1']) || return
|
@@ -48,6 +55,9 @@ module WebSocket
|
|
48
55
|
Digest::MD5.digest(sum)
|
49
56
|
end
|
50
57
|
|
58
|
+
# Calculate numbers over spaces, according to spec 5.2
|
59
|
+
# @param [String] string Key to parse
|
60
|
+
# @return [Integer] Result of calculations or nil if error occured
|
51
61
|
def numbers_over_spaces(string)
|
52
62
|
numbers = string.scan(/[0-9]/).join.to_i
|
53
63
|
|
@@ -1,12 +1,64 @@
|
|
1
1
|
module WebSocket
|
2
2
|
module Handshake
|
3
|
+
# Construct or parse a server WebSocket handshake.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# handshake = WebSocket::Handshake::Server.new
|
7
|
+
#
|
8
|
+
# # Parse client request
|
9
|
+
# @handshake << <<EOF
|
10
|
+
# GET /demo HTTP/1.1
|
11
|
+
# Upgrade: websocket
|
12
|
+
# Connection: Upgrade
|
13
|
+
# Host: example.com
|
14
|
+
# Sec-WebSocket-Origin: http://example.com
|
15
|
+
# Sec-WebSocket-Version: 17
|
16
|
+
# Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
17
|
+
#
|
18
|
+
# EOF
|
19
|
+
#
|
20
|
+
# # All data received?
|
21
|
+
# @handshake.finished?
|
22
|
+
#
|
23
|
+
# # No parsing errors?
|
24
|
+
# @handshake.valid?
|
25
|
+
#
|
26
|
+
# # Create response
|
27
|
+
# @handshake.to_s # HTTP/1.1 101 Switching Protocols
|
28
|
+
# # Upgrade: websocket
|
29
|
+
# # Connection: Upgrade
|
30
|
+
# # Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
31
|
+
#
|
3
32
|
class Server < Base
|
4
33
|
|
34
|
+
# Initialize new WebSocket Server
|
35
|
+
#
|
36
|
+
# @param [Hash] args Arguments for server
|
37
|
+
#
|
38
|
+
# @option args [Boolean] :secure If true then server will use wss:// protocol
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# Websocket::Handshake::Server.new(:secure => true)
|
5
42
|
def initialize(args = {})
|
6
43
|
super
|
7
44
|
@secure = !!args[:secure]
|
8
45
|
end
|
9
46
|
|
47
|
+
# Add text of request from Client. This method will parse content immediately and update version, state and error(if neccessary)
|
48
|
+
#
|
49
|
+
# @param [String] data Data to add
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# @handshake << <<EOF
|
53
|
+
# GET /demo HTTP/1.1
|
54
|
+
# Upgrade: websocket
|
55
|
+
# Connection: Upgrade
|
56
|
+
# Host: example.com
|
57
|
+
# Sec-WebSocket-Origin: http://example.com
|
58
|
+
# Sec-WebSocket-Version: 13
|
59
|
+
# Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
60
|
+
#
|
61
|
+
# EOF
|
10
62
|
def <<(data)
|
11
63
|
@data << data
|
12
64
|
if parse_data
|
@@ -14,12 +66,27 @@ module WebSocket
|
|
14
66
|
end
|
15
67
|
end
|
16
68
|
|
69
|
+
# Should send content to client after finished parsing?
|
70
|
+
# @return [Boolean] true
|
17
71
|
def should_respond?
|
18
72
|
true
|
19
73
|
end
|
20
74
|
|
75
|
+
# Host of server according to client header
|
76
|
+
# @return [String] host
|
77
|
+
def host
|
78
|
+
@headers["host"].to_s.split(":")[0].to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
# Port of server according to client header
|
82
|
+
# @return [String] port
|
83
|
+
def port
|
84
|
+
@headers["host"].to_s.split(":")[1]
|
85
|
+
end
|
86
|
+
|
21
87
|
private
|
22
88
|
|
89
|
+
# Set version of protocol basing on client requets. AFter cotting method calls include_version.
|
23
90
|
def set_version
|
24
91
|
@version = @headers['sec-websocket-version'].to_i if @headers['sec-websocket-version']
|
25
92
|
@version ||= @headers['sec-websocket-draft'].to_i if @headers['sec-websocket-draft']
|
@@ -28,6 +95,8 @@ module WebSocket
|
|
28
95
|
include_version
|
29
96
|
end
|
30
97
|
|
98
|
+
# Include set of methods for selected protocol version
|
99
|
+
# @return [Boolean] false if protocol number is unknown, otherwise true
|
31
100
|
def include_version
|
32
101
|
case @version
|
33
102
|
when 75 then extend Handler::Server75
|
@@ -40,6 +109,9 @@ module WebSocket
|
|
40
109
|
|
41
110
|
PATH = /^(\w+) (\/[^\s]*) HTTP\/1\.1$/
|
42
111
|
|
112
|
+
# Parse first line of Client response.
|
113
|
+
# @param [String] line Line to parse
|
114
|
+
# @return [Boolean] True if parsed correctly. False otherwise
|
43
115
|
def parse_first_line(line)
|
44
116
|
line_parts = line.match(PATH)
|
45
117
|
set_error(:invalid_header) and return unless line_parts
|
data/lib/websocket/version.rb
CHANGED
@@ -99,7 +99,7 @@ describe 'Incoming frame draft 03' do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
context "should raise error with too long frame" do
|
102
|
-
let(:encoded_text) { "\x04\x7F" + "a" * WebSocket
|
102
|
+
let(:encoded_text) { "\x04\x7F" + "a" * WebSocket.max_frame_size }
|
103
103
|
let(:decoded_text) { nil }
|
104
104
|
let(:error) { :frame_too_long }
|
105
105
|
|
@@ -99,7 +99,7 @@ describe 'Incoming frame draft 04' do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
context "should raise error with too long frame" do
|
102
|
-
let(:encoded_text) { "\x84\x7F" + "a" * WebSocket
|
102
|
+
let(:encoded_text) { "\x84\x7F" + "a" * WebSocket.max_frame_size }
|
103
103
|
let(:decoded_text) { nil }
|
104
104
|
let(:error) { :frame_too_long }
|
105
105
|
|
@@ -115,7 +115,7 @@ describe 'Incoming frame draft 05' do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
context "should raise error with too long frame" do
|
118
|
-
let(:encoded_text) { "\x84\x7F" + "a" * WebSocket
|
118
|
+
let(:encoded_text) { "\x84\x7F" + "a" * WebSocket.max_frame_size }
|
119
119
|
let(:decoded_text) { nil }
|
120
120
|
let(:error) { :frame_too_long }
|
121
121
|
|
@@ -115,7 +115,7 @@ describe 'Incoming frame draft 07' do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
context "should raise error with too long frame" do
|
118
|
-
let(:encoded_text) { "\x81\x7F" + "a" * WebSocket
|
118
|
+
let(:encoded_text) { "\x81\x7F" + "a" * WebSocket.max_frame_size }
|
119
119
|
let(:decoded_text) { nil }
|
120
120
|
let(:error) { :frame_too_long }
|
121
121
|
|
@@ -50,7 +50,7 @@ describe 'Incoming frame draft 75' do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
context "with too long frame" do
|
53
|
-
let(:encoded_text) { "\x00" + "a" * WebSocket
|
53
|
+
let(:encoded_text) { "\x00" + "a" * WebSocket.max_frame_size + "\xFF" }
|
54
54
|
let(:error) { :frame_too_long }
|
55
55
|
|
56
56
|
it_should_behave_like('valid_incoming_frame') unless RUBY_PLATFORM == "java"
|
@@ -4,7 +4,7 @@ describe 'Client draft 76 handshake' do
|
|
4
4
|
let(:handshake) { WebSocket::Handshake::Client.new({ :uri => 'ws://example.com/demo', :origin => 'http://example.com', :version => version }.merge(@request_params || {})) }
|
5
5
|
|
6
6
|
let(:version) { 76 }
|
7
|
-
let(:client_request) { client_handshake_76({ :key1 => handshake.key1, :key2 => handshake.key2, :key3 => handshake.key3 }.merge(@request_params || {})) }
|
7
|
+
let(:client_request) { client_handshake_76({ :key1 => handshake.send(:key1), :key2 => handshake.send(:key2), :key3 => handshake.send(:key3) }.merge(@request_params || {})) }
|
8
8
|
let(:server_response) { server_handshake_76({ :challenge => handshake.send(:challenge) }.merge(@request_params || {})) }
|
9
9
|
|
10
10
|
it_should_behave_like 'all client drafts'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: websocket
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -46,6 +46,7 @@ files:
|
|
46
46
|
- examples/client.rb
|
47
47
|
- examples/server.rb
|
48
48
|
- examples/tests/autobahn_client.rb
|
49
|
+
- examples/tests/autobahn_server.rb
|
49
50
|
- examples/tests/echo_client.rb
|
50
51
|
- examples/tests/echo_server.rb
|
51
52
|
- lib/websocket.rb
|
@@ -120,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
121
|
version: '0'
|
121
122
|
segments:
|
122
123
|
- 0
|
123
|
-
hash:
|
124
|
+
hash: 221385565863631789
|
124
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
126
|
none: false
|
126
127
|
requirements:
|
@@ -129,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
130
|
version: '0'
|
130
131
|
segments:
|
131
132
|
- 0
|
132
|
-
hash:
|
133
|
+
hash: 221385565863631789
|
133
134
|
requirements: []
|
134
135
|
rubyforge_project:
|
135
136
|
rubygems_version: 1.8.24
|