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.
33 34 35 36 37 38 39 |
# File 'lib/protocol/hpack/decompressor.rb', line 33 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.
41 42 43 |
# File 'lib/protocol/hpack/decompressor.rb', line 41 def buffer @buffer end |
#context ⇒ Object (readonly)
Returns the value of attribute context.
42 43 44 |
# File 'lib/protocol/hpack/decompressor.rb', line 42 def context @context end |
#offset ⇒ Object (readonly)
Returns the value of attribute offset.
43 44 45 |
# File 'lib/protocol/hpack/decompressor.rb', line 43 def offset @offset end |
#table_size_limit ⇒ Object (readonly)
Returns the value of attribute table_size_limit.
45 46 47 |
# File 'lib/protocol/hpack/decompressor.rb', line 45 def table_size_limit @table_size_limit end |
Instance Method Details
#decode(list = []) ⇒ Array
Decodes and processes header commands within provided buffer.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/protocol/hpack/decompressor.rb', line 155 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
47 48 49 |
# File 'lib/protocol/hpack/decompressor.rb', line 47 def end? @offset >= @buffer.bytesize end |
#peek_byte ⇒ Object
59 60 61 |
# File 'lib/protocol/hpack/decompressor.rb', line 59 def peek_byte @buffer.getbyte(@offset) end |
#read_byte ⇒ Object
51 52 53 54 55 56 57 |
# File 'lib/protocol/hpack/decompressor.rb', line 51 def read_byte if byte = @buffer.getbyte(@offset) @offset += 1 end return byte end |
#read_bytes(length) ⇒ Object
63 64 65 66 67 68 69 |
# File 'lib/protocol/hpack/decompressor.rb', line 63 def read_bytes(length) slice = @buffer.byteslice(@offset, length) @offset += length return slice end |
#read_header ⇒ Hash
Decodes header command from provided buffer.
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 148 149 |
# File 'lib/protocol/hpack/decompressor.rb', line 115 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.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/protocol/hpack/decompressor.rb', line 75 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.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/protocol/hpack/decompressor.rb', line 95 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 |