Class: HTTP2::Header::Compressor
- Inherits:
-
Object
- Object
- HTTP2::Header::Compressor
- Includes:
- BufferUtils, PackingExtensions
- Defined in:
- lib/http/2/header/compressor.rb,
sig/header/compressor.rbs
Overview
Responsible for encoding header key-value pairs using HPACK algorithm.
Instance Method Summary collapse
-
#encode(headers) ⇒ String
Encodes provided list of HTTP headers.
-
#header(h, buffer = "".b) ⇒ String
Encodes
hheader command with appropriate header representation intobuffer. -
#huffman_string(str, buffer = "".b) ⇒ String
encodes
strintobufferusing Huffman encoding. -
#initialize(settings = Settings.new) ⇒ Compressor
constructor
A new instance of Compressor.
-
#integer(i, n, buffer:, offset: buffer.size) ⇒ String
Encodes
ivia integer representation intobufferat the offset set byoffset. -
#plain_string(str, plain = "".b) ⇒ String
encodes
strintobuffer. -
#set_huffman_size(buffer, huffman_offset) ⇒ String
encodes the huffman string size from
bufferinto the string at the offset indicated byhuffman_offset. -
#string(str, buffer = "".b) ⇒ String
Encodes provided value via string literal representation.
-
#table_size=(size) ⇒ void
Set dynamic table
sizein EncodingContext.
Methods included from BufferUtils
#append_str, #read_str, #read_uint32, #shift_byte
Methods included from PackingExtensions
Constructor Details
#initialize(settings = Settings.new) ⇒ Compressor
Returns a new instance of Compressor.
10 11 12 |
# File 'lib/http/2/header/compressor.rb', line 10 def initialize(settings = Settings.new) @cc = EncodingContext.new(settings) end |
Instance Method Details
#encode(headers) ⇒ String
Encodes provided list of HTTP headers.
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/http/2/header/compressor.rb', line 112 def encode(headers) buffer = "".b headers.partition { |f, _| f.start_with? ":" }.each do |hs| @cc.encode(hs) do |cmd| header(cmd, buffer) end end buffer end |
#header(h, buffer = "".b) ⇒ String
Encodes h header command with appropriate header representation into buffer.
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/compressor.rb', line 82 def header(h, buffer = "".b) type = h[:type] rep = HEADREP[type] offset = buffer.size case type when :indexed integer(h[:name] + 1, rep[:prefix], buffer: buffer) when :changetablesize integer(h[:value], rep[:prefix], buffer: buffer) else name = h[:name] if name.is_a? Integer integer(name + 1, rep[:prefix], buffer: buffer) else integer(0, rep[:prefix], buffer: buffer) string(name, buffer) end string(h[:value], buffer) end # set header representation pattern on first byte fb = buffer.getbyte(offset) | rep[:pattern] buffer.setbyte(offset, fb) buffer end |
#huffman_string(str, buffer = "".b) ⇒ String
encodes str into buffer using Huffman encoding.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/http/2/header/compressor.rb', line 126 def huffman_string(str, buffer = "".b) huffman_offset = buffer.bytesize buffer << "\x00".b Huffman.encode(str, buffer) size = buffer.bytesize - huffman_offset - 1 if size < 127 buffer.setbyte(huffman_offset, 0x80 | size) else buffer.slice!(huffman_offset, 1) set_huffman_size(buffer, huffman_offset) end buffer end |
#integer(i, n, buffer:, offset: buffer.size) ⇒ String
Encodes i via integer representation into buffer at the offset set by offset.
If I < 2^N - 1, encode I on N bits Else encode 2^N - 1 on N bits I = I - (2^N - 1) While I >= 128 Encode (I % 128 + 128) on 8 bits I = I / 128 encode (I) on 8 bits
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/http/2/header/compressor.rb', line 31 def integer(i, n, buffer:, offset: buffer.size) limit = (1 << n) - 1 return pack([i], "C", buffer: buffer, offset: offset) if i < limit bytes = [] bytes.push limit unless n.zero? i -= limit while i >= 128 bytes.push((i % 128) + 128) i /= 128 end bytes.push i pack(bytes, "C*", buffer: buffer, offset: offset) end |
#plain_string(str, plain = "".b) ⇒ String
encodes str into buffer.
142 143 144 145 146 |
# File 'lib/http/2/header/compressor.rb', line 142 def plain_string(str, plain = "".b) integer(str.bytesize, 7, buffer: plain) append_str(plain, str) plain end |
#set_huffman_size(buffer, huffman_offset) ⇒ String
encodes the huffman string size from buffer into the string at the offset indicated by huffman_offset
149 150 151 152 153 |
# File 'lib/http/2/header/compressor.rb', line 149 def set_huffman_size(buffer, huffman_offset) integer(buffer.bytesize - huffman_offset, 7, buffer: buffer, offset: huffman_offset) buffer.setbyte(huffman_offset, buffer.getbyte(huffman_offset) | 0x80) buffer end |
#string(str, buffer = "".b) ⇒ String
Encodes provided value via string literal representation.
- The string length, defined as the number of bytes needed to store its UTF-8 representation, is represented as an integer with a seven bits prefix. If the string length is strictly less than 127, it is represented as one byte.
- If the bit 7 of the first byte is 1, the string value is represented as a list of Huffman encoded octets (padded with bit 1's until next octet boundary).
- If the bit 7 of the first byte is 0, the string value is represented as a list of UTF-8 encoded octets.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/http/2/header/compressor.rb', line 61 def string(str, buffer = "".b) case @cc.settings.huffman when :always huffman_string(str, buffer) when :never plain_string(str, buffer) else huffman = Huffman.encode(str) if huffman.bytesize < str.bytesize huffman_offset = buffer.bytesize integer(huffman.bytesize, 7, buffer: buffer) buffer.setbyte(huffman_offset, buffer.getbyte(huffman_offset) | 0x80) append_str(buffer, huffman) buffer else plain_string(str, buffer) end end end |
#table_size=(size) ⇒ void
This method returns an undefined value.
Set dynamic table size in EncodingContext
15 16 17 |
# File 'lib/http/2/header/compressor.rb', line 15 def table_size=(size) @cc.table_size = size end |