Implement ServerSession, passes Autobahn 12.1.*.

This commit is contained in:
James Coglan
2014-12-05 19:32:40 +00:00
commit 24c610c671
7 changed files with 176 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
Gemfile.lock
*.gem
+2
View File
@@ -0,0 +1,2 @@
source 'https://rubygems.org'
gemspec
View File
+33
View File
@@ -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
+47
View File
@@ -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
+75
View File
@@ -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
+17
View File
@@ -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