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.