lib/protocol/hpack/context.rb in protocol-hpack-1.1.0 vs lib/protocol/hpack/context.rb in protocol-hpack-1.2.0

- old
+ new

@@ -29,13 +29,13 @@ module HPACK # Header representation as defined by the spec. HEADER_REPRESENTATION = { indexed: {prefix: 7, pattern: 0x80}, incremental: {prefix: 6, pattern: 0x40}, - noindex: {prefix: 4, pattern: 0x00}, - neverindexed: {prefix: 4, pattern: 0x10}, - changetablesize: {prefix: 5, pattern: 0x20}, + no_index: {prefix: 4, pattern: 0x00}, + never_indexed: {prefix: 4, pattern: 0x10}, + change_table_size: {prefix: 5, pattern: 0x20}, } # To decompress header blocks, a decoder only needs to maintain a # dynamic table as a decoding context. # No other state information is needed. @@ -103,52 +103,42 @@ ['transfer-encoding', ''], ['user-agent', ''], ['vary', ''], ['via', ''], ['www-authenticate', ''], - ].each {|pair| pair.each(&:freeze).freeze}.freeze - - # Current table of header key-value pairs. - attr_reader :table - - # Current encoding options + ].each {|pair| pair.each(&:freeze).freeze}.freeze + + # Initializes compression context with appropriate client/server defaults and maximum size of the dynamic table. # - # :table_size Integer maximum dynamic table size in bytes - # :huffman Symbol :always, :never, :shorter - # :index Symbol :all, :static, :never - attr_reader :options - - # Initializes compression context with appropriate client/server - # defaults and maximum size of the dynamic table. - # - # @param options [Hash] encoding options - # :table_size Integer maximum dynamic table size in bytes - # :huffman Symbol :always, :never, :shorter - # :index Symbol :all, :static, :never - def initialize(**options) - default_options = { - huffman: :shorter, - index: :all, - table_size: 4096, - } + # @param table [Array] Table of header key-value pairs. + # @option huffman [Symbol] One of `:always`, `:never`, `:shorter`. Controls use of compression. + # @option index [Symbol] One of `:all`, `:static`, `:never`. Controls use of static/dynamic tables. + # @option table_size [Integer] The current maximum dynamic table size. + def initialize(table = nil, huffman: :shorter, index: :all, table_size: 4096) + @huffman = huffman + @index = index - @table = [] - @options = default_options.merge(options) - @limit = @options[:table_size] + @table_size = table_size + + @table = (table&.dup) || [] end - - # Duplicates current compression context - # @return [Context] - def dup - other = Context.new(@options) + + def initialize_copy(other) + super - other.instance_variable_set :@table, @table.dup - other.instance_variable_set :@limit, @limit - - return other + # This is the only mutable state: + @table = @table.dup end - + + # Current table of header key-value pairs. + attr :table + + attr :huffman + attr :index + + attr :table_size + # Finds an entry in current dynamic table by index. # Note that index is zero-based in this module. # # If the index is greater than the last index in the static table, # an entry in the dynamic table is dereferenced. @@ -173,11 +163,11 @@ # @return [Array] +[name, value]+ header field that is added to the decoded header list def decode(command) emit = nil case command[:type] - when :changetablesize + when :change_table_size self.table_size = command[:value] when :indexed # Indexed Representation # An _indexed representation_ entails the following actions: @@ -187,11 +177,11 @@ idx = command[:name] k, v = dereference(idx) emit = [k, v] - when :incremental, :noindex, :neverindexed + 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 @@ -217,26 +207,26 @@ end return emit end - # Plan header compression according to +@options [:index]+ + # Plan header compression according to +@index+ # :never Do not use dynamic table or static table reference at all. # :static Use static table only. # :all Use all of them. # # @param headers [Array] +[[name, value], ...]+ # @return [Array] array of commands def encode(headers) commands = [] - # Literals commands are marked with :noindex when index is not used - noindex = [:static, :never].include?(@options[:index]) + # 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] = :noindex if noindex && command[:type] == :incremental + command[:type] = :no_index if no_index && command[:type] == :incremental commands << command decode(command) end @@ -245,11 +235,11 @@ # Emits command for a header. # Prefer static table over dynamic table. # Prefer exact match over name-only match. # - # +@options [:index]+ controls whether to use the dynamic table, + # +@index+ controls whether to use the dynamic table, # static table, or both. # :never Do not use dynamic table or static table reference at all. # :static Use static table only. # :all Use all of them. # @@ -257,21 +247,21 @@ # @return [Hash] command def add_command(*header) exact = nil name_only = nil - if [:all, :static].include?(@options[:index]) + if [:all, :static].include?(@index) STATIC_TABLE.each_index do |i| if STATIC_TABLE[i] == header exact ||= i break elsif STATIC_TABLE[i].first == header.first name_only ||= i end end end - if [:all].include?(@options[:index]) && !exact + if [:all].include?(@index) && !exact @table.each_index do |i| if @table[i] == header exact ||= i + STATIC_TABLE.size break elsif @table[i].first == header.first @@ -289,12 +279,12 @@ end end # Alter dynamic table size. # When the size is reduced, some headers might be evicted. - def table_size=(size) - @limit = size + def table_size= size + @table_size = size size_check(nil) end # Returns current table size in octets # @return [Integer] @@ -312,26 +302,26 @@ def add_to_table(command) return unless size_check(command) @table.unshift(command) end - # To keep the dynamic table size lower than or equal to @limit, + # To keep the dynamic table size lower than or equal to @table_size, # remove one or more entries at the end of the dynamic table. # # @param command [Hash] # @return [Boolean] whether +command+ fits in the dynamic table. def size_check(command) cursize = current_table_size cmdsize = command.nil? ? 0 : command[0].bytesize + command[1].bytesize + 32 - while cursize + cmdsize > @limit + while cursize + cmdsize > @table_size break if @table.empty? e = @table.pop cursize -= e[0].bytesize + e[1].bytesize + 32 end - cmdsize <= @limit + cmdsize <= @table_size end end end end