protocol-websocket 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7a0f15089bc637ca5755d75a9cea1f219ad1b4903ad7d267f1faf26021bf050d
4
+ data.tar.gz: c1e73cce6d131bbb0ef398144c48b08ea6439c46268ff1c12ab1f12679b1c8aa
5
+ SHA512:
6
+ metadata.gz: 0a2f6af33312ea2d00a13124422344a7dfbd1ba01077ffd8747ba8ab7125626bd6d2a8dfe69b28d29417f790dc247c49e87174bb4a74fe2b87919f27c54721f7
7
+ data.tar.gz: 52b56ed1c83b0fe0869fffa67a90ea01650020104eef81dce01ee151e911035df6c8b5df4a493fac36f76a6e1a9cd4a744cb046373e8139cd23ff9ebf34409d7
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --warnings
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ dist: xenial
3
+ cache: bundler
4
+
5
+ matrix:
6
+ include:
7
+ - rvm: 2.4
8
+ - rvm: 2.5
9
+ - rvm: 2.6
10
+ - rvm: 2.6
11
+ env: COVERAGE=PartialSummary,Coveralls
12
+ - rvm: truffleruby
13
+ - rvm: jruby-head
14
+ env: JRUBY_OPTS="--debug -X+O"
15
+ - rvm: ruby-head
16
+ allow_failures:
17
+ - rvm: truffleruby
18
+ - rvm: ruby-head
19
+ - rvm: jruby-head
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in protocol-websocket.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Protocol::WebSocket
2
+
3
+ Provides a low-level implementation of the WebSocket protocol according to [RFC6455](https://tools.ietf.org/html/rfc6455). It only implements the latest stable version (13).
4
+
5
+ [![Build Status](https://secure.travis-ci.com/socketry/protocol-websocket.svg)](http://travis-ci.com/socketry/protocol-websocket)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'protocol-websocket'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install protocol-websocket
22
+
23
+ ## Usage
24
+
25
+ Here is a basic WebSocket client:
26
+
27
+ ```ruby
28
+ stream = # connect to remote system
29
+ framer = Protocol::WebSocket::Framer.new(stream)
30
+
31
+ frame = framer.read_frame
32
+ ```
33
+
34
+ ## Contributing
35
+
36
+ 1. Fork it
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create new Pull Request
41
+
42
+ ## License
43
+
44
+ Released under the MIT license.
45
+
46
+ Copyright, 2019, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining a copy
49
+ of this software and associated documentation files (the "Software"), to deal
50
+ in the Software without restriction, including without limitation the rights
51
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52
+ copies of the Software, and to permit persons to whom the Software is
53
+ furnished to do so, subject to the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be included in
56
+ all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'websocket/version'
22
+ require_relative 'websocket/framer'
@@ -0,0 +1,31 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'digest/sha1'
22
+
23
+ module Protocol
24
+ module WebSocket
25
+ GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
26
+
27
+ def self.accept_digest(key)
28
+ Digest::SHA1.base64digest(key + GUID)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'protocol/http/error'
22
+
23
+ module Protocol
24
+ module WebSocket
25
+ class BadRequest < HTTP::BadRequest
26
+ end
27
+
28
+ class ProtocolError < HTTP::ProtocolError
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,204 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'error'
22
+
23
+ module Protocol
24
+ module WebSocket
25
+ class Frame
26
+ include Comparable
27
+
28
+ # Opcodes
29
+ CONTINUATION = 0x0
30
+ TEXT = 0x1
31
+ BINARY = 0x2
32
+ CLOSE = 0x8
33
+ PING = 0x9
34
+ PONG = 0xA
35
+
36
+ # @param length [Integer] the length of the payload, or nil if the header has not been read yet.
37
+ def initialize(fin = true, opcode = 0, mask = nil, payload = nil)
38
+ @fin = fin
39
+ @opcode = opcode
40
+ @mask = mask
41
+ @length = payload&.bytesize
42
+ @payload = payload
43
+ end
44
+
45
+ def self.read(stream)
46
+ frame = self.new
47
+
48
+ if frame.read(stream)
49
+ return frame
50
+ end
51
+ rescue EOFError
52
+ return nil
53
+ end
54
+
55
+ def <=> other
56
+ to_ary <=> other.to_ary
57
+ end
58
+
59
+ def to_ary
60
+ [@fin, @opcode, @mask, @length, @payload]
61
+ end
62
+
63
+ def control?
64
+ @opcode & 0x8
65
+ end
66
+
67
+ def continued?
68
+ @fin == false
69
+ end
70
+
71
+ # The generic frame header uses the following binary representation:
72
+ #
73
+ # 0 1 2 3
74
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
75
+ # +-+-+-+-+-------+-+-------------+-------------------------------+
76
+ # |F|R|R|R| opcode|M| Payload len | Extended payload length |
77
+ # |I|S|S|S| (4) |A| (7) | (16/64) |
78
+ # |N|V|V|V| |S| | (if payload len==126/127) |
79
+ # | |1|2|3| |K| | |
80
+ # +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
81
+ # | Extended payload length continued, if payload len == 127 |
82
+ # + - - - - - - - - - - - - - - - +-------------------------------+
83
+ # | |Masking-key, if MASK set to 1 |
84
+ # +-------------------------------+-------------------------------+
85
+ # | Masking-key (continued) | Payload Data |
86
+ # +-------------------------------- - - - - - - - - - - - - - - - +
87
+ # : Payload Data continued ... :
88
+ # + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
89
+ # | Payload Data continued ... |
90
+ # +---------------------------------------------------------------+
91
+
92
+ attr_accessor :fin
93
+ attr_accessor :opcode
94
+ attr_accessor :mask
95
+ attr_accessor :length
96
+ attr_accessor :payload
97
+
98
+ def unpack
99
+ @payload
100
+ end
101
+
102
+ def pack(payload)
103
+ @payload = payload
104
+ @length = payload.bytesize
105
+
106
+ if @length.bit_length > 64
107
+ raise ProtocolError, "Frame length #{@length} bigger than allowed 64-bit field!"
108
+ end
109
+ end
110
+
111
+ def read(stream)
112
+ buffer = stream.read(2) or raise EOFError
113
+ first, second = buffer.unpack("CC")
114
+
115
+ @fin = (first & 0b1000_0000 != 0)
116
+ # rsv = byte & 0b0111_0000
117
+ @opcode = first & 0b0000_1111
118
+
119
+ @mask = (second & 0b1000_0000 != 0)
120
+ @length = second & 0b0111_1111
121
+
122
+ if @length == 126
123
+ buffer = stream.read(2) or raise EOFError
124
+ @length = buffer.unpack('n').first
125
+ elsif @length == 127
126
+ buffer = stream.read(4) or raise EOFError
127
+ @length = buffer.unpack('Q>').first
128
+ end
129
+
130
+ if @mask
131
+ @mask = stream.read(4) or raise EOFError
132
+ @payload = read_mask(@mask, @length, stream)
133
+ else
134
+ @mask = nil
135
+ @payload = stream.read(@length) or raise EOFError
136
+ end
137
+
138
+ if @payload&.bytesize != @length
139
+ raise ProtocolError, "Invalid payload size: #{@length} != #{@payload.bytesize}!"
140
+ end
141
+
142
+ return true
143
+ end
144
+
145
+ def write(stream)
146
+ buffer = String.new.b
147
+
148
+ if @payload&.bytesize != @length
149
+ raise ProtocolError, "Invalid payload size: #{@length} != #{@payload.bytesize}!"
150
+ end
151
+
152
+ if @mask and @mask.bytesize != 4
153
+ raise ProtocolError, "Invalid mask length!"
154
+ end
155
+
156
+ if length <= 125
157
+ short_length = length
158
+ elsif length.bit_length <= 16
159
+ short_length = 126
160
+ else
161
+ short_length = 127
162
+ end
163
+
164
+ buffer << [
165
+ (@fin ? 0b1000_0000 : 0) | @opcode,
166
+ (@mask ? 0b1000_0000 : 0) | short_length,
167
+ ].pack('CC')
168
+
169
+ if short_length == 126
170
+ buffer << [@length].pack('n')
171
+ elsif short_length == 127
172
+ buffer << [@length].pack('Q>')
173
+ end
174
+
175
+ if @mask
176
+ buffer << @mask
177
+ write_mask(@mask, @payload, buffer)
178
+ stream.write(buffer)
179
+ else
180
+ stream.write(buffer)
181
+ stream.write(@payload)
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ def read_mask(mask, length, stream)
188
+ data = stream.read(length) or raise EOFError
189
+
190
+ for i in 0...data.bytesize do
191
+ data.setbyte(i, data.getbyte(i) ^ mask.getbyte(i % 4))
192
+ end
193
+
194
+ return data
195
+ end
196
+
197
+ def write_mask(mask, data, buffer)
198
+ for i in 0...data.bytesize do
199
+ buffer << (data.getbyte(i) ^ mask.getbyte(i % 4))
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+
23
+ module Protocol
24
+ module WebSocket
25
+ class Framer
26
+ def initialize(stream)
27
+ @stream = stream
28
+ end
29
+
30
+ def close
31
+ @stream.close
32
+ end
33
+
34
+ def flush
35
+ @stream.flush
36
+ end
37
+
38
+ def read_frame
39
+ Frame.read(@stream)
40
+ end
41
+
42
+ def read_message
43
+
44
+ end
45
+
46
+ def write_message(opcode, payload)
47
+ end
48
+
49
+ def write_frame(frame)
50
+ frame.write(@stream)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Protocol
22
+ module WebSocket
23
+ VERSION = "0.1.0"
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+
2
+ require_relative "lib/protocol/websocket/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "protocol-websocket"
6
+ spec.version = Protocol::WebSocket::VERSION
7
+ spec.authors = ["Samuel Williams"]
8
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
+
10
+ spec.summary = "A low level implementation of the WebSocket protocol."
11
+ spec.homepage = "https://github.com/socketry/protocol-websocket"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
15
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ end
17
+
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "protocol-http"
22
+
23
+ spec.add_development_dependency "covered"
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: protocol-websocket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: protocol-http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: covered
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description:
84
+ email:
85
+ - samuel.williams@oriontransfer.co.nz
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - lib/protocol/websocket.rb
97
+ - lib/protocol/websocket/digest.rb
98
+ - lib/protocol/websocket/error.rb
99
+ - lib/protocol/websocket/frame.rb
100
+ - lib/protocol/websocket/framer.rb
101
+ - lib/protocol/websocket/version.rb
102
+ - protocol-websocket.gemspec
103
+ homepage: https://github.com/socketry/protocol-websocket
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.0.2
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A low level implementation of the WebSocket protocol.
126
+ test_files: []