class Protocol::HPACK::Context
No other state information is needed.
dynamic table as a decoding context.
To decompress header blocks, a decoder only needs to maintain a
def add_command(name, value)
-
(Hash)
- command
Parameters:
-
value
(String
) -- -
name
(String
) --
def add_command(name, value) exact = nil name_only = nil if @index == :all || @index == :static if (values_and_indices = STATIC_EXACT_LOOKUP[name]) values_and_indices.each do |known_value, index| if value == known_value exact = index break end end needs_name_lookup = exact.nil? else needs_name_lookup = true end if needs_name_lookup && (static_value = STATIC_NAME_LOOKUP[name]) name_only = static_value end end if @index == :all && !exact @table.each_index do |i| entry = @table[i] if entry.first == name if entry.last == value exact ||= i + STATIC_TABLE.size break else name_only ||= i + STATIC_TABLE.size end end end end if exact {name: exact, type: :indexed} elsif name_only {name: name_only, value: value, type: :incremental} else {name: name, value: value, type: :incremental} end end
def add_to_table(command)
-
command
(Array
) -- +[name, value]+
def add_to_table(command) return unless size_check(command) command.each(&:freeze) command.freeze @table.unshift(command) @current_table_size += entry_size(command) end
def change_table_size(size)
def change_table_size(size) self.table_size = size # The command to resize the table: return {type: :change_table_size, value: size} end
def compute_current_table_size
-
(Integer)
-
def compute_current_table_size @table.sum { |k, v| k.bytesize + v.bytesize + 32 } end
def decode(command)
-
(Array)
- +[name, value]+ header field that is added to the decoded header list
Parameters:
-
command
(Hash
) -- {type:, name:, value:, index:}
def decode(command) emit = nil case command[:type] when :change_table_size self.table_size = command[:value] when :indexed # Indexed Representation # An _indexed representation_ entails the following actions: # o The header field corresponding to the referenced entry in either # the static table or dynamic table is added to the decoded header # list. idx = command[:name] k, v = dereference(idx) emit = [k, v] when :incremental, :no_index, :never_indexed # A _literal representation_ that is _not added_ to the dynamic table # entails the following action: # o The header field is added to the decoded header list. # A _literal representation_ that is _added_ to the dynamic table # entails the following actions: # o The header field is added to the decoded header list. # o The header field is inserted at the beginning of the dynamic table. if command[:name].is_a? Integer k, v = dereference(command[:name]) command = command.dup command[:index] ||= command[:name] command[:value] ||= v command[:name] = k end emit = [command[:name], command[:value]] add_to_table(emit) if command[:type] == :incremental else raise CompressionError, "Invalid type: #{command[:type]}" end return emit end
def dereference(index)
-
(Array)
- +[key, value]+
Parameters:
-
index
(Integer
) -- zero-based index in the dynamic table.
def dereference(index) # NOTE: index is zero-based in this module. value = STATIC_TABLE[index] || @table[index - STATIC_TABLE.size] if value.nil? raise CompressionError, "Index #{index} too large!" end return value end
def encode(headers)
-
(Array)
- array of commands
Parameters:
-
headers
(Array
) -- +[[name, value], ...]+
def encode(headers) commands = [] # Literals commands are marked with :no_index when index is not used no_index = [:static, :never].include?(@index) headers.each do |field, value| command = add_command(field, value) command[:type] = :no_index if no_index && command[:type] == :incremental commands << command decode(command) end return commands end
def entry_size(e)
def entry_size(e) e[0].bytesize + e[1].bytesize + 32 end
def initialize(table = nil, huffman: :shorter, index: :all, table_size: 4096)
(**table_size)
-
The
(Integer
) -- current maximum dynamic table size. -
One
(Symbol
) -- of `:all`, `:static`, `:never`. Controls use of static/dynamic tables. -
One
(Symbol
) -- of `:always`, `:never`, `:shorter`. Controls use of compression.
Parameters:
-
table
(Array
) -- Table of header key-value pairs.
def initialize(table = nil, huffman: :shorter, index: :all, table_size: 4096) @huffman = huffman @index = index @table_size = table_size @table = (table&.dup) || [] end
def initialize_copy(other)
def initialize_copy(other) super # This is the only mutable state: @table = @table.dup end
def size_check(command)
-
(Boolean)
- whether +command+ fits in the dynamic table.
Parameters:
-
command
(Hash
) --
def size_check(command) @current_table_size ||= compute_current_table_size cmdsize = command.nil? ? 0 : command[0].bytesize + command[1].bytesize + 32 while @current_table_size + cmdsize > @table_size break if @table.empty? e = @table.pop @current_table_size -= e[0].bytesize + e[1].bytesize + 32 end cmdsize <= @table_size end
def table_size= size
Alter dynamic table size.
def table_size= size @table_size = size size_check(nil) end