aboutsummaryrefslogtreecommitdiffstats
path: root/lib/plum/hpack/context.rb
blob: 5256e5ed5628f9bac278c4831bb5a04952fa89a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# frozen-string-literal: true

module Plum
  module HPACK
    module Context
      attr_reader :dynamic_table, :limit, :size

      def limit=(value)
        @limit = value
        evict
      end

      private
      def initialize(dynamic_table_limit)
        @limit = dynamic_table_limit
        @dynamic_table = []
        @size = 0
      end

      def store(name, value)
        value = value.to_s
        @dynamic_table.unshift([name.freeze, value.freeze])
        @size += name.bytesize + value.bytesize + 32
        evict
      end

      def fetch(index)
        if index == 0
          raise HPACKError.new("index can't be 0")
        elsif index <= STATIC_TABLE_SIZE
            STATIC_TABLE[index - 1]
        elsif index <= STATIC_TABLE.size + @dynamic_table.size
          @dynamic_table[index - STATIC_TABLE_SIZE - 1]
        else
          raise HPACKError.new("invalid index: #{index}")
        end
      end

      def search(name, value)
        si = STATIC_TABLE.index { |n, v| n == name && v == value }
        return si + 1 if si
        di = @dynamic_table.index { |n, v| n == name && v == value }
        return di + STATIC_TABLE_SIZE + 1 if di
      end

      def search_half(name)
        si = STATIC_TABLE.index { |n, v| n == name }
        return si + 1 if si
        di = @dynamic_table.index { |n, v| n == name }
        return di + STATIC_TABLE_SIZE + 1 if di
      end

      def evict
        while @size > @limit
          name, value = @dynamic_table.pop
          @size -= name.bytesize + value.bytesize + 32
        end
      end
    end
  end
end