Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a75062f38d | |||
| 7f98c533dc | |||
| e5406a7575 | |||
| dfa7cae1e8 | |||
| 2e28257863 | |||
| a3caf0bf78 | |||
| 95051a28ce | |||
| 7be2003001 | |||
| 7b92a67806 | |||
| c03d8f2ef8 | |||
| 167a7f9a8d | |||
| 76422c3b41 | |||
| b2168fca78 | |||
| 1cb01d1304 | |||
| e0e7a26511 | |||
| 2e9ad522d1 | |||
| 966f48a980 | |||
| f88d2aa918 | |||
| 673dae1dda | |||
| 81702d4162 | |||
| 8c072d0d65 | |||
| 33223453a2 | |||
| db21758f3b | |||
| 5fa83fd517 | |||
| bae484c69d | |||
| 9c57240cfb | |||
| bbef7fbbcb | |||
| d5238e2837 | |||
| 8cc90986cf | |||
| 7737036691 | |||
| 0fc8ea74db | |||
| efb40b3b8e | |||
| c24da157a0 | |||
| 7c1f34a9c6 | |||
| 610feed4c8 | |||
| 301f1876ea |
@@ -0,0 +1,34 @@
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ruby:
|
||||
- ruby-2.0
|
||||
- ruby-2.1
|
||||
# - ruby-2.2
|
||||
- ruby-2.3
|
||||
- ruby-2.4
|
||||
- ruby-2.5
|
||||
- ruby-2.6
|
||||
- ruby-2.7
|
||||
- ruby-3.0
|
||||
- ruby-3.1
|
||||
- ruby-3.2
|
||||
- jruby-9.1
|
||||
- jruby-9.2
|
||||
- jruby-9.3
|
||||
- jruby-9.4
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
- run: ruby --version
|
||||
- run: bundle exec rspec
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
language: ruby
|
||||
|
||||
rvm:
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
- 2.1.3
|
||||
- jruby-19mode
|
||||
- rbx-2.2
|
||||
|
||||
script: bundle exec rspec -c spec/
|
||||
@@ -0,0 +1,21 @@
|
||||
### 0.1.4 / 2017-09-10
|
||||
|
||||
- Use `9` instead of `8` as the `windowBits` parameter to zlib, to deal with
|
||||
restrictions introduced in zlib v1.2.9
|
||||
|
||||
### 0.1.3 / 2016-05-20
|
||||
|
||||
- Amend all warnings issued when running with -W2
|
||||
|
||||
### 0.1.2 / 2015-11-06
|
||||
|
||||
- The server does not send `server_max_window_bits` if the client does not ask
|
||||
for it; this works around an issue in Firefox.
|
||||
|
||||
### 0.1.1 / 2014-12-18
|
||||
|
||||
- Don't allow configure() to be called with unrecognized options
|
||||
|
||||
### 0.1.0 / 2014-12-13
|
||||
|
||||
- Initial release
|
||||
@@ -0,0 +1,4 @@
|
||||
# Code of Conduct
|
||||
|
||||
All projects under the [Faye](https://github.com/faye) umbrella are covered by
|
||||
the [Code of Conduct](https://github.com/faye/code-of-conduct).
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Copyright 2014-2017 James Coglan
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
@@ -1,4 +1,4 @@
|
||||
# permessage_deflate [](http://travis-ci.org/faye/permessage-deflate-ruby)
|
||||
# permessage_deflate
|
||||
|
||||
Implements the
|
||||
[permessage-deflate](https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression)
|
||||
@@ -11,7 +11,7 @@ WebSocket protocol extension as a plugin for
|
||||
$ gem install permessage_deflate
|
||||
```
|
||||
|
||||
## Usage
|
||||
## Usage
|
||||
|
||||
Add the plugin to your extensions:
|
||||
|
||||
@@ -40,52 +40,28 @@ exts.add(deflate)
|
||||
|
||||
The set of available options can be split into two sets: those that control the
|
||||
session's compressor for outgoing messages and do not need to be communicated to
|
||||
the peer, and those that are negoatiated as part of the protocol. The settings
|
||||
the peer, and those that are negotiated as part of the protocol. The settings
|
||||
only affecting the compressor are described fully in the [Zlib
|
||||
documentation](http://ruby-doc.org/stdlib-2.1.0/libdoc/zlib/rdoc/Zlib/Deflate.html#method-c-new):
|
||||
|
||||
* `:level`: sets the compression level, can be an integer from `0` to `9`, or
|
||||
one of the contants `Zlib::NO_COMPRESSION`, `Zlib::BEST_SPEED`,
|
||||
- `:level`: sets the compression level, can be an integer from `0` to `9`, or
|
||||
one of the constants `Zlib::NO_COMPRESSION`, `Zlib::BEST_SPEED`,
|
||||
`Zlib::BEST_COMPRESSION`, or `Zlib::DEFAULT_COMPRESSION`
|
||||
* `:mem_level`: sets how much memory the compressor allocates, can be an integer
|
||||
- `:mem_level`: sets how much memory the compressor allocates, can be an integer
|
||||
from `1` to `9`, or one of the constants `Zlib::MAX_MEM_LEVEL`, or
|
||||
`Zlib::DEF_MEM_LEVEL`
|
||||
* `:strategy`: can be one of the constants `Zlib::FILTERED`,
|
||||
- `:strategy`: can be one of the constants `Zlib::FILTERED`,
|
||||
`Zlib::HUFFMAN_ONLY`, `Zlib::RLE`, `Zlib::FIXED`, or `Zlib::DEFAULT_STRATEGY`
|
||||
|
||||
The other options relate to settings that are negotiated via the protocol and
|
||||
can be used to set the local session's behaviour and control that of the peer:
|
||||
|
||||
* `:no_context_takeover`: if `true`, stops the session reusing a deflate context
|
||||
- `:no_context_takeover`: if `true`, stops the session reusing a deflate context
|
||||
between messages
|
||||
* `:request_no_context_takeover`: if `true`, makes the session tell the other
|
||||
- `:request_no_context_takeover`: if `true`, makes the session tell the other
|
||||
peer not to reuse a deflate context between messages
|
||||
* `:max_window_bits`: an integer from `8` to `15` inclusive that sets the
|
||||
- `:max_window_bits`: an integer from `8` to `15` inclusive that sets the
|
||||
maximum size of the session's sliding window; a lower window size will be used
|
||||
if requested by the peer
|
||||
* `:request_max_window_bits`: an integer from `8` to `15` inclusive to ask the
|
||||
- `:request_max_window_bits`: an integer from `8` to `15` inclusive to ask the
|
||||
other peer to use to set its maximum sliding window size, if supported
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 James Coglan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the 'Software'), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -8,6 +8,24 @@ class PermessageDeflate
|
||||
|
||||
ConfigurationError = Class.new(ArgumentError)
|
||||
|
||||
VALID_OPTIONS = [
|
||||
:level,
|
||||
:mem_level,
|
||||
:strategy,
|
||||
:no_context_takeover,
|
||||
:max_window_bits,
|
||||
:request_no_context_takeover,
|
||||
:request_max_window_bits
|
||||
]
|
||||
|
||||
def self.validate_options(options, valid_keys)
|
||||
options.keys.each do |key|
|
||||
unless valid_keys.include?(key)
|
||||
raise ConfigurationError, "Unrecognized option: #{ key.inspect }"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Extension
|
||||
define_method(:name) { 'permessage-deflate' }
|
||||
define_method(:type) { 'permessage' }
|
||||
@@ -16,6 +34,9 @@ class PermessageDeflate
|
||||
define_method(:rsv3) { false }
|
||||
|
||||
def configure(options)
|
||||
@options ||= nil
|
||||
|
||||
PermessageDeflate.validate_options(options, VALID_OPTIONS)
|
||||
options = (@options || {}).merge(options)
|
||||
PermessageDeflate.new(options)
|
||||
end
|
||||
|
||||
@@ -59,12 +59,12 @@ class PermessageDeflate
|
||||
|
||||
@own_context_takeover = !(@accept_no_context_takeover || params['client_no_context_takeover'])
|
||||
@own_window_bits = [
|
||||
@accept_max_window_bits || DEFAULT_MAX_WINDOW_BITS,
|
||||
params['client_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
@accept_max_window_bits || MAX_WINDOW_BITS,
|
||||
params['client_max_window_bits'] || MAX_WINDOW_BITS
|
||||
].min
|
||||
|
||||
@peer_context_takeover = !params['server_no_context_takeover']
|
||||
@peer_window_bits = params['server_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
@peer_window_bits = params['server_max_window_bits'] || MAX_WINDOW_BITS
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@@ -17,42 +17,48 @@ class PermessageDeflate
|
||||
end
|
||||
|
||||
def generate_response
|
||||
params = {}
|
||||
response = {}
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.1
|
||||
if @accept_no_context_takeover or @params['server_no_context_takeover']
|
||||
params['server_no_context_takeover'] = true
|
||||
# https://tools.ietf.org/html/rfc7692#section-7.1.1.1
|
||||
|
||||
@own_context_takeover = !@accept_no_context_takeover &&
|
||||
!@params['server_no_context_takeover']
|
||||
|
||||
response['server_no_context_takeover'] = true unless @own_context_takeover
|
||||
|
||||
# https://tools.ietf.org/html/rfc7692#section-7.1.1.2
|
||||
|
||||
@peer_context_takeover = !@request_no_context_takeover &&
|
||||
!@params['client_no_context_takeover']
|
||||
|
||||
response['client_no_context_takeover'] = true unless @peer_context_takeover
|
||||
|
||||
# https://tools.ietf.org/html/rfc7692#section-7.1.2.1
|
||||
|
||||
@own_window_bits = [ @accept_max_window_bits || MAX_WINDOW_BITS,
|
||||
@params['server_max_window_bits'] || MAX_WINDOW_BITS
|
||||
].min
|
||||
|
||||
# In violation of the spec, Firefox closes the connection if it does not
|
||||
# send server_max_window_bits but the server includes this in its response
|
||||
if @own_window_bits < MAX_WINDOW_BITS and @params['server_max_window_bits']
|
||||
response['server_max_window_bits'] = @own_window_bits
|
||||
end
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.2
|
||||
if @request_no_context_takeover or @params['client_no_context_takeover']
|
||||
params['client_no_context_takeover'] = true
|
||||
end
|
||||
# https://tools.ietf.org/html/rfc7692#section-7.1.2.2
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.1
|
||||
if @accept_max_window_bits or @params['server_max_window_bits']
|
||||
accept_max = @accept_max_window_bits || DEFAULT_MAX_WINDOW_BITS
|
||||
server_max = @params['server_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
params['server_max_window_bits'] = [accept_max, server_max].min
|
||||
end
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.2
|
||||
if client_max = @params['client_max_window_bits']
|
||||
if client_max == true
|
||||
params['client_max_window_bits'] = @request_max_window_bits if @request_max_window_bits
|
||||
else
|
||||
request_max = @request_max_window_bits || DEFAULT_MAX_WINDOW_BITS
|
||||
params['client_max_window_bits'] = [request_max, client_max].min
|
||||
end
|
||||
client_max = MAX_WINDOW_BITS if client_max == true
|
||||
@peer_window_bits = [@request_max_window_bits || MAX_WINDOW_BITS, client_max].min
|
||||
else
|
||||
@peer_window_bits = MAX_WINDOW_BITS
|
||||
end
|
||||
|
||||
@own_context_takeover = !params['server_no_context_takeover']
|
||||
@own_window_bits = params['server_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
if @peer_window_bits < MAX_WINDOW_BITS
|
||||
response['client_max_window_bits'] = @peer_window_bits
|
||||
end
|
||||
|
||||
@peer_context_takeover = !params['client_no_context_takeover']
|
||||
@peer_window_bits = params['client_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
|
||||
params
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -8,7 +8,8 @@ class PermessageDeflate
|
||||
'client_max_window_bits'
|
||||
]
|
||||
|
||||
DEFAULT_MAX_WINDOW_BITS = 15
|
||||
MIN_WINDOW_BITS = 9
|
||||
MAX_WINDOW_BITS = 15
|
||||
VALID_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15]
|
||||
|
||||
def self.valid_params?(params)
|
||||
@@ -39,6 +40,8 @@ class PermessageDeflate
|
||||
@accept_max_window_bits = options.fetch(:max_window_bits, nil)
|
||||
@request_no_context_takeover = options.fetch(:request_no_context_takeover, false)
|
||||
@request_max_window_bits = options.fetch(:request_max_window_bits, nil)
|
||||
|
||||
@deflate = @inflate = nil
|
||||
end
|
||||
|
||||
def process_incoming_message(message)
|
||||
@@ -81,14 +84,20 @@ class PermessageDeflate
|
||||
|
||||
def get_inflate
|
||||
return @inflate if @inflate
|
||||
inflate = Zlib::Inflate.new(-@peer_window_bits)
|
||||
|
||||
window_bits = [@peer_window_bits, MIN_WINDOW_BITS].max
|
||||
inflate = Zlib::Inflate.new(-window_bits)
|
||||
|
||||
@inflate = inflate if @peer_context_takeover
|
||||
inflate
|
||||
end
|
||||
|
||||
def get_deflate
|
||||
return @deflate if @deflate
|
||||
deflate = Zlib::Deflate.new(@level, -@own_window_bits, @mem_level, @strategy)
|
||||
|
||||
window_bits = [@own_window_bits, MIN_WINDOW_BITS].max
|
||||
deflate = Zlib::Deflate.new(@level, -window_bits, @mem_level, @strategy)
|
||||
|
||||
@deflate = deflate if @own_context_takeover
|
||||
deflate
|
||||
end
|
||||
|
||||
+11
-11
@@ -1,17 +1,17 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = 'permessage_deflate'
|
||||
s.version = '0.1.0'
|
||||
s.summary = 'Per-message DEFLATE compression extension for WebSocket connections'
|
||||
s.author = 'James Coglan'
|
||||
s.email = 'jcoglan@gmail.com'
|
||||
s.homepage = 'http://github.com/faye/permessage-deflate-ruby'
|
||||
s.license = 'MIT'
|
||||
s.name = 'permessage_deflate'
|
||||
s.version = '0.1.4'
|
||||
s.summary = 'Per-message DEFLATE compression extension for WebSocket connections'
|
||||
s.author = 'James Coglan'
|
||||
s.email = 'jcoglan@gmail.com'
|
||||
s.homepage = 'https://github.com/faye/permessage-deflate-ruby'
|
||||
s.license = 'Apache-2.0'
|
||||
|
||||
s.extra_rdoc_files = %w[README.md]
|
||||
s.rdoc_options = %w[--main README.md --markup markdown]
|
||||
s.require_paths = %w[lib]
|
||||
s.extra_rdoc_files = %w[README.md]
|
||||
s.rdoc_options = %w[--main README.md --markup markdown]
|
||||
s.require_paths = %w[lib]
|
||||
|
||||
s.files = %w[README.md] + Dir.glob('lib/**/*.rb')
|
||||
s.files = %w[CHANGELOG.md LICENSE.md README.md] + Dir.glob('lib/**/*.rb')
|
||||
|
||||
s.add_development_dependency 'rspec'
|
||||
end
|
||||
|
||||
@@ -90,9 +90,9 @@ describe PermessageDeflate::ClientSession do
|
||||
expect(activate).to be true
|
||||
end
|
||||
|
||||
it "uses context takeover and 8 window bits for inflating incoming messages" do
|
||||
it "uses context takeover and 9 window bits for inflating incoming messages" do
|
||||
activate
|
||||
expect(Zlib::Inflate).to receive(:new).with(-8).exactly(1).and_return(inflate)
|
||||
expect(Zlib::Inflate).to receive(:new).with(-9).exactly(1).and_return(inflate)
|
||||
process_incoming_message
|
||||
process_incoming_message
|
||||
end
|
||||
@@ -113,9 +113,9 @@ describe PermessageDeflate::ClientSession do
|
||||
expect(activate).to be true
|
||||
end
|
||||
|
||||
it "uses context takeover and 8 window bits for deflating outgoing messages" do
|
||||
it "uses context takeover and 9 window bits for deflating outgoing messages" do
|
||||
activate
|
||||
expect(Zlib::Deflate).to receive(:new).with(level, -8, mem_level, strategy).exactly(1).and_return(deflate)
|
||||
expect(Zlib::Deflate).to receive(:new).with(level, -9, mem_level, strategy).exactly(1).and_return(deflate)
|
||||
process_outgoing_message
|
||||
process_outgoing_message
|
||||
end
|
||||
@@ -191,9 +191,9 @@ describe PermessageDeflate::ClientSession do
|
||||
expect(activate).to be true
|
||||
end
|
||||
|
||||
it "uses context takeover and 8 window bits for deflating outgoing messages" do
|
||||
it "uses context takeover and 9 window bits for deflating outgoing messages" do
|
||||
activate
|
||||
expect(Zlib::Deflate).to receive(:new).with(level, -8, mem_level, strategy).exactly(1).and_return(deflate)
|
||||
expect(Zlib::Deflate).to receive(:new).with(level, -9, mem_level, strategy).exactly(1).and_return(deflate)
|
||||
process_outgoing_message
|
||||
process_outgoing_message
|
||||
end
|
||||
@@ -204,7 +204,7 @@ describe PermessageDeflate::ClientSession do
|
||||
before { options[:max_window_bits] = 20 }
|
||||
|
||||
it "raises when generating the offer" do
|
||||
expect { offer }.to raise_error
|
||||
expect { offer }.to raise_error(PermessageDeflate::ConfigurationError)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -286,7 +286,7 @@ describe PermessageDeflate::ClientSession do
|
||||
before { options[:request_max_window_bits] = 20 }
|
||||
|
||||
it "raises when generating an offer" do
|
||||
expect { offer }.to raise_error
|
||||
expect { offer }.to raise_error(PermessageDeflate::ConfigurationError)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -163,8 +163,8 @@ describe PermessageDeflate::ServerSession do
|
||||
before { options[:max_window_bits] = 12 }
|
||||
|
||||
describe "with an empty offer" do
|
||||
it "includes server_max_window_bits in the response" do
|
||||
expect(response).to eq("server_max_window_bits" => 12)
|
||||
it "does not include server_max_window_bits in the response" do
|
||||
expect(response).to eq({})
|
||||
end
|
||||
|
||||
it "uses context takeover and 12 window bits for deflating outgoing messages" do
|
||||
|
||||
Reference in New Issue
Block a user