websocket 1.2.3 → 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +17 -0
- data/.github/workflows/publish.yml +17 -0
- data/.rubocop.yml +35 -3
- data/.travis.yml +14 -7
- data/CHANGELOG.md +24 -0
- data/Gemfile +12 -4
- data/README.md +3 -2
- data/Rakefile +8 -3
- data/lib/websocket.rb +4 -1
- data/lib/websocket/error.rb +8 -0
- data/lib/websocket/exception_handler.rb +3 -1
- data/lib/websocket/frame.rb +2 -0
- data/lib/websocket/frame/base.rb +5 -9
- data/lib/websocket/frame/data.rb +5 -2
- data/lib/websocket/frame/handler.rb +2 -0
- data/lib/websocket/frame/handler/base.rb +6 -4
- data/lib/websocket/frame/handler/handler03.rb +23 -16
- data/lib/websocket/frame/handler/handler04.rb +1 -0
- data/lib/websocket/frame/handler/handler05.rb +1 -0
- data/lib/websocket/frame/handler/handler07.rb +10 -9
- data/lib/websocket/frame/handler/handler75.rb +8 -7
- data/lib/websocket/frame/incoming.rb +2 -0
- data/lib/websocket/frame/incoming/client.rb +2 -0
- data/lib/websocket/frame/incoming/server.rb +2 -0
- data/lib/websocket/frame/outgoing.rb +3 -1
- data/lib/websocket/frame/outgoing/client.rb +2 -0
- data/lib/websocket/frame/outgoing/server.rb +2 -0
- data/lib/websocket/handshake.rb +2 -0
- data/lib/websocket/handshake/base.rb +26 -13
- data/lib/websocket/handshake/client.rb +17 -14
- data/lib/websocket/handshake/handler.rb +2 -0
- data/lib/websocket/handshake/handler/base.rb +2 -0
- data/lib/websocket/handshake/handler/client.rb +11 -0
- data/lib/websocket/handshake/handler/client01.rb +2 -0
- data/lib/websocket/handshake/handler/client04.rb +15 -4
- data/lib/websocket/handshake/handler/client11.rb +2 -0
- data/lib/websocket/handshake/handler/client75.rb +18 -2
- data/lib/websocket/handshake/handler/client76.rb +11 -5
- data/lib/websocket/handshake/handler/server.rb +2 -0
- data/lib/websocket/handshake/handler/server04.rb +12 -4
- data/lib/websocket/handshake/handler/server75.rb +21 -5
- data/lib/websocket/handshake/handler/server76.rb +14 -16
- data/lib/websocket/handshake/server.rb +7 -4
- data/lib/websocket/nice_inspect.rb +12 -0
- data/lib/websocket/version.rb +3 -1
- data/spec/frame/incoming_03_spec.rb +20 -17
- data/spec/frame/incoming_04_spec.rb +20 -17
- data/spec/frame/incoming_05_spec.rb +22 -19
- data/spec/frame/incoming_07_spec.rb +24 -21
- data/spec/frame/incoming_75_spec.rb +13 -10
- data/spec/frame/incoming_common_spec.rb +18 -8
- data/spec/frame/masking_spec.rb +3 -1
- data/spec/frame/outgoing_03_spec.rb +13 -10
- data/spec/frame/outgoing_04_spec.rb +13 -10
- data/spec/frame/outgoing_05_spec.rb +12 -9
- data/spec/frame/outgoing_07_spec.rb +13 -10
- data/spec/frame/outgoing_75_spec.rb +8 -5
- data/spec/frame/outgoing_common_spec.rb +11 -4
- data/spec/handshake/client_04_spec.rb +46 -3
- data/spec/handshake/client_11_spec.rb +5 -3
- data/spec/handshake/client_75_spec.rb +28 -1
- data/spec/handshake/client_76_spec.rb +30 -3
- data/spec/handshake/server_04_spec.rb +37 -4
- data/spec/handshake/server_75_spec.rb +25 -1
- data/spec/handshake/server_76_spec.rb +33 -9
- data/spec/spec_helper.rb +2 -2
- data/spec/support/all_client_drafts.rb +23 -21
- data/spec/support/all_server_drafts.rb +21 -16
- data/spec/support/frames_base.rb +2 -0
- data/spec/support/handshake_requests.rb +19 -17
- data/spec/support/incoming_frames.rb +46 -25
- data/spec/support/outgoing_frames.rb +30 -8
- data/spec/support/overwrites.rb +2 -0
- data/websocket.gemspec +4 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7060e7e52081f894382fcfd1d67a8f3eda15b3b0c86abf4e5dea1f44e6f1c204
|
4
|
+
data.tar.gz: 93981161e7d5ded1e8182d67dd357ffc9a4c606b6bbbe6e84e7c03244db0a949
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b260ffa5fac7b49981fd876ebc6adc55ced481e84fce368b8d974565edd431b9b4c563c718e889c7fd6eb28f80d8a2f20f2734d0d261610068c2f37e40c380be
|
7
|
+
data.tar.gz: d3c905e52be9abe45ac1f8575b31876d7efffcebc1554a124620c6b19b7d2b4b38037a2a0c5bc2a181532af79b484ea951dfb47864aecd3c6a00686f929246d1
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
name: Publish Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v*
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
build:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- name: Release Gem
|
14
|
+
uses: cadwallion/publish-rubygems-action@master
|
15
|
+
env:
|
16
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
17
|
+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
|
data/.rubocop.yml
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
DisplayCopNames: true
|
5
|
+
TargetRubyVersion: 2.1
|
6
|
+
|
7
|
+
# New version of Rubocop does not support 2.0
|
8
|
+
Gemspec/RequiredRubyVersion:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Layout/IndentHeredoc:
|
12
|
+
Enabled: false
|
13
|
+
|
1
14
|
# Target: 15
|
2
15
|
Metrics/AbcSize:
|
3
16
|
Max: 24
|
@@ -5,6 +18,10 @@ Metrics/AbcSize:
|
|
5
18
|
- lib/websocket/frame/handler/handler75.rb
|
6
19
|
- spec/**/*
|
7
20
|
|
21
|
+
Metrics/BlockLength:
|
22
|
+
Exclude:
|
23
|
+
- spec/**/*
|
24
|
+
|
8
25
|
Metrics/ClassLength:
|
9
26
|
Enabled: false
|
10
27
|
|
@@ -30,8 +47,23 @@ Metrics/PerceivedComplexity:
|
|
30
47
|
- lib/websocket/frame/handler/handler75.rb
|
31
48
|
- spec/support/handshake_requests.rb
|
32
49
|
|
33
|
-
|
50
|
+
RSpec/ContextWording:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
RSpec/DescribeClass:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
RSpec/ExampleLength:
|
34
57
|
Enabled: false
|
35
58
|
|
36
|
-
|
37
|
-
|
59
|
+
RSpec/InstanceVariable:
|
60
|
+
Enabled: false
|
61
|
+
|
62
|
+
RSpec/MultipleExpectations:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
RSpec/NamedSubject:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
Style/Documentation:
|
69
|
+
Enabled: false
|
data/.travis.yml
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
+
dist: trusty
|
1
2
|
language: ruby
|
2
|
-
script: "bundle exec rake
|
3
|
+
script: "bundle exec rake"
|
3
4
|
rvm:
|
4
|
-
- 1.9.3
|
5
|
-
- 2.0
|
6
5
|
- 2.1
|
7
6
|
- 2.2
|
8
|
-
-
|
9
|
-
-
|
7
|
+
- 2.3
|
8
|
+
- 2.4
|
9
|
+
- 2.5
|
10
10
|
- ruby-head
|
11
|
-
|
12
|
-
-
|
11
|
+
- jruby-9.1.9.0 # https://github.com/travis-ci/travis-ci/issues/8446
|
12
|
+
- jruby-head
|
13
|
+
- rbx-3
|
14
|
+
|
15
|
+
matrix:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: ruby-head
|
18
|
+
- rvm: jruby-head
|
19
|
+
- rvm: rbx-3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.2.9
|
4
|
+
|
5
|
+
- avoid ruby -w warnings
|
6
|
+
|
7
|
+
## 1.2.8
|
8
|
+
|
9
|
+
- restore support for Ruby 2.0+
|
10
|
+
|
11
|
+
## 1.2.7
|
12
|
+
|
13
|
+
- fix bug in previous version for Ruby 2.3
|
14
|
+
|
15
|
+
## 1.2.6
|
16
|
+
|
17
|
+
- duplicate variables passed in initializers to avoid changing them
|
18
|
+
|
19
|
+
## 1.2.5
|
20
|
+
|
21
|
+
- make handshake server resilient to non-string Rack env keys
|
22
|
+
|
23
|
+
## 1.2.4
|
24
|
+
|
25
|
+
- add subprotocol handling for both server and client
|
26
|
+
|
3
27
|
## 1.2.3
|
4
28
|
|
5
29
|
- fix for draft 76 when challenge might sometimes fail
|
data/Gemfile
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'http://rubygems.org'
|
2
4
|
|
3
|
-
|
5
|
+
group :development do
|
6
|
+
gem 'rake'
|
7
|
+
gem 'rspec', '~> 3.7'
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
gem '
|
9
|
+
# Use same version as Code Climate for consistency with CI
|
10
|
+
# https://github.com/codeclimate/codeclimate-rubocop/blob/master/Gemfile.lock
|
11
|
+
gem 'rubocop', '0.52.1', require: false
|
12
|
+
gem 'rubocop-rspec', '1.21.0', require: false
|
13
|
+
end
|
14
|
+
|
15
|
+
gemspec
|
data/README.md
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
Universal Ruby library to handle WebSocket protocol. It focuses on providing abstraction layer over [WebSocket API](http://dev.w3.org/html5/websockets/) instead of providing server or client functionality.
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/websocket.svg)](http://badge.fury.io/rb/websocket)
|
6
|
-
[![
|
7
|
-
[![
|
6
|
+
[![Gem Downloads](https://img.shields.io/gem/dt/websocket.svg?maxAge=2592000)](https://rubygems.org/gems/websocket)
|
7
|
+
[![Travis CI](https://travis-ci.org/imanel/websocket-ruby.svg)](http://travis-ci.org/imanel/websocket-ruby)
|
8
|
+
[![Code Climate](https://codeclimate.com/github/imanel/websocket-ruby.svg)](https://codeclimate.com/github/imanel/websocket-ruby)
|
8
9
|
|
9
10
|
**Autobahn tests:** [server](http://imanel.github.com/websocket-ruby/autobahn/server/), [client](http://imanel.github.com/websocket-ruby/autobahn/client/)
|
10
11
|
|
data/Rakefile
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
-
|
2
|
-
Bundler::GemHelper.install_tasks
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
require 'bundler'
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
5
8
|
|
6
9
|
RSpec::Core::RakeTask.new do |t|
|
7
10
|
t.rspec_opts = ['-c', '-f progress']
|
8
11
|
t.pattern = 'spec/**/*_spec.rb'
|
9
12
|
end
|
10
13
|
|
11
|
-
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[spec rubocop]
|
12
17
|
|
13
18
|
namespace :autobahn do
|
14
19
|
desc 'Run autobahn tests for client'
|
data/lib/websocket.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# WebSocket protocol implementation in Ruby
|
2
4
|
# This module does not provide a WebSocket server or client, but is made for using
|
3
5
|
# in http servers or clients to provide WebSocket support.
|
@@ -6,12 +8,13 @@
|
|
6
8
|
module WebSocket
|
7
9
|
# Default WebSocket version to use
|
8
10
|
DEFAULT_VERSION = 13
|
9
|
-
ROOT =
|
11
|
+
ROOT = __dir__
|
10
12
|
|
11
13
|
autoload :Error, "#{ROOT}/websocket/error"
|
12
14
|
autoload :ExceptionHandler, "#{ROOT}/websocket/exception_handler"
|
13
15
|
autoload :Frame, "#{ROOT}/websocket/frame"
|
14
16
|
autoload :Handshake, "#{ROOT}/websocket/handshake"
|
17
|
+
autoload :NiceInspect, "#{ROOT}/websocket/nice_inspect"
|
15
18
|
|
16
19
|
# Limit of frame size payload in bytes
|
17
20
|
def self.max_frame_size
|
data/lib/websocket/error.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebSocket
|
2
4
|
class Error < RuntimeError
|
3
5
|
class Frame < ::WebSocket::Error
|
@@ -99,6 +101,12 @@ module WebSocket
|
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
104
|
+
class UnsupportedProtocol < ::WebSocket::Error::Handshake
|
105
|
+
def message
|
106
|
+
:unsupported_protocol
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
102
110
|
class InvalidStatusCode < ::WebSocket::Error::Handshake
|
103
111
|
def message
|
104
112
|
:invalid_status_code
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebSocket
|
2
4
|
module ExceptionHandler
|
3
5
|
attr_accessor :error
|
@@ -12,7 +14,7 @@ module WebSocket
|
|
12
14
|
# @param [String] method_name Name of method that should be wrapped and rescued
|
13
15
|
# @param [Hash] options Options for rescue
|
14
16
|
#
|
15
|
-
# @
|
17
|
+
# @option options [Any] :return Value that should be returned instead of raised error
|
16
18
|
def rescue_method(method_name, options = {})
|
17
19
|
define_method "#{method_name}_with_rescue" do |*args|
|
18
20
|
begin
|
data/lib/websocket/frame.rb
CHANGED
data/lib/websocket/frame/base.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebSocket
|
2
4
|
module Frame
|
3
5
|
# @abstract Subclass and override to implement custom frames
|
4
6
|
class Base
|
5
7
|
include ExceptionHandler
|
8
|
+
include NiceInspect
|
6
9
|
|
7
10
|
attr_reader :type, :version, :error
|
8
11
|
attr_accessor :data, :code
|
@@ -36,14 +39,7 @@ module WebSocket
|
|
36
39
|
|
37
40
|
# Implement in submodules
|
38
41
|
def supported_frames
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
# Recreate inspect as #to_s was overwritten
|
43
|
-
def inspect
|
44
|
-
vars = instance_variables.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(', ')
|
45
|
-
insp = Kernel.format("#{self.class}:0x%08x", __id__)
|
46
|
-
"<#{insp} #{vars}>"
|
42
|
+
raise NotImplementedError
|
47
43
|
end
|
48
44
|
|
49
45
|
private
|
@@ -58,7 +54,7 @@ module WebSocket
|
|
58
54
|
when 4 then Handler::Handler04.new(self)
|
59
55
|
when 5..6 then Handler::Handler05.new(self)
|
60
56
|
when 7..13 then Handler::Handler07.new(self)
|
61
|
-
else
|
57
|
+
else raise WebSocket::Error::Frame::UnknownVersion
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
data/lib/websocket/frame/data.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebSocket
|
2
4
|
module Frame
|
3
5
|
class Data < String
|
4
6
|
def initialize(*args)
|
5
7
|
super(*convert_args(args))
|
8
|
+
@masking_key = nil
|
6
9
|
end
|
7
10
|
|
8
11
|
def <<(*args)
|
@@ -11,12 +14,12 @@ module WebSocket
|
|
11
14
|
|
12
15
|
# Convert all arguments to ASCII-8BIT for easier traversing
|
13
16
|
def convert_args(args)
|
14
|
-
args.
|
17
|
+
args.collect { |arg| arg.dup.force_encoding('ASCII-8BIT') }
|
15
18
|
end
|
16
19
|
|
17
20
|
# Extract mask from 4 first bytes according to spec
|
18
21
|
def set_mask
|
19
|
-
|
22
|
+
raise WebSocket::Error::Frame::MaskTooShort if bytesize < 4
|
20
23
|
@masking_key = self[0..3].bytes.to_a
|
21
24
|
end
|
22
25
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebSocket
|
2
4
|
module Frame
|
3
5
|
module Handler
|
@@ -9,13 +11,13 @@ module WebSocket
|
|
9
11
|
# Convert data to raw frame ready to send to client
|
10
12
|
# @return [String] Encoded frame
|
11
13
|
def encode_frame
|
12
|
-
|
14
|
+
raise NotImplementedError
|
13
15
|
end
|
14
16
|
|
15
17
|
# Convert raw data to decoded frame
|
16
18
|
# @return [WebSocket::Frame::Incoming] Frame if found, nil otherwise
|
17
19
|
def decode_frame
|
18
|
-
|
20
|
+
raise NotImplementedError
|
19
21
|
end
|
20
22
|
|
21
23
|
private
|
@@ -24,14 +26,14 @@ module WebSocket
|
|
24
26
|
# @param [Symbol] frame_type Frame type
|
25
27
|
# @return [Boolean] True if given frame type is control frame
|
26
28
|
def control_frame?(frame_type)
|
27
|
-
|
29
|
+
!%i[text binary continuation].include?(frame_type)
|
28
30
|
end
|
29
31
|
|
30
32
|
# Check if frame is one of data frames
|
31
33
|
# @param [Symbol] frame_type Frame type
|
32
34
|
# @return [Boolean] True if given frame type is data frame
|
33
35
|
def data_frame?(frame_type)
|
34
|
-
[
|
36
|
+
%i[text binary].include?(frame_type)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'securerandom'
|
3
5
|
|
4
6
|
module WebSocket
|
@@ -13,14 +15,19 @@ module WebSocket
|
|
13
15
|
pong: 3,
|
14
16
|
text: 4,
|
15
17
|
binary: 5
|
16
|
-
}
|
18
|
+
}.freeze
|
17
19
|
|
18
20
|
# Hash of frame opcodes and it's names
|
19
|
-
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
21
|
+
FRAME_TYPES_INVERSE = FRAME_TYPES.invert.freeze
|
22
|
+
|
23
|
+
def initialize(frame)
|
24
|
+
super
|
25
|
+
@application_data_buffer = nil
|
26
|
+
end
|
20
27
|
|
21
28
|
# @see WebSocket::Frame::Base#supported_frames
|
22
29
|
def supported_frames
|
23
|
-
[
|
30
|
+
%i[text binary close ping pong]
|
24
31
|
end
|
25
32
|
|
26
33
|
# @see WebSocket::Frame::Handler::Base#encode_frame
|
@@ -50,7 +57,7 @@ module WebSocket
|
|
50
57
|
elsif frame_type == :continuation
|
51
58
|
return decode_finish_continuation_frame(application_data)
|
52
59
|
else
|
53
|
-
|
60
|
+
raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
|
54
61
|
return @frame.class.new(version: @frame.version, type: frame_type, data: application_data, decoded: true)
|
55
62
|
end
|
56
63
|
end
|
@@ -74,7 +81,7 @@ module WebSocket
|
|
74
81
|
# @return [Integer] opcode or nil
|
75
82
|
# @raise [WebSocket::Error] if frame opcode is not known
|
76
83
|
def type_to_opcode(frame_type)
|
77
|
-
FRAME_TYPES[frame_type] ||
|
84
|
+
FRAME_TYPES[frame_type] || raise(WebSocket::Error::Frame::UnknownFrameType)
|
78
85
|
end
|
79
86
|
|
80
87
|
# Convert frame opcode to type name
|
@@ -82,20 +89,20 @@ module WebSocket
|
|
82
89
|
# @return [Symbol] Frame type name or nil
|
83
90
|
# @raise [WebSocket::Error] if frame type name is not known
|
84
91
|
def opcode_to_type(opcode)
|
85
|
-
FRAME_TYPES_INVERSE[opcode] ||
|
92
|
+
FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error::Frame::UnknownOpcode)
|
86
93
|
end
|
87
94
|
|
88
95
|
def encode_header
|
89
96
|
mask = @frame.outgoing_masking? ? 0b10000000 : 0b00000000
|
90
97
|
|
91
|
-
output = ''
|
98
|
+
output = String.new('')
|
92
99
|
output << (type_to_opcode(@frame.type) | (fin ? 0b10000000 : 0b00000000)) # since more, rsv1-3 are 0 and 0x80 for Draft 4
|
93
100
|
output << encode_payload_length(@frame.data.size, mask)
|
94
101
|
output
|
95
102
|
end
|
96
103
|
|
97
104
|
def encode_payload_length(length, mask)
|
98
|
-
output = ''
|
105
|
+
output = String.new('')
|
99
106
|
if length <= 125
|
100
107
|
output << (length | mask) # since rsv4 is 0
|
101
108
|
elsif length < 65_536 # write 2 byte length
|
@@ -117,7 +124,7 @@ module WebSocket
|
|
117
124
|
frame_length = header_length + payload_length
|
118
125
|
frame_length += 4 if mask
|
119
126
|
|
120
|
-
|
127
|
+
raise(WebSocket::Error::Frame::TooLong) if frame_length > WebSocket.max_frame_size
|
121
128
|
|
122
129
|
# Check buffer size
|
123
130
|
return unless buffer_exists?(frame_length) # Buffer incomplete
|
@@ -135,13 +142,13 @@ module WebSocket
|
|
135
142
|
def decode_first_byte
|
136
143
|
first_byte = @frame.data.getbyte(0)
|
137
144
|
|
138
|
-
|
145
|
+
raise(WebSocket::Error::Frame::ReservedBitUsed) if first_byte & 0b01110000 != 0b00000000
|
139
146
|
|
140
147
|
more = ((first_byte & 0b10000000) == 0b10000000) ^ fin
|
141
148
|
frame_type = opcode_to_type first_byte & 0b00001111
|
142
149
|
|
143
|
-
|
144
|
-
|
150
|
+
raise(WebSocket::Error::Frame::FragmentedControlFrame) if more && control_frame?(frame_type)
|
151
|
+
raise(WebSocket::Error::Frame::DataFrameInsteadContinuation) if data_frame?(frame_type) && !@application_data_buffer.nil?
|
145
152
|
|
146
153
|
[more, frame_type]
|
147
154
|
end
|
@@ -152,7 +159,7 @@ module WebSocket
|
|
152
159
|
mask = @frame.incoming_masking? && (second_byte & 0b10000000) == 0b10000000
|
153
160
|
length = second_byte & 0b01111111
|
154
161
|
|
155
|
-
|
162
|
+
raise(WebSocket::Error::Frame::ControlFramePayloadTooLong) if length > 125 && control_frame?(frame_type)
|
156
163
|
|
157
164
|
header_length, payload_length = decode_payload_length(length)
|
158
165
|
|
@@ -196,16 +203,16 @@ module WebSocket
|
|
196
203
|
end
|
197
204
|
|
198
205
|
def decode_continuation_frame(application_data, frame_type)
|
199
|
-
@application_data_buffer ||= ''
|
206
|
+
@application_data_buffer ||= String.new('')
|
200
207
|
@application_data_buffer << application_data
|
201
208
|
@frame_type ||= frame_type
|
202
209
|
end
|
203
210
|
|
204
211
|
def decode_finish_continuation_frame(application_data)
|
205
|
-
|
212
|
+
raise(WebSocket::Error::Frame::UnexpectedContinuationFrame) unless @frame_type
|
206
213
|
@application_data_buffer << application_data
|
207
214
|
# Test valid UTF-8 encoding
|
208
|
-
|
215
|
+
raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
|
209
216
|
message = @frame.class.new(version: @frame.version, type: @frame_type, data: @application_data_buffer, decoded: true)
|
210
217
|
@application_data_buffer = nil
|
211
218
|
@frame_type = nil
|