Module: Biryani::HPACK::Field

Defined in:
lib/biryani/hpack/field.rb

Overview

rubocop: disable Metrics/ModuleLength

Class Method Summary collapse

Class Method Details

.decode(io, cursor, dynamic_table) ⇒ Array, Integer

rubocop: disable Metrics/CyclomaticComplexity rubocop: disable Metrics/PerceivedComplexity

Parameters:

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/biryani/hpack/field.rb', line 109

def self.decode(io, cursor, dynamic_table)
  byte = io.get_value(:U8, cursor)
  if (byte & 0b10000000).positive?
    decode_indexed(io, cursor, dynamic_table)
  elsif byte == 0b01000000
    decode_literal_field_incremental_indexing(io, cursor, dynamic_table)
  elsif (byte & 0b01000000).positive?
    decode_literal_value_incremental_indexing(io, cursor, dynamic_table)
  elsif (byte & 0b00100000).positive?
    decode_dynamic_table_size_update(io, cursor, dynamic_table)
  elsif byte == 0b00010000
    decode_literal_field_never_indexed(io, cursor)
  elsif (byte & 0b00010000).positive?
    decode_literal_value_never_indexed(io, cursor, dynamic_table)
  elsif byte.zero?
    decode_literal_field_without_indexing(io, cursor)
  elsif (byte & 0b11110000).zero?
    decode_literal_value_without_indexing(io, cursor, dynamic_table)
  else
    raise 'unreachable'
  end
end

.decode_dynamic_table_size_update(io, cursor, dynamic_table) ⇒ nil, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 0 | 1 | Max size (5+) | ---—————————+ datatracker.ietf.org/doc/html/rfc7541#section-6.3

Parameters:

Returns:

Raises:



230
231
232
233
234
235
236
237
238
# File 'lib/biryani/hpack/field.rb', line 230

def self.decode_dynamic_table_size_update(io, cursor, dynamic_table)
  raise Error::HPACKDecodeError unless cursor.zero? || (io.get_value(:U8, 0) & 0b00100000).positive? && Integer.decode(io, 5, 0)[1] == cursor

  max_size, c = Integer.decode(io, 5, cursor)
  raise Error::HPACKDecodeError if max_size > dynamic_table.limit

  dynamic_table.chomp!(max_size)
  [nil, c]
end

.decode_indexed(io, cursor, dynamic_table) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 1 | Index (7+) | ---—————————+ datatracker.ietf.org/doc/html/rfc7541#section-6.1

Parameters:

Returns:

Raises:



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/biryani/hpack/field.rb', line 146

def self.decode_indexed(io, cursor, dynamic_table)
  index, c = Integer.decode(io, 7, cursor)
  raise Error::HPACKDecodeError if index.zero? || index > STATIC_TABLE_SIZE + dynamic_table.count_entries

  field = if index <= STATIC_TABLE_SIZE
            STATIC_TABLE[index - 1]
          else
            dynamic_table[index - 1 - STATIC_TABLE_SIZE]
          end

  [field, c]
end

.decode_literal_field_incremental_indexing(io, cursor, dynamic_table) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 1 | 0 | -------------------------- | H | Name Length (7+) | ---—————————+ | Name String (Length octets) | ---—————————+ | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.1

Parameters:

Returns:



179
180
181
182
183
184
185
# File 'lib/biryani/hpack/field.rb', line 179

def self.decode_literal_field_incremental_indexing(io, cursor, dynamic_table)
  name, c = String.decode(io, cursor + 1)
  value, c = String.decode(io, c)
  dynamic_table.store(name, value)

  [[name, value], c]
end

.decode_literal_field_never_indexed(io, cursor) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 0 | 0 | 1 | 0 | -------------------------- | H | Name Length (7+) | ---—————————+ | Name String (Length octets) | ---—————————+ | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.3

Parameters:

Returns:



259
260
261
262
263
264
# File 'lib/biryani/hpack/field.rb', line 259

def self.decode_literal_field_never_indexed(io, cursor)
  name, c = String.decode(io, cursor + 1)
  value, c = String.decode(io, c)

  [[name, value], c]
end

.decode_literal_field_without_indexing(io, cursor) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 0 | 0 | 1 | 0 | -------------------------- | H | Name Length (7+) | ---—————————+ | Name String (Length octets) | ---—————————+ | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.2

Parameters:

Returns:



315
316
317
318
319
320
# File 'lib/biryani/hpack/field.rb', line 315

def self.decode_literal_field_without_indexing(io, cursor)
  name, c = String.decode(io, cursor + 1)
  value, c = String.decode(io, c)

  [[name, value], c]
end

.decode_literal_value_incremental_indexing(io, cursor, dynamic_table) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 1 | Index (6+) | -------------------------- | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.1

Parameters:

Returns:

Raises:



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/biryani/hpack/field.rb', line 203

def self.decode_literal_value_incremental_indexing(io, cursor, dynamic_table)
  index, c = Integer.decode(io, 6, cursor)
  raise Error::HPACKDecodeError if index.zero? || index > STATIC_TABLE_SIZE + dynamic_table.count_entries

  name = if index <= STATIC_TABLE_SIZE
           STATIC_TABLE[index - 1][0]
         else
           dynamic_table[index - 1 - STATIC_TABLE_SIZE][0]
         end
  value, c = String.decode(io, c)
  dynamic_table.store(name, value)

  [[name, value], c]
end

.decode_literal_value_never_indexed(io, cursor, dynamic_table) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 0 | 0 | 1 | Index (4+) | -------------------------- | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.3

Parameters:

Returns:

Raises:



282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/biryani/hpack/field.rb', line 282

def self.decode_literal_value_never_indexed(io, cursor, dynamic_table)
  index, c = Integer.decode(io, 4, cursor)
  raise Error::HPACKDecodeError if index.zero? || index > STATIC_TABLE_SIZE + dynamic_table.count_entries

  name = if index <= STATIC_TABLE_SIZE
           STATIC_TABLE[index - 1][0]
         else
           dynamic_table[index - 1 - STATIC_TABLE_SIZE][0]
         end
  value, c = String.decode(io, c)

  [[name, value], c]
end

.decode_literal_value_without_indexing(io, cursor, dynamic_table) ⇒ Array, Integer

0 1 2 3 4 5 6 7 ------------—+ | 0 | 0 | 0 | 0 | Index (4+) | -------------------------- | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | -------------------------------

Parameters:

Returns:

Raises:



337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/biryani/hpack/field.rb', line 337

def self.decode_literal_value_without_indexing(io, cursor, dynamic_table)
  index, c = Integer.decode(io, 4, cursor)
  raise Error::HPACKDecodeError if index.zero? || index > STATIC_TABLE_SIZE + dynamic_table.count_entries

  name = if index <= STATIC_TABLE_SIZE
           STATIC_TABLE[index - 1][0]
         else
           dynamic_table[index - 1 - STATIC_TABLE_SIZE][0]
         end
  value, c = String.decode(io, c)

  [[name, value], c]
end

.encode(name, value, dynamic_table) ⇒ String

Parameters:

Returns:



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/biryani/hpack/field.rb', line 10

def self.encode(name, value, dynamic_table)
  case find(name, value, dynamic_table)
  in Some(index, nil)
    res = encode_indexed(index)
  in Some(index, v)
    res = encode_literal_value(index, v)
    dynamic_table.store(name, v)
  in None
    res = encode_literal_field(name, value)
    dynamic_table.store(name, value)
  end

  res
end

.encode_indexed(index) ⇒ String

0 1 2 3 4 5 6 7 ------------—+ | 1 | Index (7+) | ---—————————+ datatracker.ietf.org/doc/html/rfc7541#section-6.1

Parameters:

Returns:



57
58
59
# File 'lib/biryani/hpack/field.rb', line 57

def self.encode_indexed(index)
  Integer.encode(index, 7, 0b10000000)
end

.encode_literal_field(name, value) ⇒ String

0 1 2 3 4 5 6 7 ------------—+ | 0 | 1 | 0 | -------------------------- | H | Name Length (7+) | ---—————————+ | Name String (Length octets) | ---—————————+ | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.1

Parameters:

Returns:



97
98
99
# File 'lib/biryani/hpack/field.rb', line 97

def self.encode_literal_field(name, value)
  "\x40#{String.encode(name)}#{String.encode(value)}"
end

.encode_literal_value(index, value) ⇒ String

0 1 2 3 4 5 6 7 ------------—+ | 0 | 1 | Index (6+) | -------------------------- | H | Value Length (7+) | ---—————————+ | Value String (Length octets) | ------------------------------- datatracker.ietf.org/doc/html/rfc7541#section-6.2.1

Parameters:

Returns:



75
76
77
# File 'lib/biryani/hpack/field.rb', line 75

def self.encode_literal_value(index, value)
  Integer.encode(index, 6, 0b01000000) + String.encode(value)
end

.find(name, value, dynamic_table) ⇒ Some, None

rubocop: disable Metrics/CyclomaticComplexity

Parameters:

Returns:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/biryani/hpack/field.rb', line 31

def self.find(name, value, dynamic_table)
  found, i = STATIC_TABLE.each_with_index.find { |nv, _| nv[0] == name && nv[1] == value }
  return Some.new(i + 1, nil) unless found.nil?

  found, i = dynamic_table.find_field(name, value)
  return Some.new(i + 1 + STATIC_TABLE_SIZE, nil) unless found.nil?

  found, i = STATIC_TABLE.each_with_index.find { |nv, _| nv[0] == name }
  return Some.new(i + 1, value) unless found.nil?

  found, i = dynamic_table.find_name(name)
  return Some.new(i + 1 + STATIC_TABLE_SIZE, value) unless found.nil?

  None.new
end