Implement ServerSession, passes Autobahn 12.1.*.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
Gemfile.lock
|
||||
*.gem
|
||||
@@ -0,0 +1,33 @@
|
||||
require 'zlib'
|
||||
|
||||
class PermessageDeflate
|
||||
VALID_PARAMS = [
|
||||
'server_no_context_takeover',
|
||||
'client_no_context_takeover',
|
||||
'server_max_window_bits',
|
||||
'client_max_window_bits'
|
||||
]
|
||||
|
||||
DEFAULT_MAX_WINDOW_BITS = 15
|
||||
VALID_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15]
|
||||
|
||||
root = File.expand_path('..', __FILE__)
|
||||
require root + '/permessage_deflate/session'
|
||||
require root + '/permessage_deflate/server_session'
|
||||
|
||||
module Extension
|
||||
define_method(:name) { 'permessage-deflate' }
|
||||
define_method(:type) { 'permessage' }
|
||||
define_method(:rsv1) { true }
|
||||
define_method(:rsv2) { false }
|
||||
define_method(:rsv3) { false }
|
||||
|
||||
def create_server_session(offers)
|
||||
offers.each do |offer|
|
||||
return ServerSession.new(offer) if ServerSession.valid_params?(offer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
extend Extension
|
||||
end
|
||||
@@ -0,0 +1,47 @@
|
||||
class PermessageDeflate
|
||||
class ServerSession < Session
|
||||
|
||||
def self.valid_params?(params)
|
||||
true # TODO
|
||||
end
|
||||
|
||||
def initialize(params)
|
||||
super()
|
||||
@params = params
|
||||
end
|
||||
|
||||
def generate_response
|
||||
params = {}
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.1
|
||||
if @params['server_no_context_takeover']
|
||||
params['server_no_context_takeover'] = true
|
||||
end
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.1.2
|
||||
if @params['client_no_context_takeover']
|
||||
params['client_no_context_takeover'] = true
|
||||
end
|
||||
|
||||
# https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression#section-8.1.2.1
|
||||
if server_max = @params['server_max_window_bits']
|
||||
params['server_max_window_bits'] = [server_max, DEFAULT_MAX_WINDOW_BITS].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']
|
||||
client_max = DEFAULT_MAX_WINDOW_BITS if client_max == true
|
||||
params['client_max_window_bits'] = [client_max, DEFAULT_MAX_WINDOW_BITS].min
|
||||
end
|
||||
|
||||
@own_context_takeover = !params['server_no_context_takeover']
|
||||
@own_window_bits = params['server_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
|
||||
@peer_context_takeover = !params['client_no_context_takeover']
|
||||
@peer_window_bits = params['client_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
|
||||
|
||||
params
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,75 @@
|
||||
class PermessageDeflate
|
||||
class Session
|
||||
|
||||
MESSAGE_OPCODES = [1, 2]
|
||||
|
||||
def valid_frame_rsv(frame)
|
||||
if MESSAGE_OPCODES.include?(frame.opcode)
|
||||
{:rsv1 => true, :rsv2 => false, :rsv3 => false}
|
||||
else
|
||||
{:rsv1 => false, :rsv2 => false, :rsv3 => false}
|
||||
end
|
||||
end
|
||||
|
||||
def process_incoming_message(message)
|
||||
compressed = message.frames.first.rsv1
|
||||
return message unless compressed
|
||||
|
||||
inflate = get_inflate
|
||||
|
||||
message.data = inflate.inflate(message.data) +
|
||||
inflate.inflate([0x00, 0x00, 0xff, 0xff].pack('C*'))
|
||||
|
||||
inflate.close unless @inflate
|
||||
message
|
||||
end
|
||||
|
||||
def process_outgoing_message(message)
|
||||
deflate = get_deflate
|
||||
payload = (deflate.deflate(message.data) + deflate.flush)[0...-4]
|
||||
frame = message.frames.first
|
||||
|
||||
deflate.close unless @deflate
|
||||
|
||||
frame.final = true
|
||||
frame.rsv1 = true
|
||||
frame.length = payload.bytesize
|
||||
frame.payload = payload
|
||||
|
||||
message.data = payload
|
||||
message.frames = [frame]
|
||||
|
||||
message
|
||||
end
|
||||
|
||||
def close
|
||||
@inflate.close if @inflate
|
||||
@inflate = nil
|
||||
|
||||
@deflate.close if @deflate
|
||||
@deflate = nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def f(string)
|
||||
bytes = string.bytes.map { |b| b.to_s(16).rjust(2, '0') }
|
||||
"<#{string.encoding}: #{bytes * ' '}>"
|
||||
end
|
||||
|
||||
def get_inflate
|
||||
return @inflate if @inflate
|
||||
inflate = Zlib::Inflate.new(-@peer_window_bits)
|
||||
@inflate = inflate if @peer_context_takeover
|
||||
inflate
|
||||
end
|
||||
|
||||
def get_deflate
|
||||
return @deflate if @deflate
|
||||
deflate = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -@own_window_bits)
|
||||
@deflate = deflate if @own_context_takeover
|
||||
deflate
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +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.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.add_development_dependency 'rspec'
|
||||
end
|
||||
Reference in New Issue
Block a user