class Plum::HPACK::Decoder

Public Class Methods

new(dynamic_table_limit) click to toggle source
Calls superclass method Plum::HPACK::Context::new
# File lib/plum/hpack/decoder.rb, line 8
def initialize(dynamic_table_limit)
  super
end

Public Instance Methods

decode(str) click to toggle source
# File lib/plum/hpack/decoder.rb, line 12
def decode(str)
  headers = []
  pos = 0
  lpos = str.bytesize
  while pos < lpos
    l, succ = parse(str, pos)
    pos += succ
    headers << l if l
  end
  headers
end

Private Instance Methods

parse(str, pos) click to toggle source
# File lib/plum/hpack/decoder.rb, line 25
def parse(str, pos)
  first_byte = str.getbyte(pos)
  if first_byte >= 0x80 # 0b1XXXXXXX
    parse_indexed(str, pos)
  elsif first_byte >= 0x40 # 0b01XXXXXX
    parse_indexing(str, pos)
  elsif first_byte >= 0x20 # 0b001XXXXX
    self.limit, succ = read_integer(str, pos, 5)
    [nil, succ]
  else # 0b0000XXXX (without indexing) or 0b0001XXXX (never indexing)
    parse_no_indexing(str, pos)
  end
end
parse_indexed(str, pos) click to toggle source
# File lib/plum/hpack/decoder.rb, line 77
def parse_indexed(str, pos)
  # indexed
  # +---+---+---+---+---+---+---+---+
  # | 1 |        Index (7+)         |
  # +---+---------------------------+
  index, succ = read_integer(str, pos, 7)
  [fetch(index), succ]
end
parse_indexing(str, pos) click to toggle source
# File lib/plum/hpack/decoder.rb, line 86
def parse_indexing(str, pos)
  # +---+---+---+---+---+---+---+---+
  # | 0 | 1 |      Index (6+)       |
  # +---+---+-----------------------+
  # | H |     Value Length (7+)     |
  # +---+---------------------------+
  # | Value String (Length octets)  |
  # +-------------------------------+
  # or
  # +---+---+---+---+---+---+---+---+
  # | 0 | 1 |           0           |
  # +---+---+-----------------------+
  # | H |     Name Length (7+)      |
  # +---+---------------------------+
  # |  Name String (Length octets)  |
  # +---+---------------------------+
  # | H |     Value Length (7+)     |
  # +---+---------------------------+
  # | Value String (Length octets)  |
  # +-------------------------------+
  ret, len = parse_literal(str, pos, 6)
  store(*ret)

  [ret, len]
end
parse_literal(str, pos, pref) click to toggle source
# File lib/plum/hpack/decoder.rb, line 137
def parse_literal(str, pos, pref)
  index, ilen = read_integer(str, pos, pref)
  if index == 0
    name, nlen = read_string(str, pos + ilen)
  else
    name, = fetch(index)
    nlen = 0
  end

  val, vlen = read_string(str, pos + ilen + nlen)

  [[name, val], ilen + nlen + vlen]
end
parse_no_indexing(str, pos) click to toggle source
# File lib/plum/hpack/decoder.rb, line 112
def parse_no_indexing(str, pos)
  # +---+---+---+---+---+---+---+---+
  # | 0 | 0 | 0 |0,1|  Index (4+)   |
  # +---+---+-----------------------+
  # | H |     Value Length (7+)     |
  # +---+---------------------------+
  # | Value String (Length octets)  |
  # +-------------------------------+
  # or
  # +---+---+---+---+---+---+---+---+
  # | 0 | 0 | 0 |0,1|       0       |
  # +---+---+-----------------------+
  # | H |     Name Length (7+)      |
  # +---+---------------------------+
  # |  Name String (Length octets)  |
  # +---+---------------------------+
  # | H |     Value Length (7+)     |
  # +---+---------------------------+
  # | Value String (Length octets)  |
  # +-------------------------------+
  ret, len = parse_literal(str, pos, 4)

  [ret, len]
end
read_integer(str, pos, prefix_length) click to toggle source
# File lib/plum/hpack/decoder.rb, line 39
def read_integer(str, pos, prefix_length)
  raise HPACKError.new("integer: end of buffer") if str.empty?

  mask = 1 << prefix_length
  ret = str.getbyte(pos) % mask
  return [ret, 1] if ret != mask - 1

  octets = 0
  while next_value = str.uint8(pos + octets + 1)
    ret += (next_value % 0x80) << (7 * octets)
    octets += 1

    if next_value < 0x80
      return [ret, 1 + octets]
    elsif octets == 4 # RFC 7541 5.1 tells us that we MUST have limitation. at least > 2 ** 28
      raise HPACKError.new("integer: too large integer")
    end
  end

  raise HPACKError.new("integer: end of buffer")
end
read_string(str, pos) click to toggle source
# File lib/plum/hpack/decoder.rb, line 61
def read_string(str, pos)
  raise HPACKError.new("string: end of buffer") if str.empty?
  first_byte = str.uint8(pos)

  huffman = first_byte > 0x80
  length, ilen = read_integer(str, pos, 7)
  raise HTTPError.new("string: end of buffer") if str.bytesize < length

  bin = str.byteslice(pos + ilen, length)
  if huffman
    [Huffman.decode(bin), ilen + length]
  else
    [bin, ilen + length]
  end
end