Class: WebSocket::Extensions

Inherits:
Object
  • Object
show all
Defined in:
lib/websocket/extensions.rb,
lib/websocket/extensions/parser.rb

Defined Under Namespace

Classes: Offers, Parser

Constant Summary collapse

ExtensionError =
Class.new(ArgumentError)
MESSAGE_OPCODES =
[1, 2]

Instance Method Summary collapse

Constructor Details

#initializeExtensions

Returns a new instance of Extensions.



10
11
12
13
14
15
16
17
# File 'lib/websocket/extensions.rb', line 10

def initialize
  @rsv1 = @rsv2 = @rsv3 = nil

  @by_name  = {}
  @in_order = []
  @sessions = []
  @index    = {}
end

Instance Method Details

#activate(header) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/websocket/extensions.rb', line 75

def activate(header)
  responses = Parser.parse_header(header)
  @sessions = []

  responses.each_offer do |name, params|
    unless record = @index[name]
      raise ExtensionError, %Q{Server sent am extension response for unknown extension "#{ name } }
    end

    ext, session = *record

    if reserved = reserved?(ext)
      raise ExtensionError, %Q{Server sent two extension responses that use the RSV#{ reserved[0] }} +
                            %Q{bit: "#{ reserved[1] }" and "#{ ext.name }"}
    end

    unless session.activate(params) == true
      raise ExtensionError, %Q{Server send unacceptable extension parameters: #{ Parser.serialize_params(name, params) }}
    end

    reserve(ext)
    @sessions.push(record)
  end
end

#add(ext) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/websocket/extensions.rb', line 19

def add(ext)
  unless ext.respond_to?(:name) and ext.name.is_a?(String)
    raise TypeError, 'extension.name must be a string'
  end

  unless ext.respond_to?(:type) and ext.type == 'permessage'
    raise TypeError, 'extension.type must be "permessage"'
  end

  unless ext.respond_to?(:rsv1) and [true, false].include?(ext.rsv1)
    raise TypeError, 'extension.rsv1 must be true or false'
  end

  unless ext.respond_to?(:rsv2) and [true, false].include?(ext.rsv2)
    raise TypeError, 'extension.rsv2 must be true or false'
  end

  unless ext.respond_to?(:rsv3) and [true, false].include?(ext.rsv3)
    raise TypeError, 'extension.rsv3 must be true or false'
  end

  if @by_name.has_key?(ext.name)
    raise TypeError, %Q{An extension with name "#{ ext.name }" is already registered}
  end

  @by_name[ext.name] = ext
  @in_order.push(ext)
end

#closeObject



157
158
159
160
161
162
163
# File 'lib/websocket/extensions.rb', line 157

def close
  return unless @sessions

  @sessions.each do |ext, session|
    session.close rescue nil
  end
end

#generate_offerObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/websocket/extensions.rb', line 48

def generate_offer
  sessions = []
  offer    = []
  index    = {}

  @in_order.each do |ext|
    session = ext.create_client_session
    next unless session

    record = [ext, session]
    sessions.push(record)
    index[ext.name] = record

    offers = session.generate_offer
    offers = offers ? [offers].flatten : []

    offers.each do |off|
      offer.push(Parser.serialize_params(ext.name, off))
    end
  end

  @sessions = sessions
  @index    = index

  offer.size > 0 ? offer.join(', ') : nil
end

#generate_response(header) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/websocket/extensions.rb', line 100

def generate_response(header)
  sessions = []
  response = []
  offers   = Parser.parse_header(header)

  @in_order.each do |ext|
    offer = offers.by_name(ext.name)
    next if offer.empty? or reserved?(ext)

    next unless session = ext.create_server_session(offer)

    reserve(ext)
    sessions.push([ext, session])
    response.push(Parser.serialize_params(ext.name, session.generate_response))
  end

  @sessions = sessions
  response.size > 0 ? response.join(', ') : nil
end

#process_incoming_message(message) ⇒ Object



137
138
139
140
141
142
143
144
145
# File 'lib/websocket/extensions.rb', line 137

def process_incoming_message(message)
  @sessions.reverse.inject(message) do |msg, (ext, session)|
    begin
      session.process_incoming_message(msg)
    rescue => error
      raise ExtensionError, [ext.name, error.message].join(': ')
    end
  end
end

#process_outgoing_message(message) ⇒ Object



147
148
149
150
151
152
153
154
155
# File 'lib/websocket/extensions.rb', line 147

def process_outgoing_message(message)
  @sessions.inject(message) do |msg, (ext, session)|
    begin
      session.process_outgoing_message(msg)
    rescue => error
      raise ExtensionError, [ext.name, error.message].join(': ')
    end
  end
end

#valid_frame_rsv(frame) ⇒ Object Also known as: valid_frame_rsv?



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/websocket/extensions.rb', line 120

def valid_frame_rsv(frame)
  allowed = { :rsv1 => false, :rsv2 => false, :rsv3 => false }

  if MESSAGE_OPCODES.include?(frame.opcode)
    @sessions.each do |ext, session|
      allowed[:rsv1] ||= ext.rsv1
      allowed[:rsv2] ||= ext.rsv2
      allowed[:rsv3] ||= ext.rsv3
    end
  end

  (allowed[:rsv1] || !frame.rsv1) &&
  (allowed[:rsv2] || !frame.rsv2) &&
  (allowed[:rsv3] || !frame.rsv3)
end