Class: HTTP::HPACK::Decompressor

Inherits:
Object
  • Object
show all
Defined in:
lib/http/hpack/decompressor.rb

Overview

Responsible for decoding received headers and maintaining compression context of the opposing peer. Decompressor must be initialized with appropriate starting context based on local role: client or server.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer, context = Context.new) ⇒ Decompressor

Returns a new instance of Decompressor.



31
32
33
34
35
# File 'lib/http/hpack/decompressor.rb', line 31

def initialize(buffer, context = Context.new)
  @buffer = buffer
  @context = context
  @offset = 0
end

Instance Attribute Details

#bufferObject (readonly)

Returns the value of attribute buffer.



37
38
39
# File 'lib/http/hpack/decompressor.rb', line 37

def buffer
  @buffer
end

#contextObject (readonly)

Returns the value of attribute context.



38
39
40
# File 'lib/http/hpack/decompressor.rb', line 38

def context
  @context
end

#offsetObject (readonly)

Returns the value of attribute offset.



39
40
41
# File 'lib/http/hpack/decompressor.rb', line 39

def offset
  @offset
end

Instance Method Details

#decode(list = []) ⇒ Array

Decodes and processes header commands within provided buffer.

Parameters:

  • buffer (Buffer)

Returns:

  • (Array)

    [[name, value], …]



143
144
145
146
147
148
149
150
151
# File 'lib/http/hpack/decompressor.rb', line 143

def decode(list = [])
  while !end?
    if pair = @context.decode(read_header)
      list << pair
    end
  end
  
  return list
end

#end?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/http/hpack/decompressor.rb', line 41

def end?
  @offset >= @buffer.bytesize
end

#peek_byteObject



54
55
56
# File 'lib/http/hpack/decompressor.rb', line 54

def peek_byte
  @buffer.getbyte(@offset)
end

#read_byteObject



45
46
47
48
49
50
51
# File 'lib/http/hpack/decompressor.rb', line 45

def read_byte
  if byte = @buffer.getbyte(@offset)
    @offset += 1
  end
  
  return byte
end

#read_bytes(length) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/http/hpack/decompressor.rb', line 58

def read_bytes(length)
  slice = @buffer.byteslice(@offset, length)
  
  @offset += length
  
  return slice
end

#read_headerHash

Decodes header command from provided buffer.

Parameters:

  • buffer (Buffer)

Returns:

  • (Hash)

    command

Raises:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/http/hpack/decompressor.rb', line 107

def read_header
  pattern = peek_byte

  header = {}
  header[:type], type = HEADER_REPRESENTATION.find do |_t, desc|
    mask = (pattern >> desc[:prefix]) << desc[:prefix]
    mask == desc[:pattern]
  end

  raise CompressionError unless header[:type]

  header[:name] = read_integer(type[:prefix])

  case header[:type]
  when :indexed
    raise CompressionError if header[:name].zero?
    header[:name] -= 1
  when :changetablesize
    header[:value] = header[:name]
  else
    if (header[:name]).zero?
      header[:name] = read_string
    else
      header[:name] -= 1
    end
    
    header[:value] = read_string
  end

  return header
end

#read_integer(bits) ⇒ Integer

Decodes integer value from provided buffer.

Parameters:

  • bits (Integer)

    number of available bits

Returns:

  • (Integer)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/http/hpack/decompressor.rb', line 70

def read_integer(bits)
  limit = 2**bits - 1
  value = !bits.zero? ? (read_byte & limit) : 0
  
  shift = 0
  
  while byte = read_byte
    value += ((byte & 127) << shift)
    shift += 7
    
    break if (byte & 128).zero?
  end if (value == limit)

  return value
end

#read_stringString

Decodes string value from provided buffer.

Returns:

  • (String)

    UTF-8 encoded string

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/http/hpack/decompressor.rb', line 90

def read_string
  huffman = (peek_byte & 0x80) == 0x80
  
  length = read_integer(7)
  string = read_bytes(length)
  
  raise CompressionError, "Invalid string length, got #{string.bytesize}, expecting #{length}!" unless string.bytesize == length
  
  string = Huffman.new.decode(string) if huffman
  
  return string.force_encoding(Encoding::UTF_8)
end