Class: Protocol::HPACK::Decompressor
- Inherits:
-
Object
- Object
- Protocol::HPACK::Decompressor
- Defined in:
- lib/protocol/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
-
#buffer ⇒ Object
readonly
Returns the value of attribute buffer.
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#offset ⇒ Object
readonly
Returns the value of attribute offset.
-
#table_size_limit ⇒ Object
readonly
Returns the value of attribute table_size_limit.
Instance Method Summary collapse
-
#decode(list = []) ⇒ Array
Decodes and processes header commands within provided buffer.
- #end? ⇒ Boolean
-
#initialize(buffer, context = Context.new, table_size_limit: nil) ⇒ Decompressor
constructor
A new instance of Decompressor.
- #peek_byte ⇒ Object
- #read_byte ⇒ Object
- #read_bytes(length) ⇒ Object
-
#read_header ⇒ Hash
Decodes header command from provided buffer.
-
#read_integer(bits) ⇒ Integer
Decodes integer value from provided buffer.
-
#read_string ⇒ String
Decodes string value from provided buffer.
Constructor Details
#initialize(buffer, context = Context.new, table_size_limit: nil) ⇒ Decompressor
Returns a new instance of Decompressor.
31 32 33 34 35 36 37 |
# File 'lib/protocol/hpack/decompressor.rb', line 31 def initialize(buffer, context = Context.new, table_size_limit: nil) @buffer = buffer @context = context @offset = 0 @table_size_limit = table_size_limit end |
Instance Attribute Details
#buffer ⇒ Object (readonly)
Returns the value of attribute buffer.
39 40 41 |
# File 'lib/protocol/hpack/decompressor.rb', line 39 def buffer @buffer end |
#context ⇒ Object (readonly)
Returns the value of attribute context.
40 41 42 |
# File 'lib/protocol/hpack/decompressor.rb', line 40 def context @context end |
#offset ⇒ Object (readonly)
Returns the value of attribute offset.
41 42 43 |
# File 'lib/protocol/hpack/decompressor.rb', line 41 def offset @offset end |
#table_size_limit ⇒ Object (readonly)
Returns the value of attribute table_size_limit.
43 44 45 |
# File 'lib/protocol/hpack/decompressor.rb', line 43 def table_size_limit @table_size_limit end |
Instance Method Details
#decode(list = []) ⇒ Array
Decodes and processes header commands within provided buffer.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/protocol/hpack/decompressor.rb', line 153 def decode(list = []) while !end? command = read_header if pair = @context.decode(command) list << pair end end if command and command[:type] == :change_table_size raise CompressionError, "Trailing table size update!" end return list end |
#end? ⇒ Boolean
45 46 47 |
# File 'lib/protocol/hpack/decompressor.rb', line 45 def end? @offset >= @buffer.bytesize end |
#peek_byte ⇒ Object
57 58 59 |
# File 'lib/protocol/hpack/decompressor.rb', line 57 def peek_byte @buffer.getbyte(@offset) end |
#read_byte ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/protocol/hpack/decompressor.rb', line 49 def read_byte if byte = @buffer.getbyte(@offset) @offset += 1 end return byte end |
#read_bytes(length) ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/protocol/hpack/decompressor.rb', line 61 def read_bytes(length) slice = @buffer.byteslice(@offset, length) @offset += length return slice end |
#read_header ⇒ Hash
Decodes header command from provided buffer.
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 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/protocol/hpack/decompressor.rb', line 113 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 :change_table_size header[:value] = header[:name] if @table_size_limit and header[:value] > @table_size_limit raise CompressionError, "Table size #{header[:value]} exceeds limit #{@table_size_limit}!" end 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.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/protocol/hpack/decompressor.rb', line 73 def read_integer(bits) limit = 2**bits - 1 value = bits.zero? ? 0 : (read_byte & limit) 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_string ⇒ String
Decodes string value from provided buffer.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/protocol/hpack/decompressor.rb', line 93 def read_string huffman = (peek_byte & 0x80) == 0x80 length = read_integer(7) raise CompressionError, "Invalid string length!" unless length 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 |