Class: HTTP2::Header::Decompressor
- Inherits:
-
Object
- Object
- HTTP2::Header::Decompressor
- Includes:
- BufferUtils, Error
- Defined in:
- lib/http/2/header/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.
Constant Summary collapse
- FORBIDDEN_HEADERS =
%w[connection te].freeze
Instance Method Summary collapse
-
#decode(buf, frame = nil) ⇒ Array
Decodes and processes header commands within provided buffer.
-
#header(buf) ⇒ Hash
Decodes header command from provided buffer.
-
#initialize(options = {}) ⇒ Decompressor
constructor
A new instance of Decompressor.
-
#integer(buf, n) ⇒ Integer
Decodes integer value from provided buffer.
-
#string(buf) ⇒ String
Decodes string value from provided buffer.
-
#table_size=(size) ⇒ Object
Set dynamic table size in EncodingContext.
Methods included from BufferUtils
#append_str, #read_str, #read_uint32, #shift_byte
Constructor Details
#initialize(options = {}) ⇒ Decompressor
Returns a new instance of Decompressor.
19 20 21 |
# File 'lib/http/2/header/decompressor.rb', line 19 def initialize( = {}) @cc = EncodingContext.new() end |
Instance Method Details
#decode(buf, frame = nil) ⇒ Array
Decodes and processes header commands within provided buffer.
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 |
# File 'lib/http/2/header/decompressor.rb', line 116 def decode(buf, frame = nil) list = [] decoding_pseudo_headers = true @cc.listen_on_table do until buf.empty? field, value = @cc.process(header(buf)) next if field.nil? is_pseudo_header = field.start_with?(":") if !decoding_pseudo_headers && is_pseudo_header raise ProtocolError, "one or more pseudo headers encountered after regular headers" end decoding_pseudo_headers = is_pseudo_header raise ProtocolError, "invalid header received: #{field}" if FORBIDDEN_HEADERS.include?(field) if frame case field when ":status" frame[:status] = Integer(value) when ":method" frame[:method] = value when "content-length" frame[:content_length] = Integer(value) when "trailer" (frame[:trailer] ||= []) << value end end list << [field, value] end end list end |
#header(buf) ⇒ Hash
Decodes header command from provided buffer.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/http/2/header/decompressor.rb', line 78 def header(buf) peek = buf.getbyte(0) header_type, type = HEADREP.find do |_, desc| mask = (peek >> desc[:prefix]) << desc[:prefix] mask == desc[:pattern] end raise CompressionError unless header_type && type header_name = integer(buf, type[:prefix]) case header_type when :indexed raise CompressionError if header_name.zero? header_name -= 1 { type: header_type, name: header_name } when :changetablesize { type: header_type, name: header_name, value: header_name } else if header_name.zero? header_name = string(buf) else header_name -= 1 end header_value = string(buf) { type: header_type, name: header_name, value: header_value } end end |
#integer(buf, n) ⇒ Integer
Decodes integer value from provided buffer.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/http/2/header/decompressor.rb', line 34 def integer(buf, n) limit = (1 << n) - 1 i = n.zero? ? 0 : (shift_byte(buf) & limit) m = 0 if i == limit offset = 0 buf.each_byte.with_index do |byte, idx| offset = idx # while (byte = shift_byte(buf)) i += ((byte & 127) << m) m += 7 break if byte.nobits?(128) end read_str(buf, offset + 1) end i end |
#string(buf) ⇒ String
Decodes string value from provided buffer.
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/http/2/header/decompressor.rb', line 62 def string(buf) raise CompressionError, "invalid header block fragment" if buf.empty? huffman = buf.getbyte(0).allbits?(0x80) len = integer(buf, 7) str = read_str(buf, len) raise CompressionError, "string too short" unless str.bytesize == len str = Huffman.decode(str) if huffman str.force_encoding(Encoding::UTF_8) end |
#table_size=(size) ⇒ Object
Set dynamic table size in EncodingContext
25 26 27 |
# File 'lib/http/2/header/decompressor.rb', line 25 def table_size=(size) @cc.table_size = size end |