lib/protocol/hpack/context.rb in protocol-hpack-1.4.3 vs lib/protocol/hpack/context.rb in protocol-hpack-1.5.0

- old
+ new

@@ -1,9 +1,11 @@ # frozen_string_literal: true # Released under the MIT License. # Copyright, 2018-2024, by Samuel Williams. +# Copyright, 2024, by Maruth Goyal. +# Copyright, 2024, by Nathan Froyd. require_relative 'huffman' module Protocol # Implementation of header compression for HTTP 2.0 (HPACK) format adapted @@ -92,11 +94,24 @@ ["user-agent", ""], ["vary", ""], ["via", ""], ["www-authenticate", ""], ].each(&:freeze).freeze - + + STATIC_EXACT_LOOKUP = {} + STATIC_NAME_LOOKUP = {} + + STATIC_TABLE.each_with_index do |(name, value), i| + exact_header_values = (STATIC_EXACT_LOOKUP[name] ||= []) + exact_header_values << [value, i] + STATIC_NAME_LOOKUP[name] = i if STATIC_NAME_LOOKUP[name].nil? + end + + STATIC_EXACT_LOOKUP.each {|k, v| v.freeze} + STATIC_EXACT_LOOKUP.freeze + STATIC_NAME_LOOKUP.freeze + # Initializes compression context with appropriate client/server defaults and maximum size of the dynamic table. # # @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. @@ -231,42 +246,55 @@ # 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. # - # @param header [Array] +[name, value]+ + # @param name [String] + # @param value [String] # @return [Hash] command - def add_command(*header) + def add_command(name, value) exact = nil name_only = nil - 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 + 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 [:all].include?(@index) && !exact + + if @index == :all && !exact @table.each_index do |i| - if @table[i] == header - exact ||= i + STATIC_TABLE.size - break - elsif @table[i].first == header.first - name_only ||= i + STATIC_TABLE.size + 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: header.last, type: :incremental} + {name: name_only, value: value, type: :incremental} else - {name: header.first, value: header.last, type: :incremental} + {name: name, value: value, type: :incremental} end end # Alter dynamic table size. # When the size is reduced, some headers might be evicted.